1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License. 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Thread support. 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h" 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "utils/threads.h" // need Android thread priorities 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h> 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <unistd.h> 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/time.h> 27384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden#include <sys/types.h> 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/resource.h> 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/mman.h> 30384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden#include <signal.h> 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <errno.h> 32d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden#include <fcntl.h> 33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if defined(HAVE_PRCTL) 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/prctl.h> 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 38fe1be87f9ebe2a5477dfd8cae317c3b6757066bfBen Cheng#if defined(WITH_SELF_VERIFICATION) 39fe1be87f9ebe2a5477dfd8cae317c3b6757066bfBen Cheng#include "interp/Jit.h" // need for self verification 40fe1be87f9ebe2a5477dfd8cae317c3b6757066bfBen Cheng#endif 41fe1be87f9ebe2a5477dfd8cae317c3b6757066bfBen Cheng 42fe1be87f9ebe2a5477dfd8cae317c3b6757066bfBen Cheng 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* desktop Linux needs a little help with gettid() */ 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS) 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define __KERNEL__ 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project# include <linux/unistd.h> 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef _syscall0 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project_syscall0(pid_t,gettid) 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpid_t gettid() { return syscall(__NR_gettid);} 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#undef __KERNEL__ 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 55256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat// Change this to enable logging on cgroup errors 56256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat#define ENABLE_CGROUP_ERR_LOGGING 0 57256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// change this to LOGV/LOGD to debug thread activity 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define LOG_THREAD LOGVV 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectNotes on Threading 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectAll threads are native pthreads. All threads, except the JDWP debugger 65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthread, are visible to code running in the VM and to the debugger. (We 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectdon't want the debugger to try to manipulate the thread that listens for 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectinstructions from the debugger.) Internal VM threads are in the "system" 68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThreadGroup, all others are in the "main" ThreadGroup, per convention. 69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe GC only runs when all threads have been suspended. Threads are 71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectexpected to suspend themselves, using a "safe point" mechanism. We check 72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfor a suspend request at certain points in the main interpreter loop, 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectand on requests coming in from native code (e.g. all JNI functions). 74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectCertain debugger events may inspire threads to self-suspend. 75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectNative methods must use JNI calls to modify object references to avoid 77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectclashes with the GC. JNI doesn't provide a way for native code to access 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectarrays of objects as such -- code must always get/set individual entries -- 79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectso it should be possible to fully control access through JNI. 80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectInternal native VM threads, such as the finalizer thread, must explicitly 82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcheck for suspension periodically. In most cases they will be sound 83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectasleep on a condition variable, and won't notice the suspension anyway. 84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThreads may be suspended by the GC, debugger, or the SIGQUIT listener 86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthread. The debugger may suspend or resume individual threads, while the 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectGC always suspends all threads. Each thread has a "suspend count" that 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectis incremented on suspend requests and decremented on resume requests. 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectWhen the count is zero, the thread is runnable. This allows us to fulfill 90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecta debugger requirement: if the debugger suspends a thread, the thread is 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectnot allowed to run again until the debugger resumes it (or disconnects, 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectin which case we must resume all debugger-suspended threads). 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectPaused threads sleep on a condition variable, and are awoken en masse. 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectCertain "slow" VM operations, such as starting up a new thread, will be 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectdone in a separate "VMWAIT" state, so that the rest of the VM doesn't 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfreeze up waiting for the operation to finish. Threads must check for 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpending suspension when leaving VMWAIT. 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectBecause threads suspend themselves while interpreting code or when native 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcode makes JNI calls, there is no risk of suspending while holding internal 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectVM locks. All threads can enter a suspended (or native-code-only) state. 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectAlso, we don't have to worry about object references existing solely 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectin hardware registers. 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectWe do, however, have to worry about objects that were allocated internally 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectand aren't yet visible to anything else in the VM. If we allocate an 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectobject, and then go to sleep on a mutex after changing to a non-RUNNING 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstate (e.g. while trying to allocate a second object), the first object 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcould be garbage-collected out from under us while we sleep. To manage 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthis, we automatically add all allocated objects to an internal object 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecttracking list, and only remove them when we know we won't be suspended 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbefore the object appears in the GC root set. 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe debugger may choose to suspend or resume a single thread, which can 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectlead to application-level deadlocks; this is expected behavior. The VM 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectwill only check for suspension of single threads when the debugger is 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectactive (the java.lang.Thread calls for this are deprecated and hence are 119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectnot supported). Resumption of a single thread is handled by decrementing 120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthe thread's suspend count and sending a broadcast signal to the condition 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvariable. (This will cause all threads to wake up and immediately go back 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectto sleep, which isn't tremendously efficient, but neither is having the 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectdebugger attached.) 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe debugger is not allowed to resume threads suspended by the GC. This 126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectis trivially enforced by ignoring debugger requests while the GC is running 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project(the JDWP thread is suspended during GC). 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe VM maintains a Thread struct for every pthread known to the VM. There 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectis a java/lang/Thread object associated with every Thread. At present, 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthere is no safe way to go from a Thread object to a Thread struct except by 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectlocking and scanning the list; this is necessary because the lifetimes of 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthe two are not closely coupled. We may want to change this behavior, 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthough at present the only performance impact is on the debugger (see 135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectthreadObjToThread()). See also notes about dvmDetachCurrentThread(). 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project*/ 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectAlternate implementation (signal-based): 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThreads run without safe points -- zero overhead. The VM uses a signal 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project(e.g. pthread_kill(SIGUSR1)) to notify threads of suspension or resumption. 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe trouble with using signals to suspend threads is that it means a thread 144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcan be in the middle of an operation when garbage collection starts. 145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectTo prevent some sticky situations, we have to introduce critical sections 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectto the VM code. 147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectCritical sections temporarily block suspension for a given thread. 149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe thread must move to a non-blocked state (and self-suspend) after 150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfinishing its current task. If the thread blocks on a resource held 151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectby a suspended thread, we're hosed. 152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectOne approach is to require that no blocking operations, notably 154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectacquisition of mutexes, can be performed within a critical section. 155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThis is too limiting. For example, if thread A gets suspended while 156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectholding the thread list lock, it will prevent the GC or debugger from 157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbeing able to safely access the thread list. We need to wrap the critical 158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsection around the entire operation (enter critical, get lock, do stuff, 159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectrelease lock, exit critical). 160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectA better approach is to declare that certain resources can only be held 162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectwithin critical sections. A thread that enters a critical section and 163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthen gets blocked on the thread list lock knows that the thread it is 164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectwaiting for is also in a critical section, and will release the lock 165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbefore suspending itself. Eventually all threads will complete their 166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectoperations and self-suspend. For this to work, the VM must: 167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (1) Determine the set of resources that may be accessed from the GC or 169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project debugger threads. The mutexes guarding those go into the "critical 170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project resource set" (CRS). 171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (2) Ensure that no resource in the CRS can be acquired outside of a 172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project critical section. This can be verified with an assert(). 173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (3) Ensure that only resources in the CRS can be held while in a critical 174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project section. This is harder to enforce. 175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectIf any of these conditions are not met, deadlock can ensue when grabbing 177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectresources in the GC or debugger (#1) or waiting for threads to suspend 178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project(#2,#3). (You won't actually deadlock in the GC, because if the semantics 179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectabove are followed you don't need to lock anything in the GC. The risk is 180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectrather that the GC will access data structures in an intermediate state.) 181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThis approach requires more care and awareness in the VM than 183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsafe-pointing. Because the GC and debugger are fairly intrusive, there 184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectreally aren't any internal VM resources that aren't shared. Thus, the 185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectenter/exit critical calls can be added to internal mutex wrappers, which 186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectmakes it easy to get #1 and #2 right. 187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectAn ordering should be established for all locks to avoid deadlocks. 189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectMonitor locks, which are also implemented with pthread calls, should not 191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcause any problems here. Threads fighting over such locks will not be in 192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcritical sections and can be suspended freely. 193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThis can get tricky if we ever need exclusive access to VM and non-VM 195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectresources at the same time. It's not clear if this is a real concern. 196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThere are (at least) two ways to handle the incoming signals: 198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (a) Always accept signals. If we're in a critical section, the signal 200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project handler just returns without doing anything (the "suspend level" 201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project should have been incremented before the signal was sent). Otherwise, 202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if the "suspend level" is nonzero, we go to sleep. 203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (b) Block signals in critical sections. This ensures that we can't be 204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project interrupted in a critical section, but requires pthread_sigmask() 205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project calls on entry and exit. 206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThis is a choice between blocking the message and blocking the messenger. 208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectBecause UNIX signals are unreliable (you can only know that you have been 209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsignaled, not whether you were signaled once or 10 times), the choice is 210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectnot significant for correctness. The choice depends on the efficiency 211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectof pthread_sigmask() and the desire to actually block signals. Either way, 212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectit is best to ensure that there is only one indication of "blocked"; 213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecthaving two (i.e. block signals and set a flag, then only send a signal 214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectif the flag isn't set) can lead to race conditions. 215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe signal handler must take care to copy registers onto the stack (via 217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsetjmp), so that stack scans find all references. Because we have to scan 218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectnative stacks, "exact" GC is not possible with this approach. 219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectSome other concerns with flinging signals around: 221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project - Odd interactions with some debuggers (e.g. gdb on the Mac) 222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project - Restrictions on some standard library calls during GC (e.g. don't 223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project use printf on stdout to print GC debug messages) 224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project*/ 225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 22659a93123f48e9d7c2992ec4b08f75b90c74cb468Carl Shapiro#define kMaxThreadId ((1 << 16) - 1) 22759a93123f48e9d7c2992ec4b08f75b90c74cb468Carl Shapiro#define kMainThreadId 1 228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic Thread* allocThread(int interpStackSize); 231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool prepareThread(Thread* thread); 232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void setThreadSelf(Thread* thread); 233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void unlinkThread(Thread* thread); 234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void freeThread(Thread* thread); 235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void assignThreadId(Thread* thread); 236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool createFakeEntryFrame(Thread* thread); 237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool createFakeRunFrame(Thread* thread); 238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* interpThreadStart(void* arg); 239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* internalThreadStart(void* arg); 240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void threadExitUncaughtException(Thread* thread, Object* group); 241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void threadExitCheck(void* arg); 242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void waitForThreadSuspend(Thread* self, Thread* thread); 243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int getThreadPriorityFromSystem(void); 244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 24546cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee/* 24646cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee * The JIT needs to know if any thread is suspended. We do this by 24746cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee * maintaining a global sum of all threads' suspend counts. All suspendCount 24846cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee * updates should go through this after aquiring threadSuspendCountLock. 24946cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee */ 25046cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbeestatic inline void dvmAddToThreadSuspendCount(int *pSuspendCount, int delta) 25146cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee{ 25246cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee *pSuspendCount += delta; 25346cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee gDvm.sumThreadSuspendCount += delta; 25446cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee} 255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize thread list and main thread's environment. We need to set 258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * up some basic stuff so that dvmThreadSelf() will work when we start 259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * loading classes (e.g. to check for exceptions). 260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmThreadStartup(void) 262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* thread; 264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* allocate a TLS slot */ 266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pthread_key_create(&gDvm.pthreadKeySelf, threadExitCheck) != 0) { 267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("ERROR: pthread_key_create failed\n"); 268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* test our pthread lib */ 272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pthread_getspecific(gDvm.pthreadKeySelf) != NULL) 273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("WARNING: newly-created pthread TLS slot is not NULL\n"); 274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* prep thread-related locks and conditions */ 276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmInitMutex(&gDvm.threadListLock); 277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_init(&gDvm.threadStartCond, NULL); 278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //dvmInitMutex(&gDvm.vmExitLock); 279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_init(&gDvm.vmExitCond, NULL); 280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmInitMutex(&gDvm._threadSuspendLock); 281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmInitMutex(&gDvm.threadSuspendCountLock); 282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_init(&gDvm.threadSuspendCountCond, NULL); 283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef WITH_DEADLOCK_PREDICTION 284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmInitMutex(&gDvm.deadlockHistoryLock); 285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Dedicated monitor for Thread.sleep(). 289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * TODO: change this to an Object* so we don't have to expose this 290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * call, and we interact better with JDWP monitor calls. Requires 291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * deferring the object creation to much later (e.g. final "main" 292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread prep) or until first use. 293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.threadSleepMon = dvmCreateMonitor(NULL); 295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.threadIdMap = dvmAllocBitVector(kMaxThreadId, false); 297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread = allocThread(gDvm.stackSize); 299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == NULL) 300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* switch mode for when we run initializers */ 303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->status = THREAD_RUNNING; 304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to assign the threadId early so we can lock/notify 307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * object monitors. We'll set the "threadObj" field later. 308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project prepareThread(thread); 310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.threadList = thread; 311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef COUNT_PRECISE_METHODS 313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.preciseMethods = dvmPointerSetAlloc(200); 314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We're a little farther up now, and can load some basic classes. 321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We're far enough along that we can poke at java.lang.Thread and friends, 323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * but should not assume that static initializers have run (or cause them 324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to do so). That means no object allocations yet. 325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmThreadObjStartup(void) 327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Cache the locations of these classes. It's likely that we're the 330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * first to reference them, so they're being loaded now. 331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.classJavaLangThread = 333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindSystemClassNoInit("Ljava/lang/Thread;"); 334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.classJavaLangVMThread = 335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindSystemClassNoInit("Ljava/lang/VMThread;"); 336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.classJavaLangThreadGroup = 337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindSystemClassNoInit("Ljava/lang/ThreadGroup;"); 338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.classJavaLangThread == NULL || 339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.classJavaLangThreadGroup == NULL || 340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.classJavaLangThreadGroup == NULL) 341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Could not find one or more essential thread classes\n"); 343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Cache field offsets. This makes things a little faster, at the 348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * expense of hard-coding non-public field names into the VM. 349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_vmThread = 351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindFieldOffset(gDvm.classJavaLangThread, 352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "vmThread", "Ljava/lang/VMThread;"); 353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_group = 354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindFieldOffset(gDvm.classJavaLangThread, 355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "group", "Ljava/lang/ThreadGroup;"); 356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_daemon = 357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindFieldOffset(gDvm.classJavaLangThread, "daemon", "Z"); 358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_name = 359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindFieldOffset(gDvm.classJavaLangThread, 360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "name", "Ljava/lang/String;"); 361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_priority = 362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindFieldOffset(gDvm.classJavaLangThread, "priority", "I"); 363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.offJavaLangThread_vmThread < 0 || 365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_group < 0 || 366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_daemon < 0 || 367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_name < 0 || 368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_priority < 0) 369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find all fields in java.lang.Thread\n"); 371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangVMThread_thread = 375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindFieldOffset(gDvm.classJavaLangVMThread, 376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "thread", "Ljava/lang/Thread;"); 377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangVMThread_vmData = 378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFindFieldOffset(gDvm.classJavaLangVMThread, "vmData", "I"); 379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.offJavaLangVMThread_thread < 0 || 380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangVMThread_vmData < 0) 381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find all fields in java.lang.VMThread\n"); 383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Cache the vtable offset for "run()". 388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We don't want to keep the Method* because then we won't find see 390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * methods defined in subclasses. 391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* meth; 393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project meth = dvmFindVirtualMethodByDescriptor(gDvm.classJavaLangThread, "run", "()V"); 394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (meth == NULL) { 395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find run() in java.lang.Thread\n"); 396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.voffJavaLangThread_run = meth->methodIndex; 399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Cache vtable offsets for ThreadGroup methods. 402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project meth = dvmFindVirtualMethodByDescriptor(gDvm.classJavaLangThreadGroup, 404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "removeThread", "(Ljava/lang/Thread;)V"); 405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (meth == NULL) { 406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find removeThread(Thread) in java.lang.ThreadGroup\n"); 407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.voffJavaLangThreadGroup_removeThread = meth->methodIndex; 410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * All threads should be stopped by now. Clean up some thread globals. 416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmThreadShutdown(void) 418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.threadList != NULL) { 420f17638ea0748c131b68ddd72039022f04d79bd08Andy McFadden /* 421f17638ea0748c131b68ddd72039022f04d79bd08Andy McFadden * If we walk through the thread list and try to free the 422f17638ea0748c131b68ddd72039022f04d79bd08Andy McFadden * lingering thread structures (which should only be for daemon 423f17638ea0748c131b68ddd72039022f04d79bd08Andy McFadden * threads), the daemon threads may crash if they execute before 424f17638ea0748c131b68ddd72039022f04d79bd08Andy McFadden * the process dies. Let them leak. 425f17638ea0748c131b68ddd72039022f04d79bd08Andy McFadden */ 426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project freeThread(gDvm.threadList); 427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.threadList = NULL; 428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFreeBitVector(gDvm.threadIdMap); 431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmFreeMonitorList(); 433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_key_delete(gDvm.pthreadKeySelf); 435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Grab the suspend count global lock. 440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline void lockThreadSuspendCount(void) 442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Don't try to change to VMWAIT here. When we change back to RUNNING 445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we have to check for a pending suspend, which results in grabbing 446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * this lock recursively. Doesn't work with "fast" pthread mutexes. 447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This lock is always held for very brief periods, so as long as 449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * mutex ordering is respected we shouldn't stall. 450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 451fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmLockMutex(&gDvm.threadSuspendCountLock); 452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release the suspend count global lock. 456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline void unlockThreadSuspendCount(void) 458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockMutex(&gDvm.threadSuspendCountLock); 460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Grab the thread list global lock. 464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is held while "suspend all" is trying to make everybody stop. If 466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the shutdown is in progress, and somebody tries to grab the lock, they'll 467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * have to wait for the GC to finish. Therefore it's important that the 468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread not be in RUNNING mode. 469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We don't have to check to see if we should be suspended once we have 471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the lock. Nobody can suspend all threads without holding the thread list 472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * lock while they do it, so by definition there isn't a GC in progress. 4734486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * 4743469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * This function deliberately avoids the use of dvmChangeStatus(), 4753469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * which could grab threadSuspendCountLock. To avoid deadlock, threads 4763469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * are required to grab the thread list lock before the thread suspend 4773469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * count lock. (See comment in DvmGlobals.) 4783469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * 4794486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * TODO: consider checking for suspend after acquiring the lock, and 4804486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * backing off if set. As stated above, it can't happen during normal 4814486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * execution, but it *can* happen during shutdown when daemon threads 4824486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * are being suspended. 483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmLockThreadList(Thread* self) 485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ThreadStatus oldStatus; 487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self == NULL) /* try to get it from TLS */ 489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self = dvmThreadSelf(); 490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self != NULL) { 492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project oldStatus = self->status; 493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->status = THREAD_VMWAIT; 494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 4954486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden /* happens during VM shutdown */ 496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //LOGW("NULL self in dvmLockThreadList\n"); 497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project oldStatus = -1; // shut up gcc 498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 500fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmLockMutex(&gDvm.threadListLock); 501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self != NULL) 503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->status = oldStatus; 504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release the thread list global lock. 508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmUnlockThreadList(void) 510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 511fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmUnlockMutex(&gDvm.threadListLock); 512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 51499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/* 51599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Convert SuspendCause to a string. 51699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 51799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic const char* getSuspendCauseStr(SuspendCause why) 51899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{ 51999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project switch (why) { 52099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project case SUSPEND_NOT: return "NOT?"; 52199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project case SUSPEND_FOR_GC: return "gc"; 52299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project case SUSPEND_FOR_DEBUG: return "debug"; 52399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project case SUSPEND_FOR_DEBUG_EVENT: return "debug-event"; 52499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project case SUSPEND_FOR_STACK_DUMP: return "stack-dump"; 525fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom case SUSPEND_FOR_VERIFY: return "verify"; 526a8e64a7c83ac6fb487a140f77ab8803b46193f45Ben Cheng#if defined(WITH_JIT) 527a8e64a7c83ac6fb487a140f77ab8803b46193f45Ben Cheng case SUSPEND_FOR_TBL_RESIZE: return "table-resize"; 528a8e64a7c83ac6fb487a140f77ab8803b46193f45Ben Cheng case SUSPEND_FOR_IC_PATCH: return "inline-cache-patch"; 52960c24f436d603c564d5351a6f81821f12635733cBen Cheng case SUSPEND_FOR_CC_RESET: return "reset-code-cache"; 530964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee case SUSPEND_FOR_REFRESH: return "refresh jit status"; 531a8e64a7c83ac6fb487a140f77ab8803b46193f45Ben Cheng#endif 53299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project default: return "UNKNOWN"; 53399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 53499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project} 535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Grab the "thread suspend" lock. This is required to prevent the 538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * GC and the debugger from simultaneously suspending all threads. 539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If we fail to get the lock, somebody else is trying to suspend all 541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * threads -- including us. If we go to sleep on the lock we'll deadlock 542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the VM. Loop until we get it or somebody puts us to sleep. 543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void lockThreadSuspend(const char* who, SuspendCause why) 545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const int kSpinSleepTime = 3*1000*1000; /* 3s */ 547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project u8 startWhen = 0; // init req'd to placate gcc 548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int sleepIter = 0; 549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int cc; 55097319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao 551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project do { 552fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom cc = dvmTryLockMutex(&gDvm._threadSuspendLock); 553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (cc != 0) { 554fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom Thread* self = dvmThreadSelf(); 555fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom 556fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom if (!dvmCheckSuspendPending(self)) { 557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 5582aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * Could be that a resume-all is in progress, and something 5592aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * grabbed the CPU when the wakeup was broadcast. The thread 5602aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * performing the resume hasn't had a chance to release the 561e8059be22919a5978ff9abb2f961faac5e3d6a4dAndy McFadden * thread suspend lock. (We release before the broadcast, 562e8059be22919a5978ff9abb2f961faac5e3d6a4dAndy McFadden * so this should be a narrow window.) 5632aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * 5642aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * Could be we hit the window as a suspend was started, 5652aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * and the lock has been grabbed but the suspend counts 5662aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * haven't been incremented yet. 56799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 56899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Could be an unusual JNI thread-attach thing. 56999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 57099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Could be the debugger telling us to resume at roughly 571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the same time we're posting an event. 572a8e64a7c83ac6fb487a140f77ab8803b46193f45Ben Cheng * 573a8e64a7c83ac6fb487a140f77ab8803b46193f45Ben Cheng * Could be two app threads both want to patch predicted 574a8e64a7c83ac6fb487a140f77ab8803b46193f45Ben Cheng * chaining cells around the same time. 575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 57699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGI("threadid=%d ODD: want thread-suspend lock (%s:%s)," 57799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project " it's held, no suspend pending\n", 578fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom self->threadId, who, getSuspendCauseStr(why)); 57999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } else { 58099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* we suspended; reset timeout */ 58199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project sleepIter = 0; 582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* give the lock-holder a chance to do some work */ 585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (sleepIter == 0) 586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project startWhen = dvmGetRelativeTimeUsec(); 587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmIterativeSleep(sleepIter++, kSpinSleepTime, startWhen)) { 58899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGE("threadid=%d: couldn't get thread-suspend lock (%s:%s)," 589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project " bailing\n", 590fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom self->threadId, who, getSuspendCauseStr(why)); 5912aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden /* threads are not suspended, thread dump could crash */ 592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpAllThreads(false); 593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAbort(); 594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } while (cc != 0); 597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(cc == 0); 598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release the "thread suspend" lock. 602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline void unlockThreadSuspend(void) 604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 605fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmUnlockMutex(&gDvm._threadSuspendLock); 606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Kill any daemon threads that still exist. All of ours should be 611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * stopped, so these should be Thread objects or JNI-attached threads 612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * started by the application. Actively-running threads are likely 613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to crash the process if they continue to execute while the VM 614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * shuts down, so we really need to kill or suspend them. (If we want 615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the VM to restart within this process, we need to kill them, but that 616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * leaves open the possibility of orphaned resources.) 617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Waiting for the thread to suspend may be unwise at this point, but 619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * if one of these is wedged in a critical section then we probably 620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * would've locked up on the last GC attempt. 621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It's possible for this function to get called after a failed 623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * initialization, so be careful with assumptions about the environment. 6244486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * 6254486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * This will be called from whatever thread calls DestroyJavaVM, usually 6264486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * but not necessarily the main thread. It's likely, but not guaranteed, 6274486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * that the current thread has already been cleaned up. 628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmSlayDaemons(void) 630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 6314486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden Thread* self = dvmThreadSelf(); // may be null 632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* target; 6334486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden int threadId = 0; 6344486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden bool doWait = false; 635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6384486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden if (self != NULL) 6394486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden threadId = self->threadId; 6404486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project target = gDvm.threadList; 642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (target != NULL) { 643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (target == self) { 644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project target = target->next; 645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmGetFieldBoolean(target->threadObj, 649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_daemon)) 650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 6514486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden /* should never happen; suspend it with the rest */ 652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("threadid=%d: non-daemon id=%d still running at shutdown?!\n", 6534486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden threadId, target->threadId); 654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6564486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden char* threadName = dvmGetThreadName(target); 6574486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden LOGD("threadid=%d: suspending daemon id=%d name='%s'\n", 6584486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden threadId, target->threadId, threadName); 6594486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden free(threadName); 660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6614486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden /* mark as suspended */ 6624486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden lockThreadSuspendCount(); 6634486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden dvmAddToThreadSuspendCount(&target->suspendCount, 1); 6644486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden unlockThreadSuspendCount(); 6654486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden doWait = true; 6664486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 6674486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden target = target->next; 6684486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 6694486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 6704486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden //dvmDumpAllThreads(false); 6714486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 6724486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden /* 6734486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * Unlock the thread list, relocking it later if necessary. It's 6744486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * possible a thread is in VMWAIT after calling dvmLockThreadList, 6754486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * and that function *doesn't* check for pending suspend after 6764486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * acquiring the lock. We want to let them finish their business 6774486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * and see the pending suspend before we continue here. 6784486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * 6794486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * There's no guarantee of mutex fairness, so this might not work. 6804486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * (The alternative is to have dvmLockThreadList check for suspend 6814486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * after acquiring the lock and back off, something we should consider.) 6824486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden */ 6834486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden dvmUnlockThreadList(); 6844486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 6854486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden if (doWait) { 686d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden bool complained = false; 687d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden 6884486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden usleep(200 * 1000); 6894486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 6904486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden dvmLockThreadList(self); 6914486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 6924486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden /* 6934486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * Sleep for a bit until the threads have suspended. We're trying 6944486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * to exit, so don't wait for too long. 6954486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden */ 6964486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden int i; 6974486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden for (i = 0; i < 10; i++) { 6984486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden bool allSuspended = true; 6994486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 7004486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden target = gDvm.threadList; 7014486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden while (target != NULL) { 7024486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden if (target == self) { 7034486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden target = target->next; 7044486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden continue; 7054486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 7064486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 707b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden if (target->status == THREAD_RUNNING) { 708d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (!complained) 709d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGD("threadid=%d not ready yet\n", target->threadId); 7104486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden allSuspended = false; 711d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden /* keep going so we log each running daemon once */ 7124486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 7134486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 7144486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden target = target->next; 7154486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 7164486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 7174486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden if (allSuspended) { 7184486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden LOGD("threadid=%d: all daemons have suspended\n", threadId); 7194486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden break; 7204486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } else { 721d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (!complained) { 722d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden complained = true; 723d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGD("threadid=%d: waiting briefly for daemon suspension\n", 724d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden threadId); 725d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 7264486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 7274486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 7284486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden usleep(200 * 1000); 7294486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 7304486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden dvmUnlockThreadList(); 7314486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 7334486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden#if 0 /* bad things happen if they come out of JNI or "spuriously" wake up */ 7344486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden /* 7354486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden * Abandon the threads and recover their resources. 7364486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden */ 7374486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden target = gDvm.threadList; 7384486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden while (target != NULL) { 7394486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden Thread* nextTarget = target->next; 7404486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden unlinkThread(target); 741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project freeThread(target); 742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project target = nextTarget; 743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 7444486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden#endif 745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 7464486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden //dvmDumpAllThreads(true); 747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Finish preparing the parts of the Thread struct required to support 752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * JNI registration. 753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmPrepMainForJni(JNIEnv* pEnv) 755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self; 757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* main thread is always first in list at this point */ 759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self = gDvm.threadList; 760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(self->threadId == kMainThreadId); 761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* create a "fake" JNI frame at the top of the main thread interp stack */ 763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!createFakeEntryFrame(self)) 764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* fill these in, since they weren't ready at dvmCreateJNIEnv time */ 767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetJniEnvThreadId(pEnv, self); 768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetThreadJNIEnv(self, (JNIEnv*) pEnv); 769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Finish preparing the main thread, allocating some objects to represent 776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it. As part of doing so, we finish initializing Thread and ThreadGroup. 777a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden * This will execute some interpreted code (e.g. class initializers). 778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmPrepMainThread(void) 780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* thread; 782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* groupObj; 783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* threadObj; 784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* vmThreadObj; 785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StringObject* threadNameStr; 786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* init; 787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project JValue unused; 788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("+++ finishing prep on main VM thread\n"); 790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* main thread is always first in list at this point */ 792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread = gDvm.threadList; 793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->threadId == kMainThreadId); 794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Make sure the classes are initialized. We have to do this before 797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we create an instance of them. 798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmInitClass(gDvm.classJavaLangClass)) { 800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("'Class' class failed to initialize\n"); 801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmInitClass(gDvm.classJavaLangThreadGroup) || 804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project !dvmInitClass(gDvm.classJavaLangThread) || 805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project !dvmInitClass(gDvm.classJavaLangVMThread)) 806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("thread classes failed to initialize\n"); 808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project groupObj = dvmGetMainThreadGroup(); 812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (groupObj == NULL) 813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Allocate and construct a Thread with the internal-creation 817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * constructor. 818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT); 820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (threadObj == NULL) { 821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("unable to allocate main thread object\n"); 822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseTrackedAlloc(threadObj, NULL); 825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 82681f3ebe03cd33c9003641084bece0604ee68bf88Barry Hayes threadNameStr = dvmCreateStringFromCstr("main"); 827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (threadNameStr == NULL) 828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseTrackedAlloc((Object*)threadNameStr, NULL); 830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangThread, "<init>", 832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); 833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(init != NULL); 834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCallMethod(thread, init, threadObj, &unused, groupObj, threadNameStr, 835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project THREAD_NORM_PRIORITY, false); 836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmCheckException(thread)) { 837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("exception thrown while constructing main thread object\n"); 838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Allocate and construct a VMThread. 843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT); 845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (vmThreadObj == NULL) { 846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("unable to allocate main vmthread object\n"); 847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseTrackedAlloc(vmThreadObj, NULL); 850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangVMThread, "<init>", 852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "(Ljava/lang/Thread;)V"); 853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCallMethod(thread, init, vmThreadObj, &unused, threadObj); 854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmCheckException(thread)) { 855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("exception thrown while constructing main vmthread object\n"); 856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* set the VMThread.vmData field to our Thread struct */ 860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(gDvm.offJavaLangVMThread_vmData != 0); 861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)thread); 862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Stuff the VMThread back into the Thread. From this point on, other 865a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden * Threads will see that this Thread is running (at least, they would, 866a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden * if there were any). 867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, 869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project vmThreadObj); 870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadObj = threadObj; 872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 874a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden * Set the context class loader. This invokes a ClassLoader method, 875a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden * which could conceivably call Thread.currentThread(), so we want the 876a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden * Thread to be fully configured before we do this. 877a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden */ 878a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden Object* systemLoader = dvmGetSystemClassLoader(); 879a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden if (systemLoader == NULL) { 880a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden LOGW("WARNING: system class loader is NULL (setting main ctxt)\n"); 881a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden /* keep going */ 882a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden } 883a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden int ctxtClassLoaderOffset = dvmFindFieldOffset(gDvm.classJavaLangThread, 884a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden "contextClassLoader", "Ljava/lang/ClassLoader;"); 885a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden if (ctxtClassLoaderOffset < 0) { 886a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden LOGE("Unable to find contextClassLoader field in Thread\n"); 887a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden return false; 888a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden } 889a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden dvmSetFieldObject(threadObj, ctxtClassLoaderOffset, systemLoader); 890a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden 891a1a7a349843bf3bd730c3eb3bff529188f835d50Andy McFadden /* 892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Finish our thread prep. 893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* include self in non-daemon threads (mainly for AttachCurrentThread) */ 896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.nonDaemonThreadCount++; 897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Alloc and initialize a Thread struct. 904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 905e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * Does not create any objects, just stuff on the system (malloc) heap. 906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic Thread* allocThread(int interpStackSize) 908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* thread; 910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project u1* stackBottom; 911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread = (Thread*) calloc(1, sizeof(Thread)); 913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == NULL) 914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 91697319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION) 91797319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao if (dvmSelfVerificationShadowSpaceAlloc(thread) == NULL) 91897319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao return NULL; 91997319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif 92097319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao 921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(interpStackSize >= kMinStackSize && interpStackSize <=kMaxStackSize); 922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->status = THREAD_INITIALIZING; 924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->suspendCount = 0; 925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef WITH_ALLOC_LIMITS 927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->allocLimit = -1; 928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Allocate and initialize the interpreted code stack. We essentially 932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "lose" the alloc pointer, which points at the bottom of the stack, 933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * but we can get it back later because we know how big the stack is. 934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The stack must be aligned on a 4-byte boundary. 936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef MALLOC_INTERP_STACK 938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stackBottom = (u1*) malloc(interpStackSize); 939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (stackBottom == NULL) { 94097319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION) 94197319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao dvmSelfVerificationShadowSpaceFree(thread); 94297319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif 943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(thread); 944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project memset(stackBottom, 0xc5, interpStackSize); // stop valgrind complaints 947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stackBottom = mmap(NULL, interpStackSize, PROT_READ | PROT_WRITE, 949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project MAP_PRIVATE | MAP_ANON, -1, 0); 950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (stackBottom == MAP_FAILED) { 95197319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION) 95297319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao dvmSelfVerificationShadowSpaceFree(thread); 95397319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif 954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(thread); 955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(((u4)stackBottom & 0x03) == 0); // looks like our malloc ensures this 960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->interpStackSize = interpStackSize; 961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->interpStackStart = stackBottom + interpStackSize; 962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->interpStackEnd = stackBottom + STACK_OVERFLOW_RESERVE; 963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* give the thread code a chance to set things up */ 965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmInitInterpStack(thread, interpStackSize); 966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return thread; 968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get a meaningful thread ID. At present this only has meaning under Linux, 972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * where getpid() and gettid() sometimes agree and sometimes don't depending 973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * on your thread model (try "export LD_ASSUME_KERNEL=2.4.19"). 974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpid_t dvmGetSysThreadId(void) 976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_GETTID 978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return gettid(); 979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return getpid(); 981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Finish initialization of a Thread struct. 986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This must be called while executing in the new thread, but before the 988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread is added to the thread list. 989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 990fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * NOTE: The threadListLock must be held by the caller (needed for 991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * assignThreadId()). 992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool prepareThread(Thread* thread) 994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assignThreadId(thread); 996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->handle = pthread_self(); 997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->systemTid = dvmGetSysThreadId(); 998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //LOGI("SYSTEM TID IS %d (pid is %d)\n", (int) thread->systemTid, 1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // (int) getpid()); 1001fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom /* 1002fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * If we were called by dvmAttachCurrentThread, the self value is 1003fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * already correctly established as "thread". 1004fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom */ 1005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project setThreadSelf(thread); 1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("threadid=%d: interp stack at %p\n", 1008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadId, thread->interpStackStart - thread->interpStackSize); 1009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize invokeReq. 1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 101377f52ebffa3793a7e824fab7da02eaee9afdae0eCarl Shapiro dvmInitMutex(&thread->invokeReq.lock); 1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_init(&thread->invokeReq.cv, NULL); 1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize our reference tracking tables. 1018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Most threads won't use jniMonitorRefTable, so we clear out the 1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * structure but don't call the init function (which allocs storage). 1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1022d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#ifdef USE_INDIRECT_REF 1023d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden if (!dvmInitIndirectRefTable(&thread->jniLocalRefTable, 1024d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden kJniLocalRefMin, kJniLocalRefMax, kIndirectKindLocal)) 1025d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden return false; 1026d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#else 1027d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden /* 1028d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden * The JNI local ref table *must* be fixed-size because we keep pointers 1029d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden * into the table in our stack frames. 1030d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden */ 1031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmInitReferenceTable(&thread->jniLocalRefTable, 1032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project kJniLocalRefMax, kJniLocalRefMax)) 1033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1034d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#endif 1035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmInitReferenceTable(&thread->internalLocalRefTable, 1036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project kInternalRefDefault, kInternalRefMax)) 1037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project memset(&thread->jniMonitorRefTable, 0, sizeof(thread->jniMonitorRefTable)); 1040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 104177f52ebffa3793a7e824fab7da02eaee9afdae0eCarl Shapiro pthread_cond_init(&thread->waitCond, NULL); 104277f52ebffa3793a7e824fab7da02eaee9afdae0eCarl Shapiro dvmInitMutex(&thread->waitMutex); 104377f52ebffa3793a7e824fab7da02eaee9afdae0eCarl Shapiro 1044f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 1045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Remove a thread from the internal list. 1049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Clear out the links to make it obvious that the thread is 1050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * no longer on the list. Caller must hold gDvm.threadListLock. 1051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void unlinkThread(Thread* thread) 1053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: removing from list\n", thread->threadId); 1055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == gDvm.threadList) { 1056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->prev == NULL); 1057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.threadList = thread->next; 1058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 1059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->prev != NULL); 1060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->prev->next = thread->next; 1061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->next != NULL) 1063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->next->prev = thread->prev; 1064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->prev = thread->next = NULL; 1065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Free a Thread struct, and all the stuff allocated within. 1069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void freeThread(Thread* thread) 1071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == NULL) 1073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 1074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* thread->threadId is zero at this point */ 1076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGVV("threadid=%d: freeing\n", thread->threadId); 1077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->interpStackStart != NULL) { 1079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project u1* interpStackBottom; 1080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project interpStackBottom = thread->interpStackStart; 1082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project interpStackBottom -= thread->interpStackSize; 1083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef MALLOC_INTERP_STACK 1084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(interpStackBottom); 1085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 1086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (munmap(interpStackBottom, thread->interpStackSize) != 0) 1087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("munmap(thread stack) failed\n"); 1088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 1089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1091d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#ifdef USE_INDIRECT_REF 1092d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden dvmClearIndirectRefTable(&thread->jniLocalRefTable); 1093d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#else 1094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmClearReferenceTable(&thread->jniLocalRefTable); 1095d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#endif 1096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmClearReferenceTable(&thread->internalLocalRefTable); 1097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (&thread->jniMonitorRefTable.table != NULL) 1098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmClearReferenceTable(&thread->jniMonitorRefTable); 1099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 110097319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION) 110197319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao dvmSelfVerificationShadowSpaceFree(thread); 110297319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif 1103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(thread); 1104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Like pthread_self(), but on a Thread*. 1108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThread* dvmThreadSelf(void) 1110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return (Thread*) pthread_getspecific(gDvm.pthreadKeySelf); 1112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Explore our sense of self. Stuffs the thread pointer into TLS. 1116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void setThreadSelf(Thread* thread) 1118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int cc; 1120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project cc = pthread_setspecific(gDvm.pthreadKeySelf, thread); 1122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (cc != 0) { 1123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Sometimes this fails under Bionic with EINVAL during shutdown. 1125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This can happen if the timing is just right, e.g. a thread 1126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * fails to attach during shutdown, but the "fail" path calls 1127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * here to ensure we clean up after ourselves. 1128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread != NULL) { 1130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("pthread_setspecific(%p) failed, err=%d\n", thread, cc); 1131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAbort(); /* the world is fundamentally hosed */ 1132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is associated with the pthreadKeySelf key. It's called by the 1138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * pthread library when a thread is exiting and the "self" pointer in TLS 1139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * is non-NULL, meaning the VM hasn't had a chance to clean up. In normal 1140909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden * operation this will not be called. 1141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is mainly of use to ensure that we don't leak resources if, for 1143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * example, a thread attaches itself to us with AttachCurrentThread and 1144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * then exits without notifying the VM. 114534e25bb8952da1ea7d28352bbe7ae8ed53a1c876Andy McFadden * 114634e25bb8952da1ea7d28352bbe7ae8ed53a1c876Andy McFadden * We could do the detach here instead of aborting, but this will lead to 114734e25bb8952da1ea7d28352bbe7ae8ed53a1c876Andy McFadden * portability problems. Other implementations do not do this check and 114834e25bb8952da1ea7d28352bbe7ae8ed53a1c876Andy McFadden * will simply be unaware that the thread has exited, leading to resource 114934e25bb8952da1ea7d28352bbe7ae8ed53a1c876Andy McFadden * leaks (and, if this is a non-daemon thread, an infinite hang when the 115034e25bb8952da1ea7d28352bbe7ae8ed53a1c876Andy McFadden * VM tries to shut down). 1151909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden * 1152909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden * Because some implementations may want to use the pthread destructor 1153909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden * to initiate the detach, and the ordering of destructors is not defined, 1154909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden * we want to iterate a couple of times to give those a chance to run. 1155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void threadExitCheck(void* arg) 1157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1158909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden const int kMaxCount = 2; 1159909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden 1160909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden Thread* self = (Thread*) arg; 1161909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden assert(self != NULL); 1162909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden 1163909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden LOGV("threadid=%d: threadExitCheck(%p) count=%d\n", 1164909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden self->threadId, arg, self->threadExitCheckCount); 1165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1166909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden if (self->status == THREAD_ZOMBIE) { 1167909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden LOGW("threadid=%d: Weird -- shouldn't be in threadExitCheck\n", 1168909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden self->threadId); 1169909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden return; 1170909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden } 1171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1172909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden if (self->threadExitCheckCount < kMaxCount) { 1173909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden /* 1174909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden * Spin a couple of times to let other destructors fire. 1175909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden */ 1176909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden LOGD("threadid=%d: thread exiting, not yet detached (count=%d)\n", 1177909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden self->threadId, self->threadExitCheckCount); 1178909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden self->threadExitCheckCount++; 1179909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden int cc = pthread_setspecific(gDvm.pthreadKeySelf, self); 1180909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden if (cc != 0) { 1181909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden LOGE("threadid=%d: unable to re-add thread to TLS\n", 1182909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden self->threadId); 1183909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden dvmAbort(); 1184909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden } 1185909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden } else { 1186909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden LOGE("threadid=%d: native thread exited without detaching\n", 1187909ce240fd544de9ba42daf590e1cf17e874ec3bAndy McFadden self->threadId); 1188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAbort(); 1189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Assign the threadId. This needs to be a small integer so that our 1195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "thin" locks fit in a small number of bits. 1196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We reserve zero for use as an invalid ID. 1198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1199fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * This must be called with threadListLock held. 1200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void assignThreadId(Thread* thread) 1202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 120359a93123f48e9d7c2992ec4b08f75b90c74cb468Carl Shapiro /* 120459a93123f48e9d7c2992ec4b08f75b90c74cb468Carl Shapiro * Find a small unique integer. threadIdMap is a vector of 1205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * kMaxThreadId bits; dvmAllocBit() returns the index of a 1206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * bit, meaning that it will always be < kMaxThreadId. 1207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int num = dvmAllocBit(gDvm.threadIdMap); 1209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (num < 0) { 1210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Ran out of thread IDs\n"); 1211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAbort(); // TODO: make this a non-fatal error result 1212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 121459a93123f48e9d7c2992ec4b08f75b90c74cb468Carl Shapiro thread->threadId = num + 1; 1215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->threadId != 0); 1217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->threadId != DVM_LOCK_INITIAL_THIN_VALUE); 1218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Give back the thread ID. 1222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void releaseThreadId(Thread* thread) 1224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->threadId > 0); 12267eed8085c5f649fdd7e320116e4062d29a199406Carl Shapiro dvmClearBit(gDvm.threadIdMap, thread->threadId - 1); 1227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadId = 0; 1228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Add a stack frame that makes it look like the native code in the main 1233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread was originally invoked from interpreted code. This gives us a 1234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * place to hang JNI local references. The VM spec says (v2 5.2) that the 1235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * VM begins by executing "main" in a class, so in a way this brings us 1236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * closer to the spec. 1237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool createFakeEntryFrame(Thread* thread) 1239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->threadId == kMainThreadId); // main thread only 1241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* find the method on first use */ 1243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.methFakeNativeEntry == NULL) { 1244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ClassObject* nativeStart; 1245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* mainMeth; 1246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project nativeStart = dvmFindSystemClassNoInit( 1248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "Ldalvik/system/NativeStart;"); 1249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (nativeStart == NULL) { 1250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find dalvik.system.NativeStart class\n"); 1251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Because we are creating a frame that represents application code, we 1256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * want to stuff the application class loader into the method's class 1257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * loader field, even though we're using the system class loader to 1258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * load it. This makes life easier over in JNI FindClass (though it 1259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * could bite us in other ways). 1260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unfortunately this is occurring too early in the initialization, 1262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of necessity coming before JNI is initialized, and we're not quite 1263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ready to set up the application class loader. 1264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * So we save a pointer to the method in gDvm.methFakeNativeEntry 1266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and check it in FindClass. The method is private so nobody else 1267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * can call it. 1268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //nativeStart->classLoader = dvmGetSystemClassLoader(); 1270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project mainMeth = dvmFindDirectMethodByDescriptor(nativeStart, 1272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "main", "([Ljava/lang/String;)V"); 1273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (mainMeth == NULL) { 1274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find 'main' in dalvik.system.NativeStart\n"); 1275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.methFakeNativeEntry = mainMeth; 1279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1281fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom if (!dvmPushJNIFrame(thread, gDvm.methFakeNativeEntry)) 1282fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom return false; 1283fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom 1284fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom /* 1285fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * Null out the "String[] args" argument. 1286fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom */ 1287fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom assert(gDvm.methFakeNativeEntry->registersSize == 1); 1288fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom u4* framePtr = (u4*) thread->curFrame; 1289fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom framePtr[0] = 0; 1290fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom 1291fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom return true; 1292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Add a stack frame that makes it look like the native thread has been 1297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * executing interpreted code. This gives us a place to hang JNI local 1298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * references. 1299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool createFakeRunFrame(Thread* thread) 1301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ClassObject* nativeStart; 1303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* runMeth; 1304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1305fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom /* 1306fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * TODO: cache this result so we don't have to dig for it every time 1307fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * somebody attaches a thread to the VM. Also consider changing this 1308fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * to a static method so we don't have a null "this" pointer in the 1309fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * "ins" on the stack. (Does it really need to look like a Runnable?) 1310fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom */ 1311fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom nativeStart = dvmFindSystemClassNoInit("Ldalvik/system/NativeStart;"); 1312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (nativeStart == NULL) { 1313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find dalvik.system.NativeStart class\n"); 1314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project runMeth = dvmFindVirtualMethodByDescriptor(nativeStart, "run", "()V"); 1318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (runMeth == NULL) { 1319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Unable to find 'run' in dalvik.system.NativeStart\n"); 1320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1323fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom if (!dvmPushJNIFrame(thread, runMeth)) 1324fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom return false; 1325fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom 1326fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom /* 1327fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * Provide a NULL 'this' argument. The method we've put at the top of 1328fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * the stack looks like a virtual call to run() in a Runnable class. 1329fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * (If we declared the method static, it wouldn't take any arguments 1330fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * and we wouldn't have to do this.) 1331fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom */ 1332fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom assert(runMeth->registersSize == 1); 1333fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom u4* framePtr = (u4*) thread->curFrame; 1334fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom framePtr[0] = 0; 1335fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom 1336fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom return true; 1337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Helper function to set the name of the current thread 1341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void setThreadName(const char *threadName) 1343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int hasAt = 0; 1345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int hasDot = 0; 1346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const char *s = threadName; 1347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (*s) { 1348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (*s == '.') hasDot = 1; 1349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else if (*s == '@') hasAt = 1; 1350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project s++; 1351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int len = s - threadName; 1353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (len < 15 || hasAt || !hasDot) { 1354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project s = threadName; 1355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 1356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project s = threadName + len - 15; 1357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 135822ec609bad694746d252606ae4f59cf3f58387bbAndy McFadden#if defined(HAVE_ANDROID_PTHREAD_SETNAME_NP) 1359b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden /* pthread_setname_np fails rather than truncating long strings */ 1360b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded into bionic 1361b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden strncpy(buf, s, sizeof(buf)-1); 1362b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden buf[sizeof(buf)-1] = '\0'; 1363b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden int err = pthread_setname_np(pthread_self(), buf); 1364b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden if (err != 0) { 1365b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden LOGW("Unable to set the name of current thread to '%s': %s\n", 1366b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden buf, strerror(err)); 1367b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden } 1368bcd88cc712eb56b248eae03b603af778a308050fAndré Goddard Rosa#elif defined(HAVE_PRCTL) 1369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0); 1370bcd88cc712eb56b248eae03b603af778a308050fAndré Goddard Rosa#else 1371b122c8b1030e4da9cbc0e7e401a72e1d614e9c3eAndy McFadden LOGD("No way to set current thread's name (%s)\n", s); 1372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 1373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create a thread as a result of java.lang.Thread.start(). 1377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We do have to worry about some concurrency problems, e.g. programs 1379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * that try to call Thread.start() on the same object from multiple threads. 1380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (This will fail for all but one, but we have to make sure that it succeeds 1381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * for exactly one.) 1382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Some of the complexity here arises from our desire to mimic the 1384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Thread vs. VMThread class decomposition we inherited. We've been given 1385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * a Thread, and now we need to create a VMThread and then populate both 1386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * objects. We also need to create one of our internal Thread objects. 1387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Pass in a stack size of 0 to get the default. 1389e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * 1390e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * The "threadObj" reference must be pinned by the caller to prevent the GC 1391e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * from moving it around (e.g. added to the tracked allocation list). 1392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmCreateInterpThread(Object* threadObj, int reqStackSize) 1394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_attr_t threadAttr; 1396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_t threadHandle; 1397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self; 1398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* newThread = NULL; 1399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* vmThreadObj = NULL; 1400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int stackSize; 1401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(threadObj != NULL); 1403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if(gDvm.zygote) { 14059dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee // Allow the sampling profiler thread. We shut it down before forking. 14069dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee StringObject* nameStr = (StringObject*) dvmGetFieldObject(threadObj, 14079dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee gDvm.offJavaLangThread_name); 14089dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee char* threadName = dvmCreateCstrFromString(nameStr); 14099dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee bool profilerThread = strcmp(threadName, "SamplingProfiler") == 0; 14109dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee free(threadName); 14119dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee if (!profilerThread) { 14129dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee dvmThrowException("Ljava/lang/IllegalStateException;", 14139dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee "No new threads in -Xzygote mode"); 1414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 14159dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee goto fail; 14169dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee } 1417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self = dvmThreadSelf(); 1420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (reqStackSize == 0) 1421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stackSize = gDvm.stackSize; 1422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else if (reqStackSize < kMinStackSize) 1423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stackSize = kMinStackSize; 1424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else if (reqStackSize > kMaxStackSize) 1425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stackSize = kMaxStackSize; 1426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else 1427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stackSize = reqStackSize; 1428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_attr_init(&threadAttr); 1430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED); 1431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * To minimize the time spent in the critical section, we allocate the 1434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * vmThread object here. 1435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT); 1437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (vmThreadObj == NULL) 1438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newThread = allocThread(stackSize); 1441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (newThread == NULL) 1442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newThread->threadObj = threadObj; 1444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(newThread->status == THREAD_INITIALIZING); 1446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to lock out other threads while we test and set the 1449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "vmThread" field in java.lang.Thread, because we use that to determine 1450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * if this thread has been started before. We use the thread list lock 1451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * because it's handy and we're going to need to grab it again soon 1452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * anyway. 1453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 1455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread) != NULL) { 1457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmThrowException("Ljava/lang/IllegalThreadStateException;", 1459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "thread has already been started"); 1460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * There are actually three data structures: Thread (object), VMThread 1465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (object), and Thread (C struct). All of them point to at least one 1466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * other. 1467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * As soon as "VMThread.vmData" is assigned, other threads can start 1469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * making calls into us (e.g. setPriority). 1470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)newThread); 1472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj); 1473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Thread creation might take a while, so release the lock. 1476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 14795617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT); 14805617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart, 14812aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden newThread); 14822aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden oldStatus = dvmChangeStatus(self, oldStatus); 14832aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden 14842aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden if (cc != 0) { 1485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Failure generally indicates that we have exceeded system 1487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * resource limits. VirtualMachineError is probably too severe, 1488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * so use OutOfMemoryError. 1489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("Thread creation failed (err=%s)\n", strerror(errno)); 1491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, NULL); 1493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmThrowException("Ljava/lang/OutOfMemoryError;", 1495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "thread creation failed"); 1496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to wait for the thread to start. Otherwise, depending on 1501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the whims of the OS scheduler, we could return and the code in our 1502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread could try to do operations on the new thread before it had 1503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * finished starting. 1504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The new thread will lock the thread list, change its state to 1506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * THREAD_STARTING, broadcast to gDvm.threadStartCond, and then sleep 1507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * on gDvm.threadStartCond (which uses the thread list lock). This 1508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread (the parent) will either see that the thread is already ready 1509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * after we grab the thread list lock, or will be awakened from the 1510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * condition variable on the broadcast. 1511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We don't want to stall the rest of the VM while the new thread 1513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * starts, which can happen if the GC wakes up at the wrong moment. 1514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * So, we change our own status to VMWAIT, and self-suspend if 1515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * necessary after we finish adding the new thread. 1516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We have to deal with an odd race with the GC/debugger suspension 1519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * mechanism when creating a new thread. The information about whether 1520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * or not a thread should be suspended is contained entirely within 1521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the Thread struct; this is usually cleaner to deal with than having 1522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * one or more globally-visible suspension flags. The trouble is that 1523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we could create the thread while the VM is trying to suspend all 1524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * threads. The suspend-count won't be nonzero for the new thread, 1525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * so dvmChangeStatus(THREAD_RUNNING) won't cause a suspension. 1526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The easiest way to deal with this is to prevent the new thread from 1528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * running until the parent says it's okay. This results in the 15292aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * following (correct) sequence of events for a "badly timed" GC 15302aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * (where '-' is us, 'o' is the child, and '+' is some other thread): 1531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - call pthread_create() 1533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - lock thread list 1534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - put self into THREAD_VMWAIT so GC doesn't wait for us 1535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - sleep on condition var (mutex = thread list lock) until child starts 1536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * + GC triggered by another thread 1537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * + thread list locked; suspend counts updated; thread list unlocked 1538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * + loop waiting for all runnable threads to suspend 1539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * + success, start GC 1540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * o child thread wakes, signals condition var to wake parent 1541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * o child waits for parent ack on condition variable 1542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - we wake up, locking thread list 1543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - add child to thread list 1544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - unlock thread list 1545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - change our state back to THREAD_RUNNING; GC causes us to suspend 1546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * + GC finishes; all threads in thread list are resumed 1547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - lock thread list 1548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - set child to THREAD_VMWAIT, and signal it to start 1549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - unlock thread list 1550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * o child resumes 1551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * o child changes state to THREAD_RUNNING 1552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The above shows the GC starting up during thread creation, but if 1554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it starts anywhere after VMThread.create() is called it will 1555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * produce the same series of events. 1556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Once the child is in the thread list, it will be suspended and 1558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * resumed like any other thread. In the above scenario the resume-all 1559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * code will try to resume the new thread, which was never actually 1560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspended, and try to decrement the child's thread suspend count to -1. 1561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We can catch this in the resume-all code. 1562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Bouncing back and forth between threads like this adds a small amount 1564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of scheduler overhead to thread startup. 1565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * One alternative to having the child wait for the parent would be 1567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to have the child inherit the parents' suspension count. This 1568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * would work for a GC, since we can safely assume that the parent 1569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread didn't cause it, but we must only do so if the parent suspension 1570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * was caused by a suspend-all. If the parent was being asked to 1571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspend singly by the debugger, the child should not inherit the value. 1572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We could also have a global "new thread suspend count" that gets 1574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * picked up by new threads before changing state to THREAD_RUNNING. 1575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This would be protected by the thread list lock and set by a 1576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspend-all. 1577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 1579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(self->status == THREAD_RUNNING); 1580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->status = THREAD_VMWAIT; 1581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (newThread->status != THREAD_STARTING) 1582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock); 1583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: adding to list\n", newThread->threadId); 1585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newThread->next = gDvm.threadList->next; 1586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (newThread->next != NULL) 1587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newThread->next->prev = newThread; 1588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newThread->prev = gDvm.threadList; 1589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.threadList->next = newThread; 1590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon)) 1592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.nonDaemonThreadCount++; // guarded by thread list lock 1593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* change status back to RUNNING, self-suspending if necessary */ 1597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmChangeStatus(self, THREAD_RUNNING); 1598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Tell the new thread to start. 1601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We must hold the thread list lock before messing with another thread. 1603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * In the general case we would also need to verify that newThread was 1604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * still in the thread list, but in our case the thread has not started 1605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * executing user code and therefore has not had a chance to exit. 1606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We move it to VMWAIT, and it then shifts itself to RUNNING, which 1608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * comes with a suspend-pending check. 1609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 1611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(newThread->status == THREAD_STARTING); 1613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newThread->status = THREAD_VMWAIT; 1614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_broadcast(&gDvm.threadStartCond); 1615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseTrackedAlloc(vmThreadObj, NULL); 1619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 1620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfail: 1622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project freeThread(newThread); 1623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseTrackedAlloc(vmThreadObj, NULL); 1624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * pthread entry function for threads started from interpreted code. 1629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* interpThreadStart(void* arg) 1631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = (Thread*) arg; 1633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project char *threadName = dvmGetThreadName(self); 1635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project setThreadName(threadName); 1636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(threadName); 1637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Finish initializing the Thread struct. 1640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1641fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmLockThreadList(self); 1642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project prepareThread(self); 1643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: created from interp\n", self->threadId); 1645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Change our status and wake our parent, who will add us to the 1648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread list and advance our state to VMWAIT. 1649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->status = THREAD_STARTING; 1651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_broadcast(&gDvm.threadStartCond); 1652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wait until the parent says we can go. Assuming there wasn't a 1655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspend pending, this will happen immediately. When it completes, 1656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we're full-fledged citizens of the VM. 1657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We have to use THREAD_VMWAIT here rather than THREAD_RUNNING 1659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * because the pthread_cond_wait below needs to reacquire a lock that 1660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspend-all is also interested in. If we get unlucky, the parent could 1661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * change us to THREAD_RUNNING, then a GC could start before we get 1662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * signaled, and suspend-all will grab the thread list lock and then 1663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * wait for us to suspend. We'll be in the tail end of pthread_cond_wait 1664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * trying to get the lock. 1665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (self->status != THREAD_VMWAIT) 1667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock); 1668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Add a JNI context. 1673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->jniEnv = dvmCreateJNIEnv(self); 1675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Change our state so the GC will wait for us from now on. If a GC is 1678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in progress this call will suspend us. 1679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmChangeStatus(self, THREAD_RUNNING); 1681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Notify the debugger & DDM. The debugger notification may cause 1684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * us to suspend ourselves (and others). 1685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.debuggerConnected) 1687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDbgPostThreadStart(self); 1688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Set the system thread priority according to the Thread object's 1691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * priority level. We don't usually need to do this, because both the 1692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Thread object and system thread priorities inherit from parents. The 1693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * tricky case is when somebody creates a Thread object, calls 1694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * setPriority(), and then starts the thread. We could manage this with 1695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * a "needs priority update" flag to avoid the redundant call. 1696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 16974879df9b4e10b3a77d7ad7c945cae0b15b8e8b31Andy McFadden int priority = dvmGetFieldInt(self->threadObj, 1698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_priority); 1699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmChangeThreadPriority(self, priority); 1700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Execute the "run" method. 1703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * At this point our stack is empty, so somebody who comes looking for 1705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * stack traces right now won't have much to look at. This is normal. 1706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* run = self->threadObj->clazz->vtable[gDvm.voffJavaLangThread_run]; 1708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project JValue unused; 1709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("threadid=%d: calling run()\n", self->threadId); 1711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(strcmp(run->name, "run") == 0); 1712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCallMethod(self, run, self->threadObj, &unused); 1713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("threadid=%d: exiting\n", self->threadId); 1714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Remove the thread from various lists, report its death, and free 1717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * its resources. 1718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDetachCurrentThread(); 1720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 1722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The current thread is exiting with an uncaught exception. The 1726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Java programming language allows the application to provide a 1727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread-exit-uncaught-exception handler for the VM, for a specific 1728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Thread, and for all threads in a ThreadGroup. 1729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Version 1.5 added the per-thread handler. We need to call 1731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "uncaughtException" in the handler object, which is either the 1732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ThreadGroup object or the Thread-specific handler. 1733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void threadExitUncaughtException(Thread* self, Object* group) 1735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* exception; 1737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* handlerObj; 1738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* uncaughtHandler = NULL; 1739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project InstField* threadHandler; 1740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("threadid=%d: thread exiting with uncaught exception (group=%p)\n", 1742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, group); 1743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(group != NULL); 1744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get a pointer to the exception, then clear out the one in the 1747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread. We don't want to have it set when executing interpreted code. 1748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project exception = dvmGetException(self); 1750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAddTrackedAlloc(exception, self); 1751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmClearException(self); 1752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get the Thread's "uncaughtHandler" object. Use it if non-NULL; 1755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * else use "group" (which is an instance of UncaughtExceptionHandler). 1756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project threadHandler = dvmFindInstanceField(gDvm.classJavaLangThread, 1758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "uncaughtHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;"); 1759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (threadHandler == NULL) { 1760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("WARNING: no 'uncaughtHandler' field in java/lang/Thread\n"); 1761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 1762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project handlerObj = dvmGetFieldObject(self->threadObj, threadHandler->byteOffset); 1764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (handlerObj == NULL) 1765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project handlerObj = group; 1766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find the "uncaughtHandler" field in this object. 1769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project uncaughtHandler = dvmFindVirtualMethodHierByDescriptor(handlerObj->clazz, 1771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V"); 1772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (uncaughtHandler != NULL) { 1774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //LOGI("+++ calling %s.uncaughtException\n", 1775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // handlerObj->clazz->descriptor); 1776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project JValue unused; 1777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCallMethod(self, uncaughtHandler, handlerObj, &unused, 1778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadObj, exception); 1779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 1780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* restore it and dump a stack trace */ 1781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("WARNING: no 'uncaughtException' method in class %s\n", 1782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project handlerObj->clazz->descriptor); 1783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetException(self, exception); 1784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLogExceptionStackTrace(); 1785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail: 178846cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee#if defined(WITH_JIT) 178946cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee /* Remove this thread's suspendCount from global suspendCount sum */ 179046cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee lockThreadSuspendCount(); 179146cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmAddToThreadSuspendCount(&self->suspendCount, -self->suspendCount); 179246cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee unlockThreadSuspendCount(); 179346cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee#endif 1794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseTrackedAlloc(exception, self); 1795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create an internal VM thread, for things like JDWP and finalizers. 1800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The easiest way to do this is create a new thread and then use the 1802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * JNI AttachCurrentThread implementation. 1803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This does not return until after the new thread has begun executing. 1805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmCreateInternalThread(pthread_t* pHandle, const char* name, 1807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project InternalThreadStart func, void* funcArg) 1808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project InternalStartArgs* pArgs; 1810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* systemGroup; 1811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_attr_t threadAttr; 1812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project volatile Thread* newThread = NULL; 1813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project volatile int createStatus = 0; 1814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project systemGroup = dvmGetSystemThreadGroup(); 1816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (systemGroup == NULL) 1817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs = (InternalStartArgs*) malloc(sizeof(*pArgs)); 1820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs->func = func; 1821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs->funcArg = funcArg; 1822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs->name = strdup(name); // storage will be owned by new thread 1823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs->group = systemGroup; 1824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs->isDaemon = true; 1825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs->pThread = &newThread; 1826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs->pCreateStatus = &createStatus; 1827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_attr_init(&threadAttr); 1829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED); 1830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pthread_create(pHandle, &threadAttr, internalThreadStart, 1832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArgs) != 0) 1833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 1834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("internal thread creation failed\n"); 1835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(pArgs->name); 1836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(pArgs); 1837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wait for the child to start. This gives us an opportunity to make 1842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * sure that the thread started correctly, and allows our caller to 1843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * assume that the thread has started running. 1844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Because we aren't holding a lock across the thread creation, it's 1846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * possible that the child will already have completed its 1847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * initialization. Because the child only adjusts "createStatus" while 1848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * holding the thread list lock, the initial condition on the "while" 1849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * loop will correctly avoid the wait if this occurs. 1850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It's also possible that we'll have to wait for the thread to finish 1852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * being created, and as part of allocating a Thread object it might 1853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * need to initiate a GC. We switch to VMWAIT while we pause. 1854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = dvmThreadSelf(); 18565617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT); 1857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 1858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (createStatus == 0) 1859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock); 1860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (newThread == NULL) { 1862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("internal thread create failed (createStatus=%d)\n", createStatus); 1863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(createStatus < 0); 1864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* don't free pArgs -- if pthread_create succeeded, child owns it */ 1865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmChangeStatus(self, oldStatus); 1867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 1868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* thread could be in any state now (except early init states) */ 1871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //assert(newThread->status == THREAD_RUNNING); 1872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmChangeStatus(self, oldStatus); 1875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 1877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * pthread entry function for internally-created threads. 1881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We are expected to free "arg" and its contents. If we're a daemon 1883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread, and we get cancelled abruptly when the VM shuts down, the 1884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * storage won't be freed. If this becomes a concern we can make a copy 1885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * on the stack. 1886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* internalThreadStart(void* arg) 1888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project InternalStartArgs* pArgs = (InternalStartArgs*) arg; 1890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project JavaVMAttachArgs jniArgs; 1891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project jniArgs.version = JNI_VERSION_1_2; 1893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project jniArgs.name = pArgs->name; 1894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project jniArgs.group = pArgs->group; 1895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project setThreadName(pArgs->name); 1897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* use local jniArgs as stack top */ 1899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmAttachCurrentThread(&jniArgs, pArgs->isDaemon)) { 1900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Tell the parent of our success. 1902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * threadListLock is the mutex for threadStartCond. 1904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(dvmThreadSelf()); 1906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *pArgs->pCreateStatus = 1; 1907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *pArgs->pThread = dvmThreadSelf(); 1908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_broadcast(&gDvm.threadStartCond); 1909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: internal '%s'\n", 1912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmThreadSelf()->threadId, pArgs->name); 1913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* execute */ 1915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (*pArgs->func)(pArgs->funcArg); 1916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* detach ourselves */ 1918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDetachCurrentThread(); 1919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 1920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Tell the parent of our failure. We don't have a Thread struct, 1922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * so we can't be suspended, so we don't need to enter a critical 1923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * section. 1924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(dvmThreadSelf()); 1926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *pArgs->pCreateStatus = -1; 1927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(*pArgs->pThread == NULL); 1928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pthread_cond_broadcast(&gDvm.threadStartCond); 1929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(*pArgs->pThread == NULL); 1932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(pArgs->name); 1935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(pArgs); 1936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 1937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 1938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 1940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Attach the current thread to the VM. 1941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Used for internally-created threads and JNI's AttachCurrentThread. 1943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon) 1945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = NULL; 1947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* threadObj = NULL; 1948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* vmThreadObj = NULL; 1949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StringObject* threadNameStr = NULL; 1950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* init; 1951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project bool ok, ret; 1952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1953e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden /* allocate thread struct, and establish a basic sense of self */ 1954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self = allocThread(gDvm.stackSize); 1955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self == NULL) 1956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project setThreadSelf(self); 1958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1960e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * Finish our thread prep. We need to do this before adding ourselves 1961e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * to the thread list or invoking any interpreted code. prepareThread() 1962e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * requires that we hold the thread list lock. 1963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 1965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ok = prepareThread(self); 1966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 1967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!ok) 1968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->jniEnv = dvmCreateJNIEnv(self); 1971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self->jniEnv == NULL) 1972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create a "fake" JNI frame at the top of the main thread interp stack. 1976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It isn't really necessary for the internal threads, but it gives 1977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the debugger something to show. It is essential for the JNI-attached 1978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * threads. 1979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!createFakeRunFrame(self)) 1981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail; 1982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1984e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * The native side of the thread is ready; add it to the list. Once 1985e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * it's on the list the thread is visible to the JDWP code and the GC. 1986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: adding to list (attached)\n", self->threadId); 1988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 1990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->next = gDvm.threadList->next; 1992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self->next != NULL) 1993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->next->prev = self; 1994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->prev = gDvm.threadList; 1995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.threadList->next = self; 1996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!isDaemon) 1997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.nonDaemonThreadCount++; 1998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 2000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2002e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * Switch state from initializing to running. 2003e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * 2004e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * It's possible that a GC began right before we added ourselves 2005e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * to the thread list, and is still going. That means our thread 2006e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * suspend count won't reflect the fact that we should be suspended. 2007e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * To deal with this, we transition to VMWAIT, pulse the heap lock, 2008e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * and then advance to RUNNING. That will ensure that we stall until 2009e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * the GC completes. 2010e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * 2011e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * Once we're in RUNNING, we're like any other thread in the VM (except 2012e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * for the lack of an initialized threadObj). We're then free to 2013e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * allocate and initialize objects. 2014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2015e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden assert(self->status == THREAD_INITIALIZING); 2016e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmChangeStatus(self, THREAD_VMWAIT); 2017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockMutex(&gDvm.gcHeapLock); 2018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockMutex(&gDvm.gcHeapLock); 2019e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmChangeStatus(self, THREAD_RUNNING); 2020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2022e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * Create Thread and VMThread objects. 2023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2024e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT); 2025e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT); 2026e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden if (threadObj == NULL || vmThreadObj == NULL) 2027e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden goto fail_unlink; 2028e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden 2029e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden /* 2030e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * This makes threadObj visible to the GC. We still have it in the 2031e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * tracked allocation table, so it can't move around on us. 2032e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden */ 2033e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden self->threadObj = threadObj; 2034e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)self); 2035e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden 2036e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden /* 2037e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * Create a string for the thread name. 2038e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden */ 2039e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden if (pArgs->name != NULL) { 204081f3ebe03cd33c9003641084bece0604ee68bf88Barry Hayes threadNameStr = dvmCreateStringFromCstr(pArgs->name); 2041e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden if (threadNameStr == NULL) { 2042e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden assert(dvmCheckException(dvmThreadSelf())); 2043e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden goto fail_unlink; 2044e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden } 2045e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden } 2046e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden 2047e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangThread, "<init>", 2048e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); 2049e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden if (init == NULL) { 2050e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden assert(dvmCheckException(self)); 2051e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden goto fail_unlink; 2052e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden } 2053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Now we're ready to run some interpreted code. 2056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to construct the Thread object and set the VMThread field. 2058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Setting VMThread tells interpreted code that we're alive. 2059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Call the (group, name, priority, daemon) constructor on the Thread. 2061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This sets the thread's name and adds it to the specified group, and 2062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * provides values for priority and daemon (which are normally inherited 2063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * from the current thread). 2064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project JValue unused; 2066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCallMethod(self, init, threadObj, &unused, (Object*)pArgs->group, 2067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project threadNameStr, getThreadPriorityFromSystem(), isDaemon); 2068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmCheckException(self)) { 2069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("exception thrown while constructing attached thread object\n"); 2070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto fail_unlink; 2071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Set the VMThread field, which tells interpreted code that we're alive. 2075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The risk of a thread start collision here is very low; somebody 2077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * would have to be deliberately polling the ThreadGroup list and 2078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * trying to start threads against anything it sees, which would 2079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * generally cause problems for all thread creation. However, for 2080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * correctness we test "vmThread" before setting it. 2081e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * 2082e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * TODO: this still has a race, it's just smaller. Not sure this is 2083e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * worth putting effort into fixing. Need to hold a lock while 2084e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * fiddling with the field, or maybe initialize the Thread object in a 2085e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * way that ensures another thread can't call start() on it. 2086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread) != NULL) { 2088e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden LOGW("WOW: thread start hijack\n"); 2089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmThrowException("Ljava/lang/IllegalThreadStateException;", 2090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "thread has already been started"); 2091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* We don't want to free anything associated with the thread 2092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * because someone is obviously interested in it. Just let 2093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it go and hope it will clean itself up when its finished. 2094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This case should never happen anyway. 2095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Since we're letting it live, we need to finish setting it up. 2097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We just have to let the caller know that the intended operation 2098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * has failed. 2099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * [ This seems strange -- stepping on the vmThread object that's 2101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * already present seems like a bad idea. TODO: figure this out. ] 2102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ret = false; 2104e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden } else { 2105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ret = true; 2106e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden } 2107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj); 2108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2109e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden /* we can now safely un-pin these */ 2110e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmReleaseTrackedAlloc(threadObj, self); 2111e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmReleaseTrackedAlloc(vmThreadObj, self); 2112e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmReleaseTrackedAlloc((Object*)threadNameStr, self); 2113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: attached from native, name=%s\n", 2115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, pArgs->name); 2116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* tell the debugger & DDM */ 2118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.debuggerConnected) 2119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDbgPostThreadStart(self); 2120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return ret; 2122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfail_unlink: 2124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 2125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlinkThread(self); 2126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!isDaemon) 2127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.nonDaemonThreadCount--; 2128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 2129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* fall through to "fail" */ 2130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfail: 2131e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmReleaseTrackedAlloc(threadObj, self); 2132e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmReleaseTrackedAlloc(vmThreadObj, self); 2133e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmReleaseTrackedAlloc((Object*)threadNameStr, self); 2134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self != NULL) { 2135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self->jniEnv != NULL) { 2136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDestroyJNIEnv(self->jniEnv); 2137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->jniEnv = NULL; 2138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project freeThread(self); 2140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project setThreadSelf(NULL); 2142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 2143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Detach the thread from the various data structures, notify other threads 2147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * that are waiting to "join" it, and free up all heap-allocated storage. 2148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Used for all threads. 2150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * When we get here the interpreted stack should be empty. The JNI 1.6 spec 2152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * requires us to enforce this for the DetachCurrentThread call, probably 2153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * because it also says that DetachCurrentThread causes all monitors 2154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * associated with the thread to be released. (Because the stack is empty, 2155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we only have to worry about explicit JNI calls to MonitorEnter.) 2156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * THOUGHT: 2158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We might want to avoid freeing our internal Thread structure until the 2159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * associated Thread/VMThread objects get GCed. Our Thread is impossible to 2160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * get to once the thread shuts down, but there is a small possibility of 2161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * an operation starting in another thread before this thread halts, and 2162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * finishing much later (perhaps the thread got stalled by a weird OS bug). 2163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We don't want something like Thread.isInterrupted() crawling through 2164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * freed storage. Can do with a Thread finalizer, or by creating a 2165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * dedicated ThreadObject class for java/lang/Thread and moving all of our 2166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * state into that. 2167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmDetachCurrentThread(void) 2169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = dvmThreadSelf(); 2171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* vmThread; 2172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* group; 2173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Make sure we're not detaching a thread that's still running. (This 2176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * could happen with an explicit JNI detach call.) 2177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * A thread created by interpreted code will finish with a depth of 2179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * zero, while a JNI-attached thread will have the synthetic "stack 2180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * starter" native method at the top. 2181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int curDepth = dvmComputeExactFrameDepth(self->curFrame); 2183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (curDepth != 0) { 2184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project bool topIsNative = false; 2185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (curDepth == 1) { 2187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* not expecting a lingering break frame; just look at curFrame */ 2188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(!dvmIsBreakFrame(self->curFrame)); 2189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StackSaveArea* ssa = SAVEAREA_FROM_FP(self->curFrame); 2190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmIsNativeMethod(ssa->method)) 2191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project topIsNative = true; 2192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!topIsNative) { 2195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("ERROR: detaching thread with interp frames (count=%d)\n", 2196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project curDepth); 2197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpThread(self, false); 2198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAbort(); 2199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project group = dvmGetFieldObject(self->threadObj, gDvm.offJavaLangThread_group); 2203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: detach (group=%p)\n", self->threadId, group); 2204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release any held monitors. Since there are no interpreted stack 2207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * frames, the only thing left are the monitors held by JNI MonitorEnter 2208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * calls. 2209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseJniMonitors(self); 2211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Do some thread-exit uncaught exception processing if necessary. 2214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (dvmCheckException(self)) 2216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project threadExitUncaughtException(self, group); 2217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Remove the thread from the thread group. 2220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (group != NULL) { 2222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Method* removeThread = 2223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project group->clazz->vtable[gDvm.voffJavaLangThreadGroup_removeThread]; 2224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project JValue unused; 2225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCallMethod(self, removeThread, group, &unused, self->threadObj); 2226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Clear the vmThread reference in the Thread object. Interpreted code 2230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * will now see that this Thread is not running. As this may be the 2231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * only reference to the VMThread object that the VM knows about, we 2232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * have to create an internal reference to it first. 2233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project vmThread = dvmGetFieldObject(self->threadObj, 2235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_vmThread); 2236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAddTrackedAlloc(vmThread, self); 2237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldObject(self->threadObj, gDvm.offJavaLangThread_vmThread, NULL); 2238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* clear out our struct Thread pointer, since it's going away */ 2240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmSetFieldObject(vmThread, gDvm.offJavaLangVMThread_vmData, NULL); 2241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Tell the debugger & DDM. This may cause the current thread or all 2244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * threads to suspend. 2245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The JDWP spec is somewhat vague about when this happens, other than 2247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * that it's issued by the dying thread, which may still appear in 2248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * an "all threads" listing. 2249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.debuggerConnected) 2251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDbgPostThreadDeath(self); 2252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Thread.join() is implemented as an Object.wait() on the VMThread 2255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * object. Signal anyone who is waiting. 2256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockObject(self, vmThread); 2258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmObjectNotifyAll(self, vmThread); 2259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockObject(self, vmThread); 2260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmReleaseTrackedAlloc(vmThread, self); 2262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project vmThread = NULL; 2263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We're done manipulating objects, so it's okay if the GC runs in 2266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * parallel with us from here out. It's important to do this if 2267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * profiling is enabled, since we can wait indefinitely. 2268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 22693469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden android_atomic_release_store(THREAD_VMWAIT, &self->status); 2270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If we're doing method trace profiling, we don't want threads to exit, 2273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * because if they do we'll end up reusing thread IDs. This complicates 2274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * analysis and makes it impossible to have reasonable output in the 2275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "threads" section of the "key" file. 2276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to do this after Thread.join() completes, or other threads 2278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * could get wedged. Since self->threadObj is still valid, the Thread 2279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * object will not get GCed even though we're no longer in the ThreadGroup 2280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * list (which is important since the profiling thread needs to get 2281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the thread's name). 2282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project MethodTraceState* traceState = &gDvm.methodTrace; 2284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockMutex(&traceState->startStopLock); 2286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (traceState->traceEnabled) { 2287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGI("threadid=%d: waiting for method trace to finish\n", 2288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId); 2289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (traceState->traceEnabled) { 2290fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmWaitCond(&traceState->threadExitCond, 2291fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom &traceState->startStopLock); 2292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockMutex(&traceState->startStopLock); 2295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 2297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Lose the JNI context. 2300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDestroyJNIEnv(self->jniEnv); 2302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->jniEnv = NULL; 2303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->status = THREAD_ZOMBIE; 2305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Remove ourselves from the internal thread list. 2308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlinkThread(self); 2310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If we're the last one standing, signal anybody waiting in 2313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * DestroyJavaVM that it's okay to exit. 2314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!dvmGetFieldBoolean(self->threadObj, gDvm.offJavaLangThread_daemon)) { 2316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.nonDaemonThreadCount--; // guarded by thread list lock 2317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (gDvm.nonDaemonThreadCount == 0) { 2319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int cc; 2320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("threadid=%d: last non-daemon thread\n", self->threadId); 2322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //dvmDumpAllThreads(false); 2323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // cond var guarded by threadListLock, which we already hold 2324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project cc = pthread_cond_signal(&gDvm.vmExitCond); 2325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(cc == 0); 2326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("threadid=%d: bye!\n", self->threadId); 2330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project releaseThreadId(self); 2331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 2332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project setThreadSelf(NULL); 23349dc72a3c54af7201b6b85d96dba23a5f85309d9bBob Lee 2335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project freeThread(self); 2336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Suspend a single thread. Do not use to suspend yourself. 2341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is used primarily for debugger/DDMS activity. Does not return 2343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * until the thread has suspended or is in a "safe" state (e.g. executing 2344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * native code outside the VM). 2345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The thread list lock should be held before calling here -- it's not 2347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * entirely safe to hang on to a Thread* from another thread otherwise. 2348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (We'd need to grab it here anyway to avoid clashing with a suspend-all.) 2349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmSuspendThread(Thread* thread) 2351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread != NULL); 2353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread != dvmThreadSelf()); 2354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //assert(thread->handle != dvmJdwpGetDebugThread(gDvm.jdwpState)); 2355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 235746cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmAddToThreadSuspendCount(&thread->suspendCount, 1); 2358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->dbgSuspendCount++; 2359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: suspend++, now=%d\n", 2361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadId, thread->suspendCount); 2362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project waitForThreadSuspend(dvmThreadSelf(), thread); 2365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Reduce the suspend count of a thread. If it hits zero, tell it to 2369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * resume. 2370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Used primarily for debugger/DDMS activity. The thread in question 2372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * might have been suspended singly or as part of a suspend-all operation. 2373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The thread list lock should be held before calling here -- it's not 2375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * entirely safe to hang on to a Thread* from another thread otherwise. 2376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (We'd need to grab it here anyway to avoid clashing with a suspend-all.) 2377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmResumeThread(Thread* thread) 2379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread != NULL); 2381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread != dvmThreadSelf()); 2382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //assert(thread->handle != dvmJdwpGetDebugThread(gDvm.jdwpState)); 2383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 2385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->suspendCount > 0) { 238646cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmAddToThreadSuspendCount(&thread->suspendCount, -1); 2387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->dbgSuspendCount--; 2388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 2389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: suspendCount already zero\n", 2390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadId); 2391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: suspend--, now=%d\n", 2394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadId, thread->suspendCount); 2395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->suspendCount == 0) { 2397fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmBroadcastCond(&gDvm.threadSuspendCountCond); 2398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Suspend yourself, as a result of debugger activity. 2405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmSuspendSelf(bool jdwpActivity) 2407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = dvmThreadSelf(); 2409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2410b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden /* debugger thread must not suspend itself due to debugger activity! */ 2411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(gDvm.jdwpState != NULL); 2412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self->handle == dvmJdwpGetDebugThread(gDvm.jdwpState)) { 2413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(false); 2414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 2415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Collisions with other suspends aren't really interesting. We want 2419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to ensure that we're the only one fiddling with the suspend count 2420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * though. 2421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 242346cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmAddToThreadSuspendCount(&self->suspendCount, 1); 2424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->dbgSuspendCount++; 2425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Suspend ourselves. 2428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(self->suspendCount > 0); 2430b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden self->status = THREAD_SUSPENDED; 2431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: self-suspending (dbg)\n", self->threadId); 2432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Tell JDWP that we've completed suspension. The JDWP thread can't 2435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * tell us to resume before we're fully asleep because we hold the 2436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspend count lock. 2437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If we got here via waitForDebugger(), don't do this part. 2439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (jdwpActivity) { 2441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //LOGI("threadid=%d: clearing wait-for-event (my handle=%08x)\n", 2442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // self->threadId, (int) self->handle); 2443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmJdwpClearWaitForEventThread(gDvm.jdwpState); 2444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (self->suspendCount != 0) { 2447fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmWaitCond(&gDvm.threadSuspendCountCond, 2448fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom &gDvm.threadSuspendCountLock); 2449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self->suspendCount != 0) { 245099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 245199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * The condition was signaled but we're still suspended. This 245299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * can happen if the debugger lets go while a SIGQUIT thread 245399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * dump event is pending (assuming SignalCatcher was resumed for 245499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * just long enough to try to grab the thread-suspend lock). 245599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 2456b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden LOGD("threadid=%d: still suspended after undo (sc=%d dc=%d)\n", 2457b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden self->threadId, self->suspendCount, self->dbgSuspendCount); 2458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(self->suspendCount == 0 && self->dbgSuspendCount == 0); 2461b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden self->status = THREAD_RUNNING; 2462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: self-reviving (dbg), status=%d\n", 2463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, self->status); 2464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_GLIBC 2470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project# define NUM_FRAMES 20 2471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project# include <execinfo.h> 2472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * glibc-only stack dump function. Requires link with "--export-dynamic". 2474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * TODO: move this into libs/cutils and make it work for all platforms. 2476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void printBackTrace(void) 2478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project void* array[NUM_FRAMES]; 2480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project size_t size; 2481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project char** strings; 2482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project size_t i; 2483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project size = backtrace(array, NUM_FRAMES); 2485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project strings = backtrace_symbols(array, size); 2486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("Obtained %zd stack frames.\n", size); 2488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (i = 0; i < size; i++) 2490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("%s\n", strings[i]); 2491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(strings); 2493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 2495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void printBackTrace(void) {} 2496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 2497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Dump the state of the current thread and that of another thread that 2500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we think is wedged. 2501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void dumpWedgedThread(Thread* thread) 2503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpThread(dvmThreadSelf(), false); 2505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project printBackTrace(); 2506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // dumping a running thread is risky, but could be useful 2508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpThread(thread, true); 2509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // stop now and get a core dump 2511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //abort(); 2512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2514d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden/* 2515d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * If the thread is running at below-normal priority, temporarily elevate 2516d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * it to "normal". 2517d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * 2518d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * Returns zero if no changes were made. Otherwise, returns bit flags 2519d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * indicating what was changed, storing the previous values in the 2520d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * provided locations. 2521d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden */ 25222b94b30abe21de859b00965d00cc7d42ee436943Andy McFaddenint dvmRaiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio, 2523d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden SchedPolicy* pSavedThreadPolicy) 2524d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden{ 2525d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden errno = 0; 2526d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden *pSavedThreadPrio = getpriority(PRIO_PROCESS, thread->systemTid); 2527d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (errno != 0) { 2528d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGW("Unable to get priority for threadid=%d sysTid=%d\n", 2529d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->threadId, thread->systemTid); 2530d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden return 0; 2531d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2532d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (get_sched_policy(thread->systemTid, pSavedThreadPolicy) != 0) { 2533d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGW("Unable to get policy for threadid=%d sysTid=%d\n", 2534d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->threadId, thread->systemTid); 2535d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden return 0; 2536d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2537d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden 2538d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden int changeFlags = 0; 2539d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden 2540d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden /* 2541d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * Change the priority if we're in the background group. 2542d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden */ 2543d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (*pSavedThreadPolicy == SP_BACKGROUND) { 2544d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (set_sched_policy(thread->systemTid, SP_FOREGROUND) != 0) { 2545d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGW("Couldn't set fg policy on tid %d\n", thread->systemTid); 2546d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } else { 2547d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden changeFlags |= kChangedPolicy; 2548d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGD("Temporarily moving tid %d to fg (was %d)\n", 2549d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->systemTid, *pSavedThreadPolicy); 2550d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2551d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2552d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden 2553d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden /* 2554d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * getpriority() returns the "nice" value, so larger numbers indicate 2555d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * lower priority, with 0 being normal. 2556d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden */ 2557d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (*pSavedThreadPrio > 0) { 2558d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden const int kHigher = 0; 2559d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (setpriority(PRIO_PROCESS, thread->systemTid, kHigher) != 0) { 2560d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGW("Couldn't raise priority on tid %d to %d\n", 2561d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->systemTid, kHigher); 2562d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } else { 2563d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden changeFlags |= kChangedPriority; 2564d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGD("Temporarily raised priority on tid %d (%d -> %d)\n", 2565d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->systemTid, *pSavedThreadPrio, kHigher); 2566d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2567d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2568d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden 2569d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden return changeFlags; 2570d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden} 2571d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden 2572d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden/* 2573d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden * Reset the priority values for the thread in question. 2574d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden */ 25752b94b30abe21de859b00965d00cc7d42ee436943Andy McFaddenvoid dvmResetThreadPriority(Thread* thread, int changeFlags, 2576d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden int savedThreadPrio, SchedPolicy savedThreadPolicy) 2577d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden{ 2578d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if ((changeFlags & kChangedPolicy) != 0) { 2579d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (set_sched_policy(thread->systemTid, savedThreadPolicy) != 0) { 2580d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGW("NOTE: couldn't reset tid %d to (%d)\n", 2581d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->systemTid, savedThreadPolicy); 2582d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } else { 2583d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGD("Restored policy of %d to %d\n", 2584d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->systemTid, savedThreadPolicy); 2585d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2586d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2587d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden 2588d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if ((changeFlags & kChangedPriority) != 0) { 2589d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (setpriority(PRIO_PROCESS, thread->systemTid, savedThreadPrio) != 0) 2590d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden { 2591d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGW("NOTE: couldn't reset priority on thread %d to %d\n", 2592d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->systemTid, savedThreadPrio); 2593d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } else { 2594d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGD("Restored priority on %d to %d\n", 2595d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->systemTid, savedThreadPrio); 2596d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2597d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 2598d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden} 2599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wait for another thread to see the pending suspension and stop running. 2602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It can either suspend itself or go into a non-running state such as 2603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * VMWAIT or NATIVE in which it cannot interact with the GC. 2604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If we're running at a higher priority, sched_yield() may not do anything, 2606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * so we need to sleep for "long enough" to guarantee that the other 2607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread has a chance to finish what it's doing. Sleeping for too short 2608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * a period (e.g. less than the resolution of the sleep clock) might cause 2609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the scheduler to return immediately, so we want to start with a 2610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "reasonable" value and expand. 2611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This does not return until the other thread has stopped running. 2613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Eventually we time out and the VM aborts. 2614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This does not try to detect the situation where two threads are 2616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * waiting for each other to suspend. In normal use this is part of a 2617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspend-all, which implies that the suspend-all lock is held, or as 2618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * part of a debugger action in which the JDWP thread is always the one 2619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * doing the suspending. (We may need to re-evaluate this now that 2620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * getThreadStackTrace is implemented as suspend-snapshot-resume.) 2621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * TODO: track basic stats about time required to suspend VM. 2623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 262446cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee#define FIRST_SLEEP (250*1000) /* 0.25s */ 262546cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee#define MORE_SLEEP (750*1000) /* 0.75s */ 2626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void waitForThreadSuspend(Thread* self, Thread* thread) 2627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const int kMaxRetries = 10; 262946cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee int spinSleepTime = FIRST_SLEEP; 26302aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden bool complained = false; 2631d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden int priChangeFlags = 0; 26327ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden int savedThreadPrio = -500; 2633d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden SchedPolicy savedThreadPolicy = SP_FOREGROUND; 2634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int sleepIter = 0; 2636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int retryCount = 0; 2637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project u8 startWhen = 0; // init req'd to placate gcc 26387ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden u8 firstStartWhen = 0; 2639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2640b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden while (thread->status == THREAD_RUNNING) { 26417ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden if (sleepIter == 0) { // get current time on first iteration 2642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project startWhen = dvmGetRelativeTimeUsec(); 26437ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden if (firstStartWhen == 0) // first iteration of first attempt 26447ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden firstStartWhen = startWhen; 26457ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden 26467ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden /* 26477ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden * After waiting for a bit, check to see if the target thread is 26487ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden * running at a reduced priority. If so, bump it up temporarily 26497ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden * to give it more CPU time. 26507ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden */ 26517ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden if (retryCount == 2) { 26527ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden assert(thread->systemTid != 0); 26532b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden priChangeFlags = dvmRaiseThreadPriorityIfNeeded(thread, 2654d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden &savedThreadPrio, &savedThreadPolicy); 26557ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden } 26567ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden } 2657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 265846cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee#if defined (WITH_JIT) 265946cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee /* 26606999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * If we're still waiting after the first timeout, unchain all 26616999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * translations iff: 26626999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * 1) There are new chains formed since the last unchain 26636999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * 2) The top VM frame of the running thread is running JIT'ed code 266446cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee */ 26656999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng if (gDvmJit.pJitEntryTable && retryCount > 0 && 26666999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng gDvmJit.hasNewChain && thread->inJitCodeCache) { 2667d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGD("JIT unchain all for threadid=%d", thread->threadId); 266846cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmJitUnchainAll(); 266946cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee } 267046cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee#endif 267146cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee 26727ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden /* 26731ede83b7ab24a7e14f37e330eb841a075525c3e9Andy McFadden * Sleep briefly. The iterative sleep call returns false if we've 26741ede83b7ab24a7e14f37e330eb841a075525c3e9Andy McFadden * exceeded the total time limit for this round of sleeping. 26757ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden */ 267646cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee if (!dvmIterativeSleep(sleepIter++, spinSleepTime, startWhen)) { 26771ede83b7ab24a7e14f37e330eb841a075525c3e9Andy McFadden if (spinSleepTime != FIRST_SLEEP) { 2678d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden LOGW("threadid=%d: spin on suspend #%d threadid=%d (pcf=%d)\n", 26791ede83b7ab24a7e14f37e330eb841a075525c3e9Andy McFadden self->threadId, retryCount, 2680d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden thread->threadId, priChangeFlags); 2681d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (retryCount > 1) { 2682d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden /* stack trace logging is slow; skip on first iter */ 2683d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden dumpWedgedThread(thread); 2684d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden } 26851ede83b7ab24a7e14f37e330eb841a075525c3e9Andy McFadden complained = true; 26861ede83b7ab24a7e14f37e330eb841a075525c3e9Andy McFadden } 2687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // keep going; could be slow due to valgrind 2689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sleepIter = 0; 269046cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee spinSleepTime = MORE_SLEEP; 2691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (retryCount++ == kMaxRetries) { 2693384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden LOGE("Fatal spin-on-suspend, dumping threads\n"); 2694384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden dvmDumpAllThreads(false); 2695384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden 2696384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden /* log this after -- long traces will scroll off log */ 2697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("threadid=%d: stuck on threadid=%d, giving up\n", 2698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, thread->threadId); 2699384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden 2700384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden /* try to get a debuggerd dump from the spinning thread */ 2701384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden dvmNukeThread(thread); 2702384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden /* abort the VM */ 2703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmAbort(); 2704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 27072aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden 27082aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden if (complained) { 27097ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden LOGW("threadid=%d: spin on suspend resolved in %lld msec\n", 27107ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden self->threadId, 27117ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden (dvmGetRelativeTimeUsec() - firstStartWhen) / 1000); 27122aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden //dvmDumpThread(thread, false); /* suspended, so dump is safe */ 27132aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden } 2714d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden if (priChangeFlags != 0) { 27152b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden dvmResetThreadPriority(thread, priChangeFlags, savedThreadPrio, 2716d2afbcf85012252754d0e9c8b0084842fcab22faAndy McFadden savedThreadPolicy); 27177ce9bd763f29959ba3c448ba8584d6711c6a40bcAndy McFadden } 2718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Suspend all threads except the current one. This is used by the GC, 2722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the debugger, and by any thread that hits a "suspend all threads" 2723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * debugger event (e.g. breakpoint or exception). 2724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If thread N hits a "suspend all threads" breakpoint, we don't want it 2726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to suspend the JDWP thread. For the GC, we do, because the debugger can 2727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * create objects and even execute arbitrary code. The "why" argument 2728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * allows the caller to say why the suspension is taking place. 2729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This can be called when a global suspend has already happened, due to 2731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * various debugger gymnastics, so keeping an "everybody is suspended" flag 2732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * doesn't work. 2733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * DO NOT grab any locks before calling here. We grab & release the thread 2735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * lock and suspend lock here (and we're not using recursive threads), and 2736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we might have to self-suspend if somebody else beats us here. 2737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2738c650d2beb66896c0cf51f737d7a39476630dd142Andy McFadden * We know the current thread is in the thread list, because we attach the 2739c650d2beb66896c0cf51f737d7a39476630dd142Andy McFadden * thread before doing anything that could cause VM suspension (like object 2740c650d2beb66896c0cf51f737d7a39476630dd142Andy McFadden * allocation). 2741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmSuspendAllThreads(SuspendCause why) 2743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = dvmThreadSelf(); 2745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* thread; 2746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(why != 0); 2748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Start by grabbing the thread suspend lock. If we can't get it, most 2751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * likely somebody else is in the process of performing a suspend or 2752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * resume, so lockThreadSuspend() will cause us to self-suspend. 2753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We keep the lock until all other threads are suspended. 2755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspend("susp-all", why); 2757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: SuspendAll starting\n", self->threadId); 2759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is possible if the current thread was in VMWAIT mode when a 2762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspend-all happened, and then decided to do its own suspend-all. 2763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This can happen when a couple of threads have simultaneous events 2764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of interest to the debugger. 2765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //assert(self->suspendCount == 0); 2767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Increment everybody's suspend count (except our own). 2770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 2772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 2774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 2775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == self) 2776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 2777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* debugger events don't suspend JDWP thread */ 2779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if ((why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) && 2780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState)) 2781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 2782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 278346cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmAddToThreadSuspendCount(&thread->suspendCount, 1); 2784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) 2785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->dbgSuspendCount++; 2786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wait for everybody in THREAD_RUNNING state to stop. Other states 2791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * indicate the code is either running natively or sleeping quietly. 2792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Any attempt to transition back to THREAD_RUNNING will cause a check 2793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * for suspension, so it should be impossible for anything to execute 2794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * interpreted code or modify objects (assuming native code plays nicely). 2795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It's also okay if the thread transitions to a non-RUNNING state. 2797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Note we released the threadSuspendCountLock before getting here, 2799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * so if another thread is fiddling with its suspend count (perhaps 2800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * self-suspending for the debugger) it won't block while we're waiting 2801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in here. 2802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 2804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == self) 2805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 2806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* debugger events don't suspend JDWP thread */ 2808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if ((why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) && 2809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState)) 2810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 2811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* wait for the other thread to see the pending suspend */ 2813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project waitForThreadSuspend(self, thread); 2814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2815b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden LOG_THREAD("threadid=%d: threadid=%d status=%d sc=%d dc=%d\n", 2816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, 2817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadId, thread->status, thread->suspendCount, 2818b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden thread->dbgSuspendCount); 2819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 2822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspend(); 2823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: SuspendAll complete\n", self->threadId); 2825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Resume all threads that are currently suspended. 2829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The "why" must match with the previous suspend. 2831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmResumeAllThreads(SuspendCause why) 2833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = dvmThreadSelf(); 2835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* thread; 2836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int cc; 2837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspend("res-all", why); /* one suspend/resume at a time */ 2839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: ResumeAll starting\n", self->threadId); 2840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Decrement the suspend counts for all threads. No need for atomic 2843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * writes, since nobody should be moving until we decrement the count. 2844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We do need to hold the thread list because of JNI attaches. 2845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 2847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 2848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 2849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == self) 2850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 2851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* debugger events don't suspend JDWP thread */ 2853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if ((why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) && 2854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState)) 28552aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden { 2856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 28572aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden } 2858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->suspendCount > 0) { 286046cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmAddToThreadSuspendCount(&thread->suspendCount, -1); 2861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) 2862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->dbgSuspendCount--; 2863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 2864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: suspendCount already zero\n", 2865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->threadId); 2866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 2870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 28722aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * In some ways it makes sense to continue to hold the thread-suspend 28732aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * lock while we issue the wakeup broadcast. It allows us to complete 28742aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * one operation before moving on to the next, which simplifies the 28752aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * thread activity debug traces. 28762aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * 28772aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * This approach caused us some difficulty under Linux, because the 28782aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * condition variable broadcast not only made the threads runnable, 28792aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * but actually caused them to execute, and it was a while before 28802aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * the thread performing the wakeup had an opportunity to release the 28812aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * thread-suspend lock. 28822aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * 28832aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * This is a problem because, when a thread tries to acquire that 28842aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * lock, it times out after 3 seconds. If at some point the thread 28852aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * is told to suspend, the clock resets; but since the VM is still 28862aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * theoretically mid-resume, there's no suspend pending. If, for 28872aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * example, the GC was waking threads up while the SIGQUIT handler 28882aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * was trying to acquire the lock, we would occasionally time out on 28892aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * a busy system and SignalCatcher would abort. 28902aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * 28912aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * We now perform the unlock before the wakeup broadcast. The next 28922aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * suspend can't actually start until the broadcast completes and 28932aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * returns, because we're holding the thread-suspend-count lock, but the 28942aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * suspending thread is now able to make progress and we avoid the abort. 28952aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * 28962aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * (Technically there is a narrow window between when we release 28972aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * the thread-suspend lock and grab the thread-suspend-count lock. 28982aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * This could cause us to send a broadcast to threads with nonzero 28992aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * suspend counts, but this is expected and they'll all just fall 29002aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * right back to sleep. It's probably safe to grab the suspend-count 29012aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * lock before releasing thread-suspend, since we're still following 29022aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden * the correct order of acquisition, but it feels weird.) 29032aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden */ 29042aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden 29052aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden LOG_THREAD("threadid=%d: ResumeAll waking others\n", self->threadId); 29062aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden unlockThreadSuspend(); 29072aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden 29082aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden /* 2909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Broadcast a notification to all suspended threads, some or all of 2910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * which may choose to wake up. No need to wait for them. 2911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 2913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond); 2914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(cc == 0); 2915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: ResumeAll complete\n", self->threadId); 2918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Undo any debugger suspensions. This is called when the debugger 2922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * disconnects. 2923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmUndoDebuggerSuspensions(void) 2925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = dvmThreadSelf(); 2927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* thread; 2928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int cc; 2929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspend("undo", SUSPEND_FOR_DEBUG); 2931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: UndoDebuggerSusp starting\n", self->threadId); 2932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Decrement the suspend counts for all threads. No need for atomic 2935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * writes, since nobody should be moving until we decrement the count. 2936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We do need to hold the thread list because of JNI attaches. 2937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(self); 2939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 2940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 2941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == self) 2942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 2943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* debugger events don't suspend JDWP thread */ 2945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState)) { 2946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->dbgSuspendCount == 0); 2947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project continue; 2948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->suspendCount >= thread->dbgSuspendCount); 295146cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee dvmAddToThreadSuspendCount(&thread->suspendCount, 295246cd5b63c29d3284a9ff3e0d0711fb136f409313Bill Buzbee -thread->dbgSuspendCount); 2953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->dbgSuspendCount = 0; 2954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 2955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 2957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Broadcast a notification to all suspended threads, some or all of 2960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * which may choose to wake up. No need to wait for them. 2961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); 2963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond); 2964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(cc == 0); 2965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 2966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspend(); 2968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: UndoDebuggerSusp complete\n", self->threadId); 2970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 2971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Determine if a thread is suspended. 2974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * As with all operations on foreign threads, the caller should hold 2976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the thread list lock before calling. 29773469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * 29783469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * If the thread is suspending or waking, these fields could be changing 29793469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * out from under us (or the thread could change state right after we 29803469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * examine it), making this generally unreliable. This is chiefly 29813469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * intended for use by the debugger. 2982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 29833469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFaddenbool dvmIsSuspended(const Thread* thread) 2984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 2985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 2986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The thread could be: 2987b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * (1) Running happily. status is RUNNING, suspendCount is zero. 2988b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * Return "false". 2989b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * (2) Pending suspend. status is RUNNING, suspendCount is nonzero. 2990b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * Return "false". 2991b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * (3) Suspended. suspendCount is nonzero, and status is !RUNNING. 2992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Return "true". 2993b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * (4) Waking up. suspendCount is zero, status is SUSPENDED 2994b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * Return "false" (since it could change out from under us, unless 2995b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * we hold suspendCountLock). 2996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2998b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden return (thread->suspendCount != 0 && thread->status != THREAD_RUNNING); 2999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wait until another thread self-suspends. This is specifically for 3003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * synchronization between the JDWP thread and a thread that has decided 3004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to suspend itself after sending an event to the debugger. 3005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Threads that encounter "suspend all" events work as well -- the thread 3007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in question suspends everybody else and then itself. 3008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We can't hold a thread lock here or in the caller, because we could 3010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * get here just before the to-be-waited-for-thread issues a "suspend all". 3011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * There's an opportunity for badness if the thread we're waiting for exits 3012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and gets cleaned up, but since the thread in question is processing a 3013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * debugger event, that's not really a possibility. (To avoid deadlock, 3014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it's important that we not be in THREAD_RUNNING while we wait.) 3015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmWaitForSuspend(Thread* thread) 3017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* self = dvmThreadSelf(); 3019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: waiting for threadid=%d to sleep\n", 3021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, thread->threadId); 3022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->handle != dvmJdwpGetDebugThread(gDvm.jdwpState)); 3024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread != self); 3025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(self->status != THREAD_RUNNING); 3026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project waitForThreadSuspend(self, thread); 3028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOG_THREAD("threadid=%d: threadid=%d is now asleep\n", 3030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, thread->threadId); 3031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Check to see if we need to suspend ourselves. If so, go to sleep on 3035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * a condition variable. 3036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns "true" if we suspended ourselves. 3038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3039b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFaddenstatic bool fullSuspendCheck(Thread* self) 3040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3041fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom assert(self != NULL); 3042fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom assert(self->suspendCount >= 0); 3043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3044b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden /* 3045b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * Grab gDvm.threadSuspendCountLock. This gives us exclusive write 3046b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * access to self->suspendCount. 3047b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden */ 3048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lockThreadSuspendCount(); /* grab gDvm.threadSuspendCountLock */ 3049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3050b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden bool needSuspend = (self->suspendCount != 0); 3051b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden if (needSuspend) { 30523469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden LOG_THREAD("threadid=%d: self-suspending\n", self->threadId); 3053b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden ThreadStatus oldStatus = self->status; /* should be RUNNING */ 3054b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden self->status = THREAD_SUSPENDED; 3055b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden 30563469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden while (self->suspendCount != 0) { 3057b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden /* 3058b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * Wait for wakeup signal, releasing lock. The act of releasing 3059b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * and re-acquiring the lock provides the memory barriers we 3060b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * need for correct behavior on SMP. 3061b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden */ 30623469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden dvmWaitCond(&gDvm.threadSuspendCountCond, 30633469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden &gDvm.threadSuspendCountLock); 30643469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden } 30653469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden assert(self->suspendCount == 0 && self->dbgSuspendCount == 0); 3066b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden self->status = oldStatus; 30673469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden LOG_THREAD("threadid=%d: self-reviving, status=%d\n", 30683469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden self->threadId, self->status); 3069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unlockThreadSuspendCount(); 3072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3073b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden return needSuspend; 3074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3077b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * Check to see if a suspend is pending. If so, suspend the current 3078b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * thread, and return "true" after we have been resumed. 3079fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom */ 3080fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrombool dvmCheckSuspendPending(Thread* self) 3081fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom{ 3082b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden assert(self != NULL); 3083b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden if (self->suspendCount == 0) { 3084b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden return false; 3085b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden } else { 3086b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden return fullSuspendCheck(self); 3087b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden } 3088fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom} 3089fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom 3090fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom/* 3091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Update our status. 3092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The "self" argument, which may be NULL, is accepted as an optimization. 3094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns the old status. 3096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThreadStatus dvmChangeStatus(Thread* self, ThreadStatus newStatus) 3098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ThreadStatus oldStatus; 3100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (self == NULL) 3102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self = dvmThreadSelf(); 3103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGVV("threadid=%d: (status %d -> %d)\n", 3105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, self->status, newStatus); 3106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project oldStatus = self->status; 3108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (newStatus == THREAD_RUNNING) { 3110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 3111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Change our status to THREAD_RUNNING. The transition requires 3112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * that we check for pending suspension, because the VM considers 3113fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * us to be "asleep" in all other states, and another thread could 3114fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * be performing a GC now. 3115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3116b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * The order of operations is very significant here. One way to 3117b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * do this wrong is: 3118b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * 3119b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * GCing thread Our thread (in NATIVE) 3120b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * ------------ ---------------------- 3121b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * check suspend count (== 0) 3122b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * dvmSuspendAllThreads() 3123b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * grab suspend-count lock 3124b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * increment all suspend counts 3125b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * release suspend-count lock 3126b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * check thread state (== NATIVE) 3127b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * all are suspended, begin GC 3128b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * set state to RUNNING 3129b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * (continue executing) 3130b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * 3131b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * We can correct this by grabbing the suspend-count lock and 3132b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * performing both of our operations (check suspend count, set 3133b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * state) while holding it, now we need to grab a mutex on every 3134b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * transition to RUNNING. 3135b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * 3136b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * What we do instead is change the order of operations so that 3137b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * the transition to RUNNING happens first. If we then detect 3138b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * that the suspend count is nonzero, we switch to SUSPENDED. 3139b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * 3140b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * Appropriate compiler and memory barriers are required to ensure 3141b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * that the operations are observed in the expected order. 3142b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * 3143b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * This does create a small window of opportunity where a GC in 3144b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * progress could observe what appears to be a running thread (if 3145b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * it happens to look between when we set to RUNNING and when we 3146b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * switch to SUSPENDED). At worst this only affects assertions 3147b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * and thread logging. (We could work around it with some sort 3148b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * of intermediate "pre-running" state that is generally treated 3149b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * as equivalent to running, but that doesn't seem worthwhile.) 3150b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * 3151b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * We can also solve this by combining the "status" and "suspend 3152b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * count" fields into a single 32-bit value. This trades the 3153b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * store/load barrier on transition to RUNNING for an atomic RMW 3154b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * op on all transitions and all suspend count updates (also, all 3155b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * accesses to status or the thread count require bit-fiddling). 3156b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * It also eliminates the brief transition through RUNNING when 3157b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * the thread is supposed to be suspended. This is possibly faster 3158b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * on SMP and slightly more correct, but less convenient. 3159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3160b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden assert(oldStatus != THREAD_RUNNING); 3161b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden android_atomic_acquire_store(newStatus, &self->status); 3162b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden if (self->suspendCount != 0) { 3163b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden fullSuspendCheck(self); 3164b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden } 3165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 3166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 3167fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom * Not changing to THREAD_RUNNING. No additional work required. 31683469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * 31693469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * We use a releasing store to ensure that, if we were RUNNING, 31703469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * any updates we previously made to objects on the managed heap 31713469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden * will be observed before the state change. 3172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3173b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden assert(newStatus != THREAD_SUSPENDED); 31743469a7e404591fe158a60b4d05b0f2c768bcfce2Andy McFadden android_atomic_release_store(newStatus, &self->status); 3175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return oldStatus; 3178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get a statically defined thread group from a field in the ThreadGroup 3182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Class object. Expected arguments are "mMain" and "mSystem". 3183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic Object* getStaticThreadGroup(const char* fieldName) 3185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StaticField* groupField; 3187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* groupObj; 3188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project groupField = dvmFindStaticField(gDvm.classJavaLangThreadGroup, 3190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fieldName, "Ljava/lang/ThreadGroup;"); 3191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (groupField == NULL) { 3192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("java.lang.ThreadGroup does not have an '%s' field\n", fieldName); 3193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmThrowException("Ljava/lang/IncompatibleClassChangeError;", NULL); 3194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 3195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project groupObj = dvmGetStaticFieldObject(groupField); 3197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (groupObj == NULL) { 3198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("java.lang.ThreadGroup.%s not initialized\n", fieldName); 3199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmThrowException("Ljava/lang/InternalError;", NULL); 3200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 3201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return groupObj; 3204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectObject* dvmGetSystemThreadGroup(void) 3206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return getStaticThreadGroup("mSystem"); 3208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectObject* dvmGetMainThreadGroup(void) 3210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return getStaticThreadGroup("mMain"); 3212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Given a VMThread object, return the associated Thread*. 3216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * NOTE: if the thread detaches, the struct Thread will disappear, and 3218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we will be touching invalid data. For safety, lock the thread list 3219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * before calling this. 3220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThread* dvmGetThreadFromThreadObject(Object* vmThreadObj) 3222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int vmData; 3224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project vmData = dvmGetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData); 32264486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 32274486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden if (false) { 32284486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden Thread* thread = gDvm.threadList; 32294486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden while (thread != NULL) { 32304486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden if ((Thread*)vmData == thread) 32314486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden break; 32324486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 32334486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden thread = thread->next; 32344486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 32354486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 32364486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden if (thread == NULL) { 32374486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden LOGW("WARNING: vmThreadObj=%p has thread=%p, not in thread list\n", 32384486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden vmThreadObj, (Thread*)vmData); 32394486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden vmData = 0; 32404486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 32414486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden } 32424486036f2c532e678804cbfcdff23ba9cd9da98aAndy McFadden 3243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return (Thread*) vmData; 3244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 32462b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden/* 32472b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden * Given a pthread handle, return the associated Thread*. 32480a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden * Caller must hold the thread list lock. 32492b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden * 32502b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden * Returns NULL if the thread was not found. 32512b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden */ 32522b94b30abe21de859b00965d00cc7d42ee436943Andy McFaddenThread* dvmGetThreadByHandle(pthread_t handle) 32532b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden{ 32540a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden Thread* thread; 32550a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 32562b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden if (thread->handle == handle) 32572b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden break; 32582b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden } 32590a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden return thread; 32600a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden} 32612b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden 32620a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden/* 32630a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden * Given a threadId, return the associated Thread*. 32640a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden * Caller must hold the thread list lock. 32650a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden * 32660a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden * Returns NULL if the thread was not found. 32670a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden */ 32680a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFaddenThread* dvmGetThreadByThreadId(u4 threadId) 32690a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden{ 32700a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden Thread* thread; 32710a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 32720a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden if (thread->threadId == threadId) 32730a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden break; 32740a24ef9d1a88984dae3f7a9bf431c82626eadb2eAndy McFadden } 32752b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden return thread; 32762b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden} 32772b94b30abe21de859b00965d00cc7d42ee436943Andy McFadden 3278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Conversion map for "nice" values. 3281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We use Android thread priority constants to be consistent with the rest 3283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of the system. In some cases adjacent entries may overlap. 3284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic const int kNiceValues[10] = { 3286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_LOWEST, /* 1 (MIN_PRIORITY) */ 3287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_BACKGROUND + 6, 3288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_BACKGROUND + 3, 3289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_BACKGROUND, 3290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_NORMAL, /* 5 (NORM_PRIORITY) */ 3291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_NORMAL - 2, 3292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_NORMAL - 4, 3293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_URGENT_DISPLAY + 3, 3294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_URGENT_DISPLAY + 2, 3295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ANDROID_PRIORITY_URGENT_DISPLAY /* 10 (MAX_PRIORITY) */ 3296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}; 3297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Change the priority of a system thread to match that of the Thread object. 3300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We map a priority value from 1-10 to Linux "nice" values, where lower 3302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * numbers indicate higher priority. 3303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmChangeThreadPriority(Thread* thread, int newPriority) 3305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pid_t pid = thread->systemTid; 3307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int newNice; 3308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (newPriority < 1 || newPriority > 10) { 3310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("bad priority %d\n", newPriority); 3311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newPriority = 5; 3312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newNice = kNiceValues[newPriority-1]; 3314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3315d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden if (newNice >= ANDROID_PRIORITY_BACKGROUND) { 33165a2056ca8c7e7c0ed9f51d68cedbee59cc936685San Mehat set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND); 33173e371e2ebbeeefe176ba1357e6ff241bd13a711eSan Mehat } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) { 33185a2056ca8c7e7c0ed9f51d68cedbee59cc936685San Mehat set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND); 3319256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat } 3320256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat 3321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (setpriority(PRIO_PROCESS, pid, newNice) != 0) { 3322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project char* str = dvmGetThreadName(thread); 3323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGI("setPriority(%d) '%s' to prio=%d(n=%d) failed: %s\n", 3324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pid, str, newPriority, newNice, strerror(errno)); 3325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(str); 3326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 3327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("setPriority(%d) to prio=%d(n=%d)\n", 3328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pid, newPriority, newNice); 3329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get the thread priority for the current thread by querying the system. 3334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is useful when attaching a thread through JNI. 3335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns a value from 1 to 10 (compatible with java.lang.Thread values). 3337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int getThreadPriorityFromSystem(void) 3339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int i, sysprio, jprio; 3341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project errno = 0; 3343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sysprio = getpriority(PRIO_PROCESS, 0); 3344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (sysprio == -1 && errno != 0) { 3345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("getpriority() failed: %s\n", strerror(errno)); 3346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return THREAD_NORM_PRIORITY; 3347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project jprio = THREAD_MIN_PRIORITY; 3350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (i = 0; i < NELEM(kNiceValues); i++) { 3351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (sysprio >= kNiceValues[i]) 3352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project break; 3353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project jprio++; 3354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (jprio > THREAD_MAX_PRIORITY) 3356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project jprio = THREAD_MAX_PRIORITY; 3357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return jprio; 3359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Return true if the thread is on gDvm.threadList. 3364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Caller should not hold gDvm.threadListLock. 3365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmIsOnThreadList(const Thread* thread) 3367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project bool ret = false; 3369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(NULL); 3371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread == gDvm.threadList) { 3372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ret = true; 3373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 3374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ret = thread->prev != NULL || thread->next != NULL; 3375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 3377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return ret; 3379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Dump a thread to the log file -- just calls dvmDumpThreadEx() with an 3383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * output target. 3384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmDumpThread(Thread* thread, bool isRunning) 3386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project DebugOutputTarget target; 3388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG); 3390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpThreadEx(&target, thread, isRunning); 3391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3394d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden * Try to get the scheduler group. 3395d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden * 33967f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden * The data from /proc/<pid>/cgroup looks (something) like: 3397d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden * 2:cpu:/bg_non_interactive 33987f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden * 1:cpuacct:/ 3399d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden * 3400ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden * We return the part on the "cpu" line after the '/', which will be an 3401ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden * empty string for the default cgroup. If the string is longer than 3402ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden * "bufLen", the string will be truncated. 34037f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden * 3404ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden * On error, -1 is returned, and an error description will be stored in 3405ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden * the buffer. 3406d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden */ 34077f64edea45478453e5612c0cc57afa3e4a90c564Andy McFaddenstatic int getSchedulerGroup(int tid, char* buf, size_t bufLen) 3408d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden{ 3409d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden#ifdef HAVE_ANDROID_OS 3410d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden char pathBuf[32]; 34117f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden char lineBuf[256]; 34127f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden FILE *fp; 3413d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden 34147f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid); 3415ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden if ((fp = fopen(pathBuf, "r")) == NULL) { 3416ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden snprintf(buf, bufLen, "[fopen-error:%d]", errno); 34177f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden return -1; 3418d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden } 3419d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden 3420ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden while (fgets(lineBuf, sizeof(lineBuf) -1, fp) != NULL) { 3421ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden char* subsys; 3422ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden char* grp; 34237f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden size_t len; 3424d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden 34257f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden /* Junk the first field */ 3426ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden subsys = strchr(lineBuf, ':'); 3427ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden if (subsys == NULL) { 34287f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden goto out_bad_data; 34297f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden } 3430d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden 3431ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden if (strncmp(subsys, ":cpu:", 5) != 0) { 34327f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden /* Not the subsys we're looking for */ 34337f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden continue; 34347f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden } 34357f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden 3436ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden grp = strchr(subsys, '/'); 3437ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden if (grp == NULL) { 34387f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden goto out_bad_data; 34397f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden } 34407f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden grp++; /* Drop the leading '/' */ 3441ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden 34427f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden len = strlen(grp); 34437f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden grp[len-1] = '\0'; /* Drop the trailing '\n' */ 34447f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden 34457f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden if (bufLen <= len) { 34467f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden len = bufLen - 1; 34477f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden } 34487f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden strncpy(buf, grp, len); 34497f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden buf[len] = '\0'; 34507f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden fclose(fp); 34517f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden return 0; 3452d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden } 3453d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden 3454ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden snprintf(buf, bufLen, "[no-cpu-subsys]"); 34557f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden fclose(fp); 34567f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden return -1; 3457ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden 3458ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFaddenout_bad_data: 34597f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden LOGE("Bad cgroup data {%s}", lineBuf); 3460ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden snprintf(buf, bufLen, "[data-parse-failed]"); 34617f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden fclose(fp); 34627f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden return -1; 3463ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden 3464d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden#else 3465ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden snprintf(buf, bufLen, "[n/a]"); 34667f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden return -1; 3467d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden#endif 3468d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden} 3469d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden 3470d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden/* 34717a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng * Convert ThreadStatus to a string. 34727a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng */ 34737a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Chengconst char* dvmGetThreadStatusStr(ThreadStatus status) 34747a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng{ 34757a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng switch (status) { 34767a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_ZOMBIE: return "ZOMBIE"; 34777a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_RUNNING: return "RUNNABLE"; 34787a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_TIMED_WAIT: return "TIMED_WAIT"; 34797a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_MONITOR: return "MONITOR"; 34807a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_WAIT: return "WAIT"; 34817a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_INITIALIZING: return "INITIALIZING"; 34827a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_STARTING: return "STARTING"; 34837a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_NATIVE: return "NATIVE"; 34847a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng case THREAD_VMWAIT: return "VMWAIT"; 3485b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden case THREAD_SUSPENDED: return "SUSPENDED"; 34867a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng default: return "UNKNOWN"; 34877a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng } 34887a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng} 34897a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng 34907a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng/* 3491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Print information about the specified thread. 3492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Works best when the thread in question is "self" or has been suspended. 3494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * When dumping a separate thread that's still running, set "isRunning" to 3495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * use a more cautious thread dump function. 3496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread, 3498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project bool isRunning) 3499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* threadObj; 3501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object* groupObj; 3502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StringObject* nameStr; 3503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project char* threadName = NULL; 3504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project char* groupName = NULL; 3505d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden char schedulerGroupBuf[32]; 3506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project bool isDaemon; 3507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int priority; // java.lang.Thread priority 3508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int policy; // pthread policy 3509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project struct sched_param sp; // pthread scheduling parameters 3510962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate char schedstatBuf[64]; // contents of /proc/[pid]/task/[tid]/schedstat 3511962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate int schedstatFd; 3512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3513e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden /* 3514e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * Get the java.lang.Thread object. This function gets called from 3515e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * some weird debug contexts, so it's possible that there's a GC in 3516e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * progress on some other thread. To decrease the chances of the 3517e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * thread object being moved out from under us, we add the reference 3518e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * to the tracked allocation list, which pins it in place. 3519e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * 3520e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * If threadObj is NULL, the thread is still in the process of being 3521e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * attached to the VM, and there's really nothing interesting to 3522e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden * say about it yet. 3523e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden */ 3524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project threadObj = thread->threadObj; 3525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (threadObj == NULL) { 3526e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden LOGI("Can't dump thread %d: threadObj not set\n", thread->threadId); 3527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 3528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3529e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmAddTrackedAlloc(threadObj, NULL); 3530e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden 3531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project nameStr = (StringObject*) dvmGetFieldObject(threadObj, 3532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_name); 3533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project threadName = dvmCreateCstrFromString(nameStr); 3534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project priority = dvmGetFieldInt(threadObj, gDvm.offJavaLangThread_priority); 3536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project isDaemon = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon); 3537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pthread_getschedparam(pthread_self(), &policy, &sp) != 0) { 3539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("Warning: pthread_getschedparam failed\n"); 3540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project policy = -1; 3541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sp.sched_priority = -1; 3542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 35437f64edea45478453e5612c0cc57afa3e4a90c564Andy McFadden if (getSchedulerGroup(thread->systemTid, schedulerGroupBuf, 3544ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden sizeof(schedulerGroupBuf)) == 0 && 3545ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden schedulerGroupBuf[0] == '\0') { 3546d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden strcpy(schedulerGroupBuf, "default"); 3547d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden } 3548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* a null value for group is not expected, but deal with it anyway */ 3550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project groupObj = (Object*) dvmGetFieldObject(threadObj, 3551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gDvm.offJavaLangThread_group); 3552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (groupObj != NULL) { 3553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int offset = dvmFindFieldOffset(gDvm.classJavaLangThreadGroup, 3554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "name", "Ljava/lang/String;"); 3555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (offset < 0) { 3556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("Unable to find 'name' field in ThreadGroup\n"); 3557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 3558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project nameStr = (StringObject*) dvmGetFieldObject(groupObj, offset); 3559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project groupName = dvmCreateCstrFromString(nameStr); 3560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (groupName == NULL) 356340607dd231b442cfec221e4c909f19245c5193e4Andy McFadden groupName = strdup("(null; initializing?)"); 3564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmPrintDebugMessage(target, 3566dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng "\"%s\"%s prio=%d tid=%d %s%s\n", 3567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project threadName, isDaemon ? " daemon" : "", 3568dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng priority, thread->threadId, dvmGetThreadStatusStr(thread->status), 3569dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng#if defined(WITH_JIT) 3570dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng thread->inJitCodeCache ? " JIT" : "" 3571dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng#else 3572dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng "" 3573dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng#endif 3574dc4a928232b7be2b634b17e60ce72c354c01ec1fBen Cheng ); 3575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmPrintDebugMessage(target, 3576b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden " | group=\"%s\" sCount=%d dsCount=%d obj=%p self=%p\n", 3577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project groupName, thread->suspendCount, thread->dbgSuspendCount, 3578b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden thread->threadObj, thread); 3579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmPrintDebugMessage(target, 3580d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden " | sysTid=%d nice=%d sched=%d/%d cgrp=%s handle=%d\n", 3581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread->systemTid, getpriority(PRIO_PROCESS, thread->systemTid), 3582d62c0b5d6acaa37bcac36452e74b21782e104968Andy McFadden policy, sp.sched_priority, schedulerGroupBuf, (int)thread->handle); 3583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3584962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate snprintf(schedstatBuf, sizeof(schedstatBuf), "/proc/%d/task/%d/schedstat", 3585962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate getpid(), thread->systemTid); 3586962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate schedstatFd = open(schedstatBuf, O_RDONLY); 3587962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate if (schedstatFd >= 0) { 3588962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate int bytes; 3589962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate bytes = read(schedstatFd, schedstatBuf, sizeof(schedstatBuf) - 1); 3590962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate close(schedstatFd); 3591962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate if (bytes > 1) { 3592962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate schedstatBuf[bytes-1] = 0; // trailing newline 3593962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate dvmPrintDebugMessage(target, " | schedstat=( %s )\n", schedstatBuf); 3594962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate } 3595962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate } 3596962f896e1eeb159a6a2ac7a560708939cbb15575Christopher Tate 3597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef WITH_MONITOR_TRACKING 3598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!isRunning) { 3599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LockedObjectData* lod = thread->pLockedObjects; 3600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (lod != NULL) 3601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmPrintDebugMessage(target, " | monitors held:\n"); 3602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else 3603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmPrintDebugMessage(target, " | monitors held: <none>\n"); 3604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (lod != NULL) { 3605beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes Object* obj = lod->obj; 3606beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes if (obj->clazz == gDvm.classJavaLangClass) { 3607beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes ClassObject* clazz = (ClassObject*) obj; 3608beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes dvmPrintDebugMessage(target, " > %p[%d] (%s object for class %s)\n", 3609beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes obj, lod->recursionCount, obj->clazz->descriptor, 3610beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes clazz->descriptor); 3611beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes } else { 3612beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes dvmPrintDebugMessage(target, " > %p[%d] (%s)\n", 3613beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes obj, lod->recursionCount, obj->clazz->descriptor); 3614beea0b72181a13e6e0850704a2a5de2df00e15c3Elliott Hughes } 3615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = lod->next; 3616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 3619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (isRunning) 3621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpRunningThreadStack(target, thread); 3622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else 3623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpThreadStack(target, thread); 3624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3625e3346d8b2049cefe4d27218b47b6da0cd179cc24Andy McFadden dvmReleaseTrackedAlloc(threadObj, NULL); 3626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(threadName); 3627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(groupName); 3628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get the name of a thread. 3632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * For correctness, the caller should hold the thread list lock to ensure 3634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * that the thread doesn't go away mid-call. 3635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns a newly-allocated string, or NULL if the Thread doesn't have a name. 3637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectchar* dvmGetThreadName(Thread* thread) 3639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StringObject* nameObj; 3641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->threadObj == NULL) { 3643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("threadObj is NULL, name not available\n"); 3644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return strdup("-unknown-"); 3645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project nameObj = (StringObject*) 3648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmGetFieldObject(thread->threadObj, gDvm.offJavaLangThread_name); 3649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return dvmCreateCstrFromString(nameObj); 3650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Dump all threads to the log file -- just calls dvmDumpAllThreadsEx() with 3654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * an output target. 3655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmDumpAllThreads(bool grabLock) 3657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project DebugOutputTarget target; 3659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG); 3661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpAllThreadsEx(&target, grabLock); 3662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Print information about all known threads. Assumes they have been 3666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * suspended (or are in a non-interpreting state, e.g. WAIT or NATIVE). 3667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If "grabLock" is true, we grab the thread lock list. This is important 3669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to do unless the caller already holds the lock. 3670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock) 3672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread* thread; 3674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmPrintDebugMessage(target, "DALVIK THREADS:\n"); 3676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3677fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom#ifdef HAVE_ANDROID_OS 3678fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom dvmPrintDebugMessage(target, 3679fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x hwl=%x hwll=%x)\n", 3680fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom gDvm.threadListLock.value, 3681fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom gDvm._threadSuspendLock.value, 3682fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom gDvm.threadSuspendCountLock.value, 3683fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom gDvm.gcHeapLock.value, 3684fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom gDvm.heapWorkerLock.value, 3685fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom gDvm.heapWorkerListLock.value); 3686fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom#endif 3687fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom 3688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (grabLock) 3689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(dvmThreadSelf()); 3690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread = gDvm.threadList; 3692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (thread != NULL) { 3693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmDumpThreadEx(target, thread, false); 3694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* verify link */ 3696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread->next == NULL || thread->next->prev == thread); 3697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread = thread->next; 3699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (grabLock) 3702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 3703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3705384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden/* 3706384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * Nuke the target thread from orbit. 3707384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * 3708384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * The idea is to send a "crash" signal to the target thread so that 3709384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * debuggerd will take notice and dump an appropriate stack trace. 3710384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * Because of the way debuggerd works, we have to throw the same signal 3711384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * at it twice. 3712384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * 3713384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * This does not necessarily cause the entire process to stop, but once a 3714384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * thread has been nuked the rest of the system is likely to be unstable. 3715384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * This returns so that some limited set of additional operations may be 3716d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * performed, but it's advisable (and expected) to call dvmAbort soon. 3717d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * (This is NOT a way to simply cancel a thread.) 3718384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden */ 3719384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFaddenvoid dvmNukeThread(Thread* thread) 3720384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden{ 3721ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden int killResult; 3722ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden 3723a388a16ee358179e4776fc6abd60fa757c3288a5Andy McFadden /* suppress the heapworker watchdog to assist anyone using a debugger */ 3724a388a16ee358179e4776fc6abd60fa757c3288a5Andy McFadden gDvm.nativeDebuggerActive = true; 3725a388a16ee358179e4776fc6abd60fa757c3288a5Andy McFadden 3726384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden /* 3727d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * Send the signals, separated by a brief interval to allow debuggerd 3728d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * to work its magic. An uncommon signal like SIGFPE or SIGSTKFLT 3729d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * can be used instead of SIGSEGV to avoid making it look like the 3730d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * code actually crashed at the current point of execution. 3731d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * 3732d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * (Observed behavior: with SIGFPE, debuggerd will dump the target 3733d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * thread and then the thread that calls dvmAbort. With SIGSEGV, 3734d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * you don't get the second stack trace; possibly something in the 3735d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * kernel decides that a signal has already been sent and it's time 3736d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * to just kill the process. The position in the current thread is 3737d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden * generally known, so the second dump is not useful.) 3738384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden * 3739a388a16ee358179e4776fc6abd60fa757c3288a5Andy McFadden * The target thread can continue to execute between the two signals. 3740a388a16ee358179e4776fc6abd60fa757c3288a5Andy McFadden * (The first just causes debuggerd to attach to it.) 3741384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden */ 3742d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden LOGD("threadid=%d: sending two SIGSTKFLTs to threadid=%d (tid=%d) to" 3743d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden " cause debuggerd dump\n", 3744d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden dvmThreadSelf()->threadId, thread->threadId, thread->systemTid); 3745ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden killResult = pthread_kill(thread->handle, SIGSTKFLT); 3746ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden if (killResult != 0) { 3747ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden LOGD("NOTE: pthread_kill #1 failed: %s\n", strerror(killResult)); 3748ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden } 3749a388a16ee358179e4776fc6abd60fa757c3288a5Andy McFadden usleep(2 * 1000 * 1000); // TODO: timed-wait until debuggerd attaches 3750ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden killResult = pthread_kill(thread->handle, SIGSTKFLT); 3751ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden if (killResult != 0) { 3752ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden LOGD("NOTE: pthread_kill #2 failed: %s\n", strerror(killResult)); 3753ddd9d0b3527072f83db00105e28fa88c47bd763bAndy McFadden } 37547122d86e220ab28bf0bc1219fea82b143536554eAndy McFadden LOGD("Sent, pausing to let debuggerd run\n"); 3755a388a16ee358179e4776fc6abd60fa757c3288a5Andy McFadden usleep(8 * 1000 * 1000); // TODO: timed-wait until debuggerd finishes 3756d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden 3757d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden /* ignore SIGSEGV so the eventual dmvAbort() doesn't notify debuggerd */ 3758d4e0952b73f9054adcc927a1c12699ba63f1672aAndy McFadden signal(SIGSEGV, SIG_IGN); 3759384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden LOGD("Continuing\n"); 3760384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden} 3761384ef6b4770ad6ae3c4c940bd6c5a6e768d1e45fAndy McFadden 3762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef WITH_MONITOR_TRACKING 3763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Count up the #of locked objects in the current thread. 3765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int getThreadObjectCount(const Thread* self) 3767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LockedObjectData* lod; 3769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int count = 0; 3770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = self->pLockedObjects; 3772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (lod != NULL) { 3773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project count++; 3774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = lod->next; 3775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return count; 3777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Add the object to the thread's locked object list if it doesn't already 3781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * exist. The most recently added object is the most likely to be released 3782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * next, so we insert at the head of the list. 3783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If it already exists, we increase the recursive lock count. 3785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The object's lock may be thin or fat. 3787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmAddToMonitorList(Thread* self, Object* obj, bool withTrace) 3789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LockedObjectData* newLod; 3791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LockedObjectData* lod; 3792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int* trace; 3793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int depth; 3794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = self->pLockedObjects; 3796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (lod != NULL) { 3797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (lod->obj == obj) { 3798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod->recursionCount++; 3799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("+++ +recursive lock %p -> %d\n", obj, lod->recursionCount); 3800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 3801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = lod->next; 3803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newLod = (LockedObjectData*) calloc(1, sizeof(LockedObjectData)); 3806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (newLod == NULL) { 3807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("malloc failed on %d bytes\n", sizeof(LockedObjectData)); 3808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 3809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newLod->obj = obj; 3811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newLod->recursionCount = 0; 3812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (withTrace) { 3814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project trace = dvmFillInStackTraceRaw(self, &depth); 3815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newLod->rawStackTrace = trace; 3816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newLod->stackDepth = depth; 3817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project newLod->next = self->pLockedObjects; 3820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->pLockedObjects = newLod; 3821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("+++ threadid=%d: added %p, now %d\n", 3823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, newLod, getThreadObjectCount(self)); 3824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Remove the object from the thread's locked object list. If the entry 3828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * has a nonzero recursion count, we just decrement the count instead. 3829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmRemoveFromMonitorList(Thread* self, Object* obj) 3831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LockedObjectData* lod; 3833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LockedObjectData* prevLod; 3834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = self->pLockedObjects; 3836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project prevLod = NULL; 3837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (lod != NULL) { 3838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (lod->obj == obj) { 3839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (lod->recursionCount > 0) { 3840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod->recursionCount--; 3841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("+++ -recursive lock %p -> %d\n", 3842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project obj, lod->recursionCount); 3843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 3844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 3845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project break; 3846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project prevLod = lod; 3849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = lod->next; 3850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (lod == NULL) { 3853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("BUG: object %p not found in thread's lock list\n", obj); 3854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 3855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (prevLod == NULL) { 3857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* first item in list */ 3858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(self->pLockedObjects == lod); 3859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->pLockedObjects = lod->next; 3860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 3861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* middle/end of list */ 3862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project prevLod->next = lod->next; 3863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("+++ threadid=%d: removed %p, now %d\n", 3866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project self->threadId, lod, getThreadObjectCount(self)); 3867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(lod->rawStackTrace); 3868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(lod); 3869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If the specified object is already in the thread's locked object list, 3873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * return the LockedObjectData struct. Otherwise return NULL. 3874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectLockedObjectData* dvmFindInMonitorList(const Thread* self, const Object* obj) 3876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LockedObjectData* lod; 3878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = self->pLockedObjects; 3880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (lod != NULL) { 3881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (lod->obj == obj) 3882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return lod; 3883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project lod = lod->next; 3884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 3886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 3887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif /*WITH_MONITOR_TRACKING*/ 3888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * GC helper functions 3892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 3893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 389499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/* 389599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Add the contents of the registers from the interpreted call stack. 389699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 3897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void gcScanInterpStackReferences(Thread *thread) 3898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const u4 *framePtr; 390099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#if WITH_EXTRA_GC_CHECKS > 1 390199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project bool first = true; 390299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif 3903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project framePtr = (const u4 *)thread->curFrame; 3905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (framePtr != NULL) { 3906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const StackSaveArea *saveArea; 3907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const Method *method; 3908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project saveArea = SAVEAREA_FROM_FP(framePtr); 3910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project method = saveArea->method; 3911fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom if (method != NULL) { 3912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef COUNT_PRECISE_METHODS 3913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* the GC is running, so no lock required */ 391499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (dvmPointerSetAddEntry(gDvm.preciseMethods, method)) 391599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGI("PGC: added %s.%s %p\n", 391699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project method->clazz->descriptor, method->name, method); 391799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif 391899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#if WITH_EXTRA_GC_CHECKS > 1 391999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 392099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * May also want to enable the memset() in the "invokeMethod" 392199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * goto target in the portable interpreter. That sets the stack 392299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * to a pattern that makes referring to uninitialized data 392399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * very obvious. 392499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 392599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 392699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (first) { 392799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 392899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * First frame, isn't native, check the "alternate" saved PC 392999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * as a sanity check. 393099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 393199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * It seems like we could check the second frame if the first 393299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * is native, since the PCs should be the same. It turns out 393399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * this doesn't always work. The problem is that we could 393499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * have calls in the sequence: 393599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * interp method #2 393699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * native method 393799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * interp method #1 393899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 393999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * and then GC while in the native method after returning 394099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * from interp method #2. The currentPc on the stack is 394199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * for interp method #1, but thread->currentPc2 is still 394299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * set for the last thing interp method #2 did. 394399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 394499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * This can also happen in normal execution: 394599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * - sget-object on not-yet-loaded class 394699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * - class init updates currentPc2 394799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * - static field init is handled by parsing annotations; 394899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * static String init requires creation of a String object, 394999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * which can cause a GC 395099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 395199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Essentially, any pattern that involves executing 395299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * interpreted code and then causes an allocation without 395399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * executing instructions in the original method will hit 395499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * this. These are rare enough that the test still has 395599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * some value. 395699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 395799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (saveArea->xtra.currentPc != thread->currentPc2) { 395899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGW("PGC: savedPC(%p) != current PC(%p), %s.%s ins=%p\n", 395999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project saveArea->xtra.currentPc, thread->currentPc2, 396099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project method->clazz->descriptor, method->name, method->insns); 396199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (saveArea->xtra.currentPc != NULL) 396299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGE(" pc inst = 0x%04x\n", *saveArea->xtra.currentPc); 396399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (thread->currentPc2 != NULL) 396499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGE(" pc2 inst = 0x%04x\n", *thread->currentPc2); 396599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project dvmDumpThread(thread, false); 396699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 396799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } else { 396899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 396999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * It's unusual, but not impossible, for a non-first frame 397099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * to be at something other than a method invocation. For 397199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * example, if we do a new-instance on a nonexistent class, 397299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * we'll have a lot of class loader activity on the stack 397399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * above the frame with the "new" operation. Could also 397499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * happen while we initialize a Throwable when an instruction 397599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * fails. 397699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 397799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * So there's not much we can do here to verify the PC, 397899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * except to verify that it's a GC point. 397999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 3980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 398199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project assert(saveArea->xtra.currentPc != NULL); 3982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 398399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 398499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project const RegisterMap* pMap; 398599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project const u1* regVector; 3986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int i; 398799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 3988cf8b55ca78c6c25e80d5f13be0376bf094d08134Andy McFadden Method* nonConstMethod = (Method*) method; // quiet gcc 3989cf8b55ca78c6c25e80d5f13be0376bf094d08134Andy McFadden pMap = dvmGetExpandedRegisterMap(nonConstMethod); 399099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (pMap != NULL) { 399199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* found map, get registers for this address */ 399299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project int addr = saveArea->xtra.currentPc - method->insns; 3993d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden regVector = dvmRegisterMapGetLine(pMap, addr); 399499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (regVector == NULL) { 399599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGW("PGC: map but no entry for %s.%s addr=0x%04x\n", 399699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project method->clazz->descriptor, method->name, addr); 399799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } else { 399899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGV("PGC: found map for %s.%s 0x%04x (t=%d)\n", 399999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project method->clazz->descriptor, method->name, addr, 400099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project thread->threadId); 4001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 400299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } else { 400399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 400499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * No map found. If precise GC is disabled this is 400599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * expected -- we don't create pointers to the map data even 400699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * if it's present -- but if it's enabled it means we're 400799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * unexpectedly falling back on a conservative scan, so it's 400899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * worth yelling a little. 400999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 401099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (gDvm.preciseGc) { 4011a66a01ad2a9e5c6aefc93d12a5c18d6bba570a3eAndy McFadden LOGVV("PGC: no map for %s.%s\n", 401299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project method->clazz->descriptor, method->name); 401399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 401499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project regVector = NULL; 401599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 401699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 401799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (regVector == NULL) { 401899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* conservative scan */ 401999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project for (i = method->registersSize - 1; i >= 0; i--) { 402099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project u4 rval = *framePtr++; 402199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (rval != 0 && (rval & 0x3) == 0) { 402299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project dvmMarkIfObject((Object *)rval); 402399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 402499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 402599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } else { 402699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 402799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Precise scan. v0 is at the lowest address on the 402899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * interpreted stack, and is the first bit in the register 402999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * vector, so we can walk through the register map and 403099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * memory in the same direction. 403199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * 403299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * A '1' bit indicates a live reference. 403399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 403499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project u2 bits = 1 << 1; 403599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project for (i = method->registersSize - 1; i >= 0; i--) { 403699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project u4 rval = *framePtr++; 403799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 403899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project bits >>= 1; 403999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (bits == 1) { 404099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* set bit 9 so we can tell when we're empty */ 404199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project bits = *regVector++ | 0x0100; 404299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGVV("loaded bits: 0x%02x\n", bits & 0xff); 404399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 404499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 404599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (rval != 0 && (bits & 0x01) != 0) { 404699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 404799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Non-null, register marked as live reference. This 404899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * should always be a valid object. 404999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 405099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#if WITH_EXTRA_GC_CHECKS > 0 405199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if ((rval & 0x3) != 0 || 405299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project !dvmIsValidObject((Object*) rval)) 405399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project { 405499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* this is very bad */ 405599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGE("PGC: invalid ref in reg %d: 0x%08x\n", 405699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project method->registersSize-1 - i, rval); 40577b4c1d52a946506d49c6da5649d1677e92263d66Andy McFadden LOGE("PGC: %s.%s addr 0x%04x\n", 40587b4c1d52a946506d49c6da5649d1677e92263d66Andy McFadden method->clazz->descriptor, method->name, 40597b4c1d52a946506d49c6da5649d1677e92263d66Andy McFadden saveArea->xtra.currentPc - method->insns); 406099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } else 406199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif 406299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project { 406399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project dvmMarkObjectNonNull((Object *)rval); 406499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 406599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } else { 406699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* 406799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Null or non-reference, do nothing at all. 406899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 406999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#if WITH_EXTRA_GC_CHECKS > 1 407099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (dvmIsValidObject((Object*) rval)) { 407199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /* this is normal, but we feel chatty */ 407299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project LOGD("PGC: ignoring valid ref in reg %d: 0x%08x\n", 407399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project method->registersSize-1 - i, rval); 407499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 407599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif 407699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 407799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project } 407899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project dvmReleaseRegisterMapLine(pMap, regVector); 4079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 4080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 4081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 408299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#if WITH_EXTRA_GC_CHECKS > 1 408399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project first = false; 408499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif 408599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 4086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* Don't fall into an infinite loop if things get corrupted. 4087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 4088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr || 4089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project saveArea->prevFrame == NULL); 4090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project framePtr = saveArea->prevFrame; 4091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 4092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 4093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void gcScanReferenceTable(ReferenceTable *refTable) 4095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 4096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Object **op; 4097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project //TODO: these asserts are overkill; turn them off when things stablize. 4099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(refTable != NULL); 4100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(refTable->table != NULL); 4101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(refTable->nextEntry != NULL); 4102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert((uintptr_t)refTable->nextEntry >= (uintptr_t)refTable->table); 4103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(refTable->nextEntry - refTable->table <= refTable->maxEntries); 4104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project op = refTable->table; 4106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while ((uintptr_t)op < (uintptr_t)refTable->nextEntry) { 4107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmMarkObjectNonNull(*(op++)); 4108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 4109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 4110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4111fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom#ifdef USE_INDIRECT_REF 4112d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFaddenstatic void gcScanIndirectRefTable(IndirectRefTable* pRefTable) 4113d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden{ 4114d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden Object** op = pRefTable->table; 4115d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden int numEntries = dvmIndirectRefTableEntries(pRefTable); 4116d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden int i; 4117d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden 4118d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden for (i = 0; i < numEntries; i++) { 4119d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden Object* obj = *op; 4120d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden if (obj != NULL) 4121d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden dvmMarkObjectNonNull(obj); 4122d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden op++; 4123d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden } 4124d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden} 4125fbdcfb9ea9e2a78f295834424c3f24986ea45dacBrian Carlstrom#endif 4126d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden 4127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 4128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Scan a Thread and mark any objects it references. 4129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 4130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void gcScanThread(Thread *thread) 4131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 4132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(thread != NULL); 4133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 4135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The target thread must be suspended or in a state where it can't do 4136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * any harm (e.g. in Object.wait()). The only exception is the current 4137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * thread, which will still be active and in the "running" state. 4138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4139b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * It's possible to encounter a false-positive here because a thread 4140b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * transitioning to running from (say) vmwait or native will briefly 4141b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * set their status to running before switching to suspended. This 4142b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * is highly unlikely, but does mean that we don't want to abort if 4143b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden * the situation arises. 4144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 4145b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden if (thread->status == THREAD_RUNNING && thread != dvmThreadSelf()) { 4146d40223ec6b9f24f7968e25eb0f760e3b4dd063d1Andy McFadden Thread* self = dvmThreadSelf(); 4147b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden LOGW("threadid=%d: Warning: GC scanning a running thread (%d)\n", 4148d40223ec6b9f24f7968e25eb0f760e3b4dd063d1Andy McFadden self->threadId, thread->threadId); 4149d40223ec6b9f24f7968e25eb0f760e3b4dd063d1Andy McFadden dvmDumpThread(thread, true); 4150d40223ec6b9f24f7968e25eb0f760e3b4dd063d1Andy McFadden LOGW("Found by:\n"); 4151d40223ec6b9f24f7968e25eb0f760e3b4dd063d1Andy McFadden dvmDumpThread(self, false); 4152d40223ec6b9f24f7968e25eb0f760e3b4dd063d1Andy McFadden 4153b5f3c0b8222efea953adb94b97a2c70ba58e26e3Andy McFadden /* continue anyway */ 4154d40223ec6b9f24f7968e25eb0f760e3b4dd063d1Andy McFadden } 4155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_THREAD_OBJECT, thread->threadId); 4157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmMarkObject(thread->threadObj); // could be NULL, when constructing 4159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_NATIVE_STACK, thread->threadId); 4161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmMarkObject(thread->exception); // usually NULL 4163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gcScanReferenceTable(&thread->internalLocalRefTable); 4164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_LOCAL, thread->threadId); 4166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4167d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#ifdef USE_INDIRECT_REF 4168d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden gcScanIndirectRefTable(&thread->jniLocalRefTable); 4169d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#else 4170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gcScanReferenceTable(&thread->jniLocalRefTable); 4171d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden#endif 4172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (thread->jniMonitorRefTable.table != NULL) { 4174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JNI_MONITOR, thread->threadId); 4175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gcScanReferenceTable(&thread->jniMonitorRefTable); 4177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 4178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_JAVA_FRAME, thread->threadId); 4180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gcScanInterpStackReferences(thread); 4182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project HPROF_CLEAR_GC_SCAN_STATE(); 4184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 4185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void gcScanAllThreads() 4187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 4188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Thread *thread; 4189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* Lock the thread list so we can safely use the 4191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * next/prev pointers. 4192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 4193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmLockThreadList(dvmThreadSelf()); 4194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (thread = gDvm.threadList; thread != NULL; 4196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project thread = thread->next) 4197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 4198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* We need to scan our own stack, so don't special-case 4199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the current thread. 4200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 4201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gcScanThread(thread); 4202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 4203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dvmUnlockThreadList(); 4205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 4206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmGcScanRootThreadGroups() 4208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 4209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* We scan the VM's list of threads instead of going 4210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * through the actual ThreadGroups, but it should be 4211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * equivalent. 4212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 421397319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao * This assumes that the ThreadGroup class object is in 4214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the root set, which should always be true; it's 4215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * loaded by the built-in class loader, which is part 4216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of the root set. 4217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 4218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project gcScanAllThreads(); 4219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 4220