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