Bug Summary

File:jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c
Warning:line 1307, column 9
Access to field 'suspendCount' results in a dereference of a null pointer (loaded from variable 'node')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name threadControl.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -D LIBC=gnu -D _GNU_SOURCE -D _REENTRANT -D _LARGEFILE64_SOURCE -D LINUX -D DEBUG -D _LITTLE_ENDIAN -D ARCH="amd64" -D amd64 -D _LP64=1 -D JDWP_LOGGING -I /home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/unix/native/libjdwp -I /home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/headers/jdk.jdwp.agent -I /home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/include -I /home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/export -D _FORTIFY_SOURCE=2 -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-unused -Wno-unused-function -std=c99 -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c /home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c
1/*
2 * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include "util.h"
27#include "eventHandler.h"
28#include "threadControl.h"
29#include "commonRef.h"
30#include "eventHelper.h"
31#include "stepControl.h"
32#include "invoker.h"
33#include "bag.h"
34
35#define HANDLING_EVENT(node)((node)->current_ei != 0) ((node)->current_ei != 0)
36
37/*
38 * Collection of info for properly handling co-located events.
39 * If the ei field is non-zero, then one of the possible
40 * co-located events has been posted and the other fields describe
41 * the event's location.
42 *
43 * See comment above deferEventReport() for an explanation of co-located events.
44 */
45typedef struct CoLocatedEventInfo_ {
46 EventIndex ei;
47 jclass clazz;
48 jmethodID method;
49 jlocation location;
50} CoLocatedEventInfo;
51
52/**
53 * The main data structure in threadControl is the ThreadNode.
54 * This is a per-thread structure that is allocated on the
55 * first event that occurs in a thread. It is freed after the
56 * thread's thread end event has completed processing. The
57 * structure contains state information on its thread including
58 * suspend counts. It also acts as a repository for other
59 * per-thread state such as the current method invocation or
60 * current step.
61 *
62 * suspendCount is the number of outstanding suspends
63 * from the debugger. suspends from the app itself are
64 * not included in this count.
65 */
66typedef struct ThreadNode {
67 jthread thread;
68 unsigned int toBeResumed : 1; /* true if this thread was successfully suspended. */
69 unsigned int pendingInterrupt : 1; /* true if thread is interrupted while handling an event. */
70 unsigned int isDebugThread : 1; /* true if this is one of our debug agent threads. */
71 unsigned int suspendOnStart : 1; /* true for new threads if we are currently in a VM.suspend(). */
72 unsigned int isStarted : 1; /* THREAD_START or VIRTUAL_THREAD_SCHEDULED event received. */
73 unsigned int popFrameEvent : 1;
74 unsigned int popFrameProceed : 1;
75 unsigned int popFrameThread : 1;
76 unsigned int handlingAppResume : 1;
77 EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */
78 jobject pendingStop; /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */
79 jint suspendCount;
80 jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */
81 jvmtiEventMode instructionStepMode;
82 StepRequest currentStep;
83 InvokeRequest currentInvoke;
84 struct bag *eventBag; /* Accumulation of JDWP events to be sent as a reply. */
85 CoLocatedEventInfo cleInfo; /* See comment above deferEventReport() for an explanation. */
86 struct ThreadNode *next;
87 struct ThreadNode *prev;
88 jlong frameGeneration; /* used to generate a unique frameID. Incremented whenever existing frameID
89 needs to be invalidated, such as when the thread is resumed. */
90 struct ThreadList *list; /* Tells us what list this thread is in. */
91#ifdef DEBUG_THREADNAME
92 char name[256];
93#endif
94} ThreadNode;
95
96static jint suspendAllCount;
97
98typedef struct ThreadList {
99 ThreadNode *first;
100} ThreadList;
101
102/*
103 * popFrameEventLock is used to notify that the event has been received
104 */
105static jrawMonitorID popFrameEventLock = NULL((void*)0);
106
107/*
108 * popFrameProceedLock is used to assure that the event thread is
109 * re-suspended immediately after the event is acknowledged.
110 */
111static jrawMonitorID popFrameProceedLock = NULL((void*)0);
112
113static jrawMonitorID threadLock;
114static jlocation resumeLocation;
115static HandlerNode *breakpointHandlerNode;
116static HandlerNode *framePopHandlerNode;
117static HandlerNode *catchHandlerNode;
118
119static jvmtiError threadControl_removeDebugThread(jthread thread);
120
121/*
122 * Threads which have issued thread start events and not yet issued thread
123 * end events are maintained in the "runningThreads" list. All other threads known
124 * to this module are kept in the "otherThreads" list.
125 */
126static ThreadList runningThreads;
127static ThreadList otherThreads;
128
129#define MAX_DEBUG_THREADS10 10
130static int debugThreadCount;
131static jthread debugThreads[MAX_DEBUG_THREADS10];
132
133typedef struct DeferredEventMode {
134 EventIndex ei;
135 jvmtiEventMode mode;
136 jthread thread;
137 struct DeferredEventMode *next;
138} DeferredEventMode;
139
140typedef struct {
141 DeferredEventMode *first;
142 DeferredEventMode *last;
143} DeferredEventModeList;
144
145static DeferredEventModeList deferredEventModes;
146
147#ifdef DEBUG1
148static void dumpThreadList(ThreadList *list);
149static void dumpThread(ThreadNode *node);
150#endif
151
152static jint
153getStackDepth(jthread thread)
154{
155 jint count = 0;
156 jvmtiError error;
157
158 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,158), log_message_end ("%s()","GetFrameCount")):((void)0)),(
gdata->jvmti))))->GetFrameCount))
159 (gdata->jvmti, thread, &count);
160 if (error != JVMTI_ERROR_NONE) {
161 EXIT_ERROR(error, "getting frame count"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)error), error, ("getting frame count"
==((void*)0)?"":"getting frame count"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 161); debugInit_exit((jvmtiError)error, "getting frame count"
); }
;
162 }
163 return count;
164}
165
166/* Get the state of the thread direct from JVMTI */
167static jvmtiError
168threadState(jthread thread, jint *pstate)
169{
170 *pstate = 0;
171 return JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,171), log_message_end ("%s()","GetThreadState")):((void)0)),
(gdata->jvmti))))->GetThreadState))
172 (gdata->jvmti, thread, pstate);
173}
174
175/* Set TLS on a specific jthread to the ThreadNode* */
176static void
177setThreadLocalStorage(jthread thread, ThreadNode *node)
178{
179 jvmtiError error;
180
181 error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,181), log_message_end ("%s()","SetThreadLocalStorage")):((void
)0)),(gdata->jvmti))))->SetThreadLocalStorage))
182 (gdata->jvmti, thread, (void*)node);
183 if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE && node == NULL((void*)0)) {
184 /* Just return. This can happen when clearing the TLS. */
185 return;
186 } else if ( error != JVMTI_ERROR_NONE ) {
187 /* The jthread object must be valid, so this must be a fatal error */
188 EXIT_ERROR(error, "cannot set thread local storage"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)error), error, ("cannot set thread local storage"
==((void*)0)?"":"cannot set thread local storage"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 188); debugInit_exit((jvmtiError)error, "cannot set thread local storage"
); }
;
189 }
190}
191
192/* Get TLS on a specific jthread, which is the ThreadNode* */
193static ThreadNode *
194getThreadLocalStorage(jthread thread)
195{
196 jvmtiError error;
197 ThreadNode *node;
198
199 node = NULL((void*)0);
200 error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadLocalStorage)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,200), log_message_end ("%s()","GetThreadLocalStorage")):((void
)0)),(gdata->jvmti))))->GetThreadLocalStorage))
201 (gdata->jvmti, thread, (void**)&node);
202 if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
203 /* Just return NULL, thread hasn't started yet */
204 return NULL((void*)0);
205 } else if ( error != JVMTI_ERROR_NONE ) {
206 /* The jthread object must be valid, so this must be a fatal error */
207 EXIT_ERROR(error, "cannot get thread local storage"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)error), error, ("cannot get thread local storage"
==((void*)0)?"":"cannot get thread local storage"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 207); debugInit_exit((jvmtiError)error, "cannot get thread local storage"
); }
;
208 }
209 return node;
210}
211
212/* Search list for nodes that don't have TLS set and match this thread.
213 * It assumed that this logic is never dealing with terminated threads,
214 * since the ThreadEnd events always delete the ThreadNode while the
215 * jthread is still alive. So we can only look at the ThreadNode's that
216 * have never had their TLS set, making the search much faster.
217 * But keep in mind, this kind of search should rarely be needed.
218 */
219static ThreadNode *
220nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
221{
222 ThreadNode *node;
223
224 for (node = list->first; node != NULL((void*)0); node = node->next) {
225 if (isSameObject(env, node->thread, thread)) {
226 break;
227 }
228 }
229 return node;
230}
231
232/*
233 * These functions maintain the linked list of currently running threads.
234 * All assume that the threadLock is held before calling.
235 */
236
237/*
238 * Search for a thread on the list. If list==NULL, search all lists.
239 */
240static ThreadNode *
241findThread(ThreadList *list, jthread thread)
242{
243 ThreadNode *node;
244
245 /* Get thread local storage for quick thread -> node access */
246 node = getThreadLocalStorage(thread);
247
248 if ( node == NULL((void*)0) ) {
249 /*
250 * If the thread was not yet started when the ThreadNode was created, then it
251 * got added to the otherThreads list and its thread local storage was not set.
252 * Search for it in the otherThreads list.
253 */
254 if ( list == NULL((void*)0) || list == &otherThreads ) {
255 node = nonTlsSearch(getEnv(), &otherThreads, thread);
256 }
257 /*
258 * Normally we can assume that a thread with no TLS will never be in the runningThreads
259 * list. This is because we always set the TLS when adding to runningThreads.
260 * However, when a thread exits, its TLS is automatically cleared. Normally this
261 * is not a problem because the debug agent will first get a THREAD_END event,
262 * and that will cause the thread to be removed from runningThreads, thus we
263 * avoid this situation of having a thread in runningThreads, but with no TLS.
264 *
265 * However... there is one exception to this. While handling VM_DEATH, the first thing
266 * the debug agent does is clear all the callbacks. This means we will no longer
267 * get THREAD_END events as threads exit. This means we might find threads on
268 * runningThreads with no TLS during VM_DEATH. Essentially the THREAD_END that
269 * would normally have resulted in removing the thread from runningThreads is
270 * missed, so the thread remains on runningThreads.
271 *
272 * The end result of all this is that if the TLS lookup failed, we still need to check
273 * if the thread is on runningThreads, but only if JVMTI callbacks have been cleared.
274 * Otherwise the thread should not be on the runningThreads.
275 */
276 if ( !gdata->jvmtiCallBacksCleared ) {
277 /* The thread better not be on runningThreads if the TLS lookup failed. */
278 JDI_ASSERT(!nonTlsSearch(getEnv(), &runningThreads, thread))do { if (gdata && gdata->assertOn && !(!nonTlsSearch
(getEnv(), &runningThreads, thread))) { jdiAssertionFailed
("/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 278, "!nonTlsSearch(getEnv(), &runningThreads, thread)"
); } } while (0)
;
279 } else {
280 /*
281 * Search the runningThreads list. The TLS lookup may have failed because the
282 * thread has terminated, but we never got the THREAD_END event.
283 */
284 if ( node == NULL((void*)0) ) {
285 if ( list == NULL((void*)0) || list == &runningThreads ) {
286 node = nonTlsSearch(getEnv(), &runningThreads, thread);
287 }
288 }
289 }
290 }
291
292 /* If a list is supplied, only return ones in this list */
293 if ( node != NULL((void*)0) && list != NULL((void*)0) && node->list != list ) {
294 return NULL((void*)0);
295 }
296 return node;
297}
298
299/* Remove a ThreadNode from a ThreadList */
300static void
301removeNode(ThreadList *list, ThreadNode *node)
302{
303 ThreadNode *prev;
304 ThreadNode *next;
305
306 prev = node->prev;
307 next = node->next;
308 if ( prev != NULL((void*)0) ) {
309 prev->next = next;
310 }
311 if ( next != NULL((void*)0) ) {
312 next->prev = prev;
313 }
314 if ( prev == NULL((void*)0) ) {
315 list->first = next;
316 }
317 node->next = NULL((void*)0);
318 node->prev = NULL((void*)0);
319 node->list = NULL((void*)0);
320}
321
322/* Add a ThreadNode to a ThreadList */
323static void
324addNode(ThreadList *list, ThreadNode *node)
325{
326 node->next = NULL((void*)0);
327 node->prev = NULL((void*)0);
328 node->list = NULL((void*)0);
329 if ( list->first == NULL((void*)0) ) {
330 list->first = node;
331 } else {
332 list->first->prev = node;
333 node->next = list->first;
334 list->first = node;
335 }
336 node->list = list;
337}
338
339static ThreadNode *
340insertThread(JNIEnv *env, ThreadList *list, jthread thread)
341{
342 ThreadNode *node;
343 struct bag *eventBag;
344
345 node = findThread(list, thread);
346 if (node == NULL((void*)0)) {
347 node = jvmtiAllocate(sizeof(*node));
348 if (node == NULL((void*)0)) {
349 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("thread table entry"
==((void*)0)?"":"thread table entry"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 349); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "thread table entry"); }
;
350 return NULL((void*)0);
351 }
352 (void)memset(node, 0, sizeof(*node));
353 eventBag = eventHelper_createEventBag();
354 if (eventBag == NULL((void*)0)) {
355 jvmtiDeallocate(node);
356 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("thread table entry"
==((void*)0)?"":"thread table entry"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 356); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "thread table entry"); }
;
357 return NULL((void*)0);
358 }
359
360 /*
361 * Init all flags false, all refs NULL, all counts 0
362 */
363
364 saveGlobalRef(env, thread, &(node->thread));
365 if (node->thread == NULL((void*)0)) {
366 jvmtiDeallocate(node);
367 bagDestroyBag(eventBag);
368 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("thread table entry"
==((void*)0)?"":"thread table entry"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 368); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "thread table entry"); }
;
369 return NULL((void*)0);
370 }
371 /*
372 * Remember if it is a debug thread
373 */
374 if (threadControl_isDebugThread(node->thread)) {
375 node->isDebugThread = JNI_TRUE1;
376 } else if (suspendAllCount > 0){
377 /*
378 * If there is a pending suspendAll, all new threads should
379 * be initialized as if they were suspended by the suspendAll,
380 * and the thread will need to be suspended when it starts.
381 */
382 node->suspendCount = suspendAllCount;
383 node->suspendOnStart = JNI_TRUE1;
384 }
385 node->current_ei = 0;
386 node->instructionStepMode = JVMTI_DISABLE;
387 node->eventBag = eventBag;
388 addNode(list, node);
389
390#ifdef DEBUG_THREADNAME
391 {
392 /* Set the thread name */
393 jvmtiThreadInfo info;
394 jvmtiError error;
395
396 memset(&info, 0, sizeof(info));
397 error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,397), log_message_end ("%s()","GetThreadInfo")):((void)0)),(
gdata->jvmti))))->GetThreadInfo))
398 (gdata->jvmti, node->thread, &info);
399 if (info.name != NULL((void*)0)) {
400 strncpy(node->name, info.name, sizeof(node->name) - 1);
401 jvmtiDeallocate(info.name);
402 }
403 }
404#endif
405
406 /* Set thread local storage for quick thread -> node access.
407 * Threads that are not yet started do not allow setting of TLS. These
408 * threads go on the otherThreads list and have their TLS set
409 * when moved to the runningThreads list. findThread() knows to look
410 * on otherThreads when the TLS lookup fails.
411 */
412 if (list != &otherThreads) {
413 setThreadLocalStorage(node->thread, (void*)node);
414 }
415 }
416
417 return node;
418}
419
420static void
421clearThread(JNIEnv *env, ThreadNode *node)
422{
423 if (node->pendingStop != NULL((void*)0)) {
424 tossGlobalRef(env, &(node->pendingStop));
425 }
426 stepControl_clearRequest(node->thread, &node->currentStep);
427 if (node->isDebugThread) {
428 (void)threadControl_removeDebugThread(node->thread);
429 }
430 /* Clear out TLS on this thread (just a cleanup action) */
431 setThreadLocalStorage(node->thread, NULL((void*)0));
432 tossGlobalRef(env, &(node->thread));
433 bagDestroyBag(node->eventBag);
434 jvmtiDeallocate(node);
435}
436
437static void
438removeThread(JNIEnv *env, ThreadList *list, jthread thread)
439{
440 ThreadNode *node;
441
442 node = findThread(list, thread);
443 if (node != NULL((void*)0)) {
444 removeNode(list, node);
445 clearThread(env, node);
446 }
447}
448
449static void
450removeResumed(JNIEnv *env, ThreadList *list)
451{
452 ThreadNode *node;
453
454 node = list->first;
455 while (node != NULL((void*)0)) {
456 ThreadNode *temp = node->next;
457 if (node->suspendCount == 0) {
458 removeThread(env, list, node->thread);
459 }
460 node = temp;
461 }
462}
463
464static void
465moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node)
466{
467 removeNode(source, node);
468 JDI_ASSERT(findThread(dest, node->thread) == NULL)do { if (gdata && gdata->assertOn && !(findThread
(dest, node->thread) == ((void*)0))) { jdiAssertionFailed(
"/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 468, "findThread(dest, node->thread) == NULL"); } } while
(0)
;
469 addNode(dest, node);
470}
471
472typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);
473
474static jvmtiError
475enumerateOverThreadList(JNIEnv *env, ThreadList *list,
476 ThreadEnumerateFunction function, void *arg)
477{
478 ThreadNode *node;
479 jvmtiError error = JVMTI_ERROR_NONE;
480
481 for (node = list->first; node != NULL((void*)0); node = node->next) {
482 error = (*function)(env, node, arg);
483 if ( error != JVMTI_ERROR_NONE ) {
484 break;
485 }
486 }
487 return error;
488}
489
490static void
491insertEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode)
492{
493 if (list->last != NULL((void*)0)) {
494 list->last->next = eventMode;
495 } else {
496 list->first = eventMode;
497 }
498 list->last = eventMode;
499}
500
501static void
502removeEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode, DeferredEventMode *prev)
503{
504 if (prev == NULL((void*)0)) {
505 list->first = eventMode->next;
506 } else {
507 prev->next = eventMode->next;
508 }
509 if (eventMode->next == NULL((void*)0)) {
510 list->last = prev;
511 }
512}
513
514static jvmtiError
515addDeferredEventMode(JNIEnv *env, jvmtiEventMode mode, EventIndex ei, jthread thread)
516{
517 DeferredEventMode *eventMode;
518
519 /*LINTED*/
520 eventMode = jvmtiAllocate((jint)sizeof(DeferredEventMode));
521 if (eventMode == NULL((void*)0)) {
522 return AGENT_ERROR_OUT_OF_MEMORY((jvmtiError)(JVMTI_ERROR_MAX+64+8));
523 }
524 eventMode->thread = NULL((void*)0);
525 saveGlobalRef(env, thread, &(eventMode->thread));
526 eventMode->mode = mode;
527 eventMode->ei = ei;
528 eventMode->next = NULL((void*)0);
529 insertEventMode(&deferredEventModes, eventMode);
530 return JVMTI_ERROR_NONE;
531}
532
533static void
534freeDeferredEventModes(JNIEnv *env)
535{
536 DeferredEventMode *eventMode;
537 eventMode = deferredEventModes.first;
538 while (eventMode != NULL((void*)0)) {
539 DeferredEventMode *next;
540 next = eventMode->next;
541 tossGlobalRef(env, &(eventMode->thread));
542 jvmtiDeallocate(eventMode);
543 eventMode = next;
544 }
545 deferredEventModes.first = NULL((void*)0);
546 deferredEventModes.last = NULL((void*)0);
547}
548
549static jvmtiError
550threadSetEventNotificationMode(ThreadNode *node,
551 jvmtiEventMode mode, EventIndex ei, jthread thread)
552{
553 jvmtiError error;
554
555 /* record single step mode */
556 if (ei == EI_SINGLE_STEP) {
557 node->instructionStepMode = mode;
558 }
559 error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,559), log_message_end ("%s()","SetEventNotificationMode")):(
(void)0)),(gdata->jvmti))))->SetEventNotificationMode))
560 (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
561 return error;
562}
563
564static void
565processDeferredEventModes(JNIEnv *env, jthread thread, ThreadNode *node)
566{
567 jvmtiError error;
568 DeferredEventMode *eventMode;
569 DeferredEventMode *prev;
570
571 prev = NULL((void*)0);
572 eventMode = deferredEventModes.first;
573 while (eventMode != NULL((void*)0)) {
574 DeferredEventMode *next = eventMode->next;
575 if (isSameObject(env, thread, eventMode->thread)) {
576 error = threadSetEventNotificationMode(node,
577 eventMode->mode, eventMode->ei, eventMode->thread);
578 if (error != JVMTI_ERROR_NONE) {
579 EXIT_ERROR(error, "cannot process deferred thread event notifications at thread start"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)error), error, ("cannot process deferred thread event notifications at thread start"
==((void*)0)?"":"cannot process deferred thread event notifications at thread start"
), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 579); debugInit_exit((jvmtiError)error, "cannot process deferred thread event notifications at thread start"
); }
;
580 }
581 removeEventMode(&deferredEventModes, eventMode, prev);
582 tossGlobalRef(env, &(eventMode->thread));
583 jvmtiDeallocate(eventMode);
584 } else {
585 prev = eventMode;
586 }
587 eventMode = next;
588 }
589}
590
591static void
592getLocks(void)
593{
594 /*
595 * Anything which might be locked as part of the handling of
596 * a JVMTI event (which means: might be locked by an application
597 * thread) needs to be grabbed here. This allows thread control
598 * code to safely suspend and resume the application threads
599 * while ensuring they don't hold a critical lock.
600 */
601
602 eventHandler_lock();
603 invoker_lock();
604 eventHelper_lock();
605 stepControl_lock();
606 commonRef_lock();
607 debugMonitorEnter(threadLock);
608
609}
610
611static void
612releaseLocks(void)
613{
614 debugMonitorExit(threadLock);
615 commonRef_unlock();
616 stepControl_unlock();
617 eventHelper_unlock();
618 invoker_unlock();
619 eventHandler_unlock();
620}
621
622void
623threadControl_initialize(void)
624{
625 jlocation unused;
626 jvmtiError error;
627
628 suspendAllCount = 0;
629 runningThreads.first = NULL((void*)0);
630 otherThreads.first = NULL((void*)0);
631 debugThreadCount = 0;
632 threadLock = debugMonitorCreate("JDWP Thread Lock");
633 if (gdata->threadClass==NULL((void*)0)) {
634 EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("no java.lang.thread class"
==((void*)0)?"":"no java.lang.thread class"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 634); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "no java.lang.thread class"); }
;
635 }
636 if (gdata->threadResume==0) {
637 EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("cannot resume thread"
==((void*)0)?"":"cannot resume thread"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 637); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "cannot resume thread"); }
;
638 }
639 /* Get the java.lang.Thread.resume() method beginning location */
640 error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
641 if (error != JVMTI_ERROR_NONE) {
642 EXIT_ERROR(error, "getting method location"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)error), error, ("getting method location"
==((void*)0)?"":"getting method location"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 642); debugInit_exit((jvmtiError)error, "getting method location"
); }
;
643 }
644}
645
646static jthread
647getResumee(jthread resumingThread)
648{
649 jthread resumee = NULL((void*)0);
650 jvmtiError error;
651 jobject object;
652 FrameNumber fnum = 0;
653
654 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,654), log_message_end ("%s()","GetLocalObject")):((void)0)),
(gdata->jvmti))))->GetLocalObject))
655 (gdata->jvmti, resumingThread, fnum, 0, &object);
656 if (error == JVMTI_ERROR_NONE) {
657 resumee = object;
658 }
659 return resumee;
660}
661
662
663static jboolean
664pendingAppResume(jboolean includeSuspended)
665{
666 ThreadList *list;
667 ThreadNode *node;
668
669 list = &runningThreads;
670 node = list->first;
671 while (node != NULL((void*)0)) {
672 if (node->resumeFrameDepth > 0) {
673 if (includeSuspended) {
674 return JNI_TRUE1;
675 } else {
676 jvmtiError error;
677 jint state;
678
679 error = threadState(node->thread, &state);
680 if (error != JVMTI_ERROR_NONE) {
681 EXIT_ERROR(error, "getting thread state"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)error), error, ("getting thread state"
==((void*)0)?"":"getting thread state"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 681); debugInit_exit((jvmtiError)error, "getting thread state"
); }
;
682 }
683 /* !node->handlingAppResume && resumeFrameDepth > 0
684 * means the thread has entered Thread.resume() */
685 if (!(state & JVMTI_THREAD_STATE_SUSPENDED) &&
686 !node->handlingAppResume) {
687 return JNI_TRUE1;
688 }
689 }
690 }
691 node = node->next;
692 }
693 return JNI_FALSE0;
694}
695
696static void
697notifyAppResumeComplete(void)
698{
699 debugMonitorNotifyAll(threadLock);
700 if (!pendingAppResume(JNI_TRUE1)) {
701 if (framePopHandlerNode != NULL((void*)0)) {
702 (void)eventHandler_free(framePopHandlerNode);
703 framePopHandlerNode = NULL((void*)0);
704 }
705 if (catchHandlerNode != NULL((void*)0)) {
706 (void)eventHandler_free(catchHandlerNode);
707 catchHandlerNode = NULL((void*)0);
708 }
709 }
710}
711
712/*
713 * Event handler for FRAME_POP and EXCEPTION_CATCH when in Thread.resume()
714 * so we can detect its completion.
715 */
716static void
717handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
718 HandlerNode *handlerNode,
719 struct bag *eventBag)
720{
721 ThreadNode *node;
722 jthread thread;
723
724 thread = evinfo->thread;
725
726 debugMonitorEnter(threadLock);
727
728 node = findThread(&runningThreads, thread);
729 if (node != NULL((void*)0)) {
730 if (node->resumeFrameDepth > 0) {
731 jint compareDepth = getStackDepth(thread);
732 if (evinfo->ei == EI_FRAME_POP) {
733 compareDepth--;
734 }
735 if (compareDepth < node->resumeFrameDepth) {
736 node->resumeFrameDepth = 0;
737 notifyAppResumeComplete();
738 }
739 }
740 }
741
742 debugMonitorExit(threadLock);
743}
744
745static void
746blockOnDebuggerSuspend(jthread thread)
747{
748 ThreadNode *node;
749
750 node = findThread(NULL((void*)0), thread);
751 if (node != NULL((void*)0)) {
752 while (node && node->suspendCount > 0) {
753 debugMonitorWait(threadLock);
754 node = findThread(NULL((void*)0), thread);
755 }
756 }
757}
758
759/*
760 * The caller is expected to hold threadLock and handlerLock.
761 * eventHandler_createInternalThreadOnly() can deadlock because of
762 * wrong lock ordering if the caller does not hold handlerLock.
763 */
764static void
765trackAppResume(jthread thread)
766{
767 jvmtiError error;
768 FrameNumber fnum;
769 ThreadNode *node;
770
771 fnum = 0;
772 node = findThread(&runningThreads, thread);
773 if (node != NULL((void*)0)) {
774 JDI_ASSERT(node->resumeFrameDepth == 0)do { if (gdata && gdata->assertOn && !(node
->resumeFrameDepth == 0)) { jdiAssertionFailed("/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 774, "node->resumeFrameDepth == 0"); } } while (0)
;
775 error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,775), log_message_end ("%s()","NotifyFramePop")):((void)0)),
(gdata->jvmti))))->NotifyFramePop))
776 (gdata->jvmti, thread, fnum);
777 if (error == JVMTI_ERROR_NONE) {
778 jint frameDepth = getStackDepth(thread);
779 if ((frameDepth > 0) && (framePopHandlerNode == NULL((void*)0))) {
780 framePopHandlerNode = eventHandler_createInternalThreadOnly(
781 EI_FRAME_POP,
782 handleAppResumeCompletion,
783 thread);
784 catchHandlerNode = eventHandler_createInternalThreadOnly(
785 EI_EXCEPTION_CATCH,
786 handleAppResumeCompletion,
787 thread);
788 if ((framePopHandlerNode == NULL((void*)0)) ||
789 (catchHandlerNode == NULL((void*)0))) {
790 (void)eventHandler_free(framePopHandlerNode);
791 framePopHandlerNode = NULL((void*)0);
792 (void)eventHandler_free(catchHandlerNode);
793 catchHandlerNode = NULL((void*)0);
794 }
795 }
796 if ((framePopHandlerNode != NULL((void*)0)) &&
797 (catchHandlerNode != NULL((void*)0)) &&
798 (frameDepth > 0)) {
799 node->resumeFrameDepth = frameDepth;
800 }
801 }
802 }
803}
804
805/* Global breakpoint handler for Thread.resume() */
806static void
807handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo,
808 HandlerNode *handlerNode,
809 struct bag *eventBag)
810{
811 jthread resumer = evinfo->thread;
812
813 debugMonitorEnter(threadLock);
814
815 /*
816 * Actual handling has to be deferred. We cannot block right here if the
817 * target of the resume call is suspended by the debugger since we are
818 * holding handlerLock which must not be released. See doPendingTasks().
819 */
820 if (resumer != NULL((void*)0)) {
821 ThreadNode* node = findThread(&runningThreads, resumer);
822 if (node != NULL((void*)0)) {
823 node->handlingAppResume = JNI_TRUE1;
824 }
825 }
826
827 debugMonitorExit(threadLock);
828}
829
830void
831threadControl_onConnect(void)
832{
833 breakpointHandlerNode = eventHandler_createInternalBreakpoint(
834 handleAppResumeBreakpoint, NULL((void*)0),
835 gdata->threadClass, gdata->threadResume, resumeLocation);
836}
837
838void
839threadControl_onDisconnect(void)
840{
841 if (breakpointHandlerNode != NULL((void*)0)) {
842 (void)eventHandler_free(breakpointHandlerNode);
843 breakpointHandlerNode = NULL((void*)0);
844 }
845 if (framePopHandlerNode != NULL((void*)0)) {
846 (void)eventHandler_free(framePopHandlerNode);
847 framePopHandlerNode = NULL((void*)0);
848 }
849 if (catchHandlerNode != NULL((void*)0)) {
850 (void)eventHandler_free(catchHandlerNode);
851 catchHandlerNode = NULL((void*)0);
852 }
853}
854
855void
856threadControl_onHook(void)
857{
858 /*
859 * As soon as the event hook is in place, we need to initialize
860 * the thread list with already-existing threads. The threadLock
861 * has been held since initialize, so we don't need to worry about
862 * insertions or deletions from the event handlers while we do this
863 */
864 JNIEnv *env;
865
866 env = getEnv();
867
868 /*
869 * Prevent any event processing until OnHook has been called
870 */
871 debugMonitorEnter(threadLock);
872
873 WITH_LOCAL_REFS(env, 1)createLocalRefSpace(env, 1); { {
874
875 jint threadCount;
876 jthread *threads;
877
878 threads = allThreads(&threadCount);
879 if (threads == NULL((void*)0)) {
880 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("thread table"==
((void*)0)?"":"thread table"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 880); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "thread table"); }
;
881 } else {
882
883 int i;
884
885 for (i = 0; i < threadCount; i++) {
886 ThreadNode *node;
887 jthread thread = threads[i];
888 node = insertThread(env, &runningThreads, thread);
889
890 /*
891 * This is a tiny bit risky. We have to assume that the
892 * pre-existing threads have been started because we
893 * can't rely on a thread start event for them. The chances
894 * of a problem related to this are pretty slim though, and
895 * there's really no choice because without setting this flag
896 * there is no way to enable stepping and other events on
897 * the threads that already exist (e.g. the finalizer thread).
898 */
899 node->isStarted = JNI_TRUE1;
900 }
901 jvmtiDeallocate(threads);
902 }
903
904 } END_WITH_LOCAL_REFS(env)(*((*((((gdata->log_flags & (0x00000002)) ?(log_message_begin
("JNI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,904), log_message_end ("%s()","PopLocalFrame")):((void)0)), (
env))))->PopLocalFrame))(env, ((void*)0)); }
905
906 debugMonitorExit(threadLock);
907}
908
909static jvmtiError
910commonSuspendByNode(ThreadNode *node)
911{
912 jvmtiError error;
913
914 LOG_MISC(("thread=%p suspended", node->thread))((gdata->log_flags & (0x00000008)) ?(log_message_begin
("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,914), log_message_end ("thread=%p suspended", node->thread
)):((void)0))
;
915 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,915), log_message_end ("%s()","SuspendThread")):((void)0)),(
gdata->jvmti))))->SuspendThread))
916 (gdata->jvmti, node->thread);
917
918 /*
919 * Mark for resume only if suspend succeeded
920 */
921 if (error == JVMTI_ERROR_NONE) {
922 node->toBeResumed = JNI_TRUE1;
923 }
924
925 /*
926 * If the thread was suspended by another app thread,
927 * do nothing and report no error (we won't resume it later).
928 */
929 if (error == JVMTI_ERROR_THREAD_SUSPENDED) {
930 error = JVMTI_ERROR_NONE;
931 }
932
933 return error;
934}
935
936/*
937 * Deferred suspends happen when the suspend is attempted on a thread
938 * that is not started. Bookkeeping (suspendCount,etc.)
939 * is handled by the original request, and once the thread actually
940 * starts, an actual suspend is attempted. This function does the
941 * deferred suspend without changing the bookkeeping that is already
942 * in place.
943 */
944static jint
945deferredSuspendThreadByNode(ThreadNode *node)
946{
947 jvmtiError error;
948
949 error = JVMTI_ERROR_NONE;
950 if (node->isDebugThread) {
951 /* Ignore requests for suspending debugger threads */
952 return JVMTI_ERROR_NONE;
953 }
954
955 /*
956 * Do the actual suspend only if a subsequent resume hasn't
957 * made it irrelevant.
958 */
959 if (node->suspendCount > 0) {
960 error = commonSuspendByNode(node);
961
962 /*
963 * Attempt to clean up from any error by decrementing the
964 * suspend count. This compensates for the increment that
965 * happens when suspendOnStart is set to true.
966 */
967 if (error != JVMTI_ERROR_NONE) {
968 node->suspendCount--;
969 }
970 }
971
972 node->suspendOnStart = JNI_FALSE0;
973
974 debugMonitorNotifyAll(threadLock);
975
976 return error;
977}
978
979static jvmtiError
980suspendThreadByNode(ThreadNode *node)
981{
982 jvmtiError error = JVMTI_ERROR_NONE;
983 if (node->isDebugThread) {
984 /* Ignore requests for suspending debugger threads */
985 return JVMTI_ERROR_NONE;
986 }
987
988 /*
989 * Just increment the suspend count if we are waiting
990 * for a deferred suspend.
991 */
992 if (node->suspendOnStart) {
993 node->suspendCount++;
994 return JVMTI_ERROR_NONE;
995 }
996
997 if (node->suspendCount == 0) {
998 error = commonSuspendByNode(node);
999
1000 if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1001 /*
1002 * This error means that the thread is either a zombie or not yet
1003 * started. In either case, we ignore the error. If the thread
1004 * is a zombie, suspend/resume are no-ops. If the thread is not
1005 * started, it will be suspended for real during the processing
1006 * of its thread start event.
1007 */
1008 node->suspendOnStart = JNI_TRUE1;
1009 error = JVMTI_ERROR_NONE;
1010 }
1011 }
1012
1013 if (error == JVMTI_ERROR_NONE) {
1014 node->suspendCount++;
1015 }
1016
1017 debugMonitorNotifyAll(threadLock);
1018
1019 return error;
1020}
1021
1022static jvmtiError
1023resumeThreadByNode(ThreadNode *node)
1024{
1025 jvmtiError error = JVMTI_ERROR_NONE;
1026
1027 if (node->isDebugThread) {
1028 /* never suspended by debugger => don't ever try to resume */
1029 return JVMTI_ERROR_NONE;
1030 }
1031 if (node->suspendCount > 0) {
1032 node->suspendCount--;
1033 debugMonitorNotifyAll(threadLock);
1034 if ((node->suspendCount == 0) && node->toBeResumed &&
1035 !node->suspendOnStart) {
1036 LOG_MISC(("thread=%p resumed", node->thread))((gdata->log_flags & (0x00000008)) ?(log_message_begin
("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1036), log_message_end ("thread=%p resumed", node->thread
)):((void)0))
;
1037 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1037), log_message_end ("%s()","ResumeThread")):((void)0)),(
gdata->jvmti))))->ResumeThread))
1038 (gdata->jvmti, node->thread);
1039 node->frameGeneration++; /* Increment on each resume */
1040 node->toBeResumed = JNI_FALSE0;
1041 if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
1042 /*
1043 * We successfully "suspended" this thread, but
1044 * we never received a THREAD_START event for it.
1045 * Since the thread never ran, we can ignore our
1046 * failure to resume the thread.
1047 */
1048 error = JVMTI_ERROR_NONE;
1049 }
1050 }
1051 }
1052
1053 return error;
1054}
1055
1056/*
1057 * Functions which respond to user requests to suspend/resume
1058 * threads.
1059 * Suspends and resumes add and subtract from a count respectively.
1060 * The thread is only suspended when the count goes from 0 to 1 and
1061 * resumed only when the count goes from 1 to 0.
1062 *
1063 * These functions suspend and resume application threads
1064 * without changing the
1065 * state of threads that were already suspended beforehand.
1066 * They must not be called from an application thread because
1067 * that thread may be suspended somewhere in the middle of things.
1068 */
1069static void
1070preSuspend(void)
1071{
1072 getLocks(); /* Avoid debugger deadlocks */
1073
1074 /*
1075 * Delay any suspend while a call to java.lang.Thread.resume is in
1076 * progress (not including those in suspended threads). The wait is
1077 * timed because the threads suspended through
1078 * java.lang.Thread.suspend won't result in a notify even though
1079 * it may change the result of pendingAppResume()
1080 */
1081 while (pendingAppResume(JNI_FALSE0)) {
1082 /*
1083 * This is ugly but we need to release the locks from getLocks
1084 * or else the notify will never happen. The locks must be
1085 * released and reacquired in the right order. else deadlocks
1086 * can happen. It is possible that, during this dance, the
1087 * notify will be missed, but since the wait needs to be timed
1088 * anyway, it won't be a disaster. Note that this code will
1089 * execute only on very rare occasions anyway.
1090 */
1091 releaseLocks();
1092
1093 debugMonitorEnter(threadLock);
1094 debugMonitorTimedWait(threadLock, 1000);
1095 debugMonitorExit(threadLock);
1096
1097 getLocks();
1098 }
1099}
1100
1101static void
1102postSuspend(void)
1103{
1104 releaseLocks();
1105}
1106
1107/*
1108 * This function must be called after preSuspend and before postSuspend.
1109 */
1110static jvmtiError
1111commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1112{
1113 ThreadNode *node;
1114
1115 /*
1116 * If the thread is not between its start and end events, we should
1117 * still suspend it. To keep track of things, add the thread
1118 * to a separate list of threads so that we'll resume it later.
1119 */
1120 node = findThread(&runningThreads, thread);
1121#if 0
1122 tty_message("commonSuspend: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1123#endif
1124 if (node == NULL((void*)0)) {
1125 node = insertThread(env, &otherThreads, thread);
1126 }
1127
1128 if ( deferred ) {
1129 return deferredSuspendThreadByNode(node);
1130 } else {
1131 return suspendThreadByNode(node);
1132 }
1133}
1134
1135
1136static jvmtiError
1137resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1138{
1139 if (node->isDebugThread) {
1140 /* never suspended by debugger => don't ever try to resume */
1141 return JVMTI_ERROR_NONE;
1142 }
1143
1144 if (node->suspendCount > 1) {
1145 node->suspendCount--;
1146 /* nested suspend so just undo one level */
1147 return JVMTI_ERROR_NONE;
1148 }
1149
1150 /*
1151 * This thread was marked for suspension since its THREAD_START
1152 * event came in during a suspendAll, but the helper hasn't
1153 * completed the job yet. We decrement the count so the helper
1154 * won't suspend this thread after we are done with the resumeAll.
1155 * Another case to be handled here is when the debugger suspends
1156 * the thread while the app has it suspended. In this case,
1157 * the toBeResumed flag has been cleared indicating that
1158 * the thread should not be resumed when the debugger does a resume.
1159 * In this case, we also have to decrement the suspend count.
1160 * If we don't then when the app resumes the thread and our Thread.resume
1161 * bkpt handler is called, blockOnDebuggerSuspend will not resume
1162 * the thread because suspendCount will be 1 meaning that the
1163 * debugger has the thread suspended. See bug 6224859.
1164 */
1165 if (node->suspendCount == 1 && (!node->toBeResumed || node->suspendOnStart)) {
1166 node->suspendCount--;
1167 return JVMTI_ERROR_NONE;
1168 }
1169
1170 if (arg == NULL((void*)0)) {
1171 /* nothing to hard resume so we're done */
1172 return JVMTI_ERROR_NONE;
1173 }
1174
1175 /*
1176 * This is tricky. A suspendCount of 1 and toBeResumed means that
1177 * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1178 * on this thread. The check for !suspendOnStart is paranoia that
1179 * we inherited from resumeThreadByNode().
1180 */
1181 if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1182 jthread **listPtr = (jthread **)arg;
1183
1184 **listPtr = node->thread;
1185 (*listPtr)++;
1186 }
1187 return JVMTI_ERROR_NONE;
1188}
1189
1190
1191static jvmtiError
1192resumeCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1193{
1194 if (node->isDebugThread) {
1195 /* never suspended by debugger => don't ever try to resume */
1196 return JVMTI_ERROR_NONE;
1197 }
1198
1199 /*
1200 * This is tricky. A suspendCount of 1 and toBeResumed means that
1201 * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1202 * on this thread. The check for !suspendOnStart is paranoia that
1203 * we inherited from resumeThreadByNode().
1204 */
1205 if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1206 jint *counter = (jint *)arg;
1207
1208 (*counter)++;
1209 }
1210 return JVMTI_ERROR_NONE;
1211}
1212
1213static void *
1214newArray(jint length, size_t nbytes)
1215{
1216 void *ptr;
1217 ptr = jvmtiAllocate(length*(jint)nbytes);
1218 if ( ptr != NULL((void*)0) ) {
1219 (void)memset(ptr, 0, length*nbytes);
1220 }
1221 return ptr;
1222}
1223
1224static void
1225deleteArray(void *ptr)
1226{
1227 jvmtiDeallocate(ptr);
1228}
1229
1230/*
1231 * This function must be called with the threadLock held.
1232 *
1233 * Two facts conspire to make this routine complicated:
1234 *
1235 * 1) the VM doesn't support nested external suspend
1236 * 2) the original resumeAll code structure doesn't retrieve the
1237 * entire thread list from JVMTI so we use the runningThreads
1238 * list and two helpers to get the job done.
1239 *
1240 * Because we hold the threadLock, state seen by resumeCountHelper()
1241 * is the same state seen in resumeCopyHelper(). resumeCountHelper()
1242 * just counts up the number of threads to be hard resumed.
1243 * resumeCopyHelper() does the accounting for nested suspends and
1244 * special cases and, finally, populates the list of hard resume
1245 * threads to be passed to ResumeThreadList().
1246 *
1247 * At first glance, you might think that the accounting could be done
1248 * in resumeCountHelper(), but then resumeCopyHelper() would see
1249 * "post-resume" state in the accounting values (suspendCount and
1250 * toBeResumed) and would not be able to distinguish between a thread
1251 * that needs a hard resume versus a thread that is already running.
1252 */
1253static jvmtiError
1254commonResumeList(JNIEnv *env)
1255{
1256 jvmtiError error;
1257 jint i;
1258 jint reqCnt;
1259 jthread *reqList;
1260 jthread *reqPtr;
1261 jvmtiError *results;
1262
1263 reqCnt = 0;
1264
1265 /* count number of threads to hard resume */
1266 (void) enumerateOverThreadList(env, &runningThreads, resumeCountHelper,
1267 &reqCnt);
1268 if (reqCnt == 0) {
2
Assuming 'reqCnt' is not equal to 0
3
Taking false branch
1269 /* nothing to hard resume so do just the accounting part */
1270 (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1271 NULL((void*)0));
1272 return JVMTI_ERROR_NONE;
1273 }
1274
1275 /*LINTED*/
1276 reqList = newArray(reqCnt, sizeof(jthread));
1277 if (reqList
3.1
'reqList' is not equal to NULL
== NULL((void*)0)) {
4
Taking false branch
1278 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume request list"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("resume request list"
==((void*)0)?"":"resume request list"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1278); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "resume request list"); }
;
1279 }
1280 /*LINTED*/
1281 results = newArray(reqCnt, sizeof(jvmtiError));
1282 if (results
4.1
'results' is not equal to NULL
== NULL((void*)0)) {
5
Taking false branch
1283 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume list"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("resume list"==
((void*)0)?"":"resume list"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1283); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "resume list"); }
;
1284 }
1285
1286 /* copy the jthread values for threads to hard resume */
1287 reqPtr = reqList;
1288 (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1289 &reqPtr);
1290
1291 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThreadList)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1291), log_message_end ("%s()","ResumeThreadList")):((void)0
)),(gdata->jvmti))))->ResumeThreadList))
6
Assuming the condition is false
7
'?' condition is false
1292 (gdata->jvmti, reqCnt, reqList, results);
1293 for (i = 0; i < reqCnt; i++) {
8
Assuming 'i' is < 'reqCnt'
9
Loop condition is true. Entering loop body
1294 ThreadNode *node;
1295
1296 node = findThread(&runningThreads, reqList[i]);
10
Value assigned to 'node'
1297 if (node == NULL((void*)0)) {
11
Assuming 'node' is equal to NULL
12
Assuming pointer value is null
13
Taking true branch
1298 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in running thread table"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+23))), ((jvmtiError)(JVMTI_ERROR_MAX+64+23)), ("missing entry in running thread table"
==((void*)0)?"":"missing entry in running thread table"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1298); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+23)), "missing entry in running thread table"); }
;
14
'?' condition is false
1299 }
1300 LOG_MISC(("thread=%p resumed as part of list", node->thread))((gdata->log_flags & (0x00000008)) ?(log_message_begin
("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1300), log_message_end ("thread=%p resumed as part of list",
node->thread)):((void)0))
;
15
Assuming the condition is false
16
'?' condition is false
1301
1302 /*
1303 * resumeThreadByNode() assumes that JVM/DI ResumeThread()
1304 * always works and does all the accounting updates. We do
1305 * the same here. We also don't clear the error.
1306 */
1307 node->suspendCount--;
17
Access to field 'suspendCount' results in a dereference of a null pointer (loaded from variable 'node')
1308 node->toBeResumed = JNI_FALSE0;
1309 node->frameGeneration++; /* Increment on each resume */
1310 }
1311 deleteArray(results);
1312 deleteArray(reqList);
1313
1314 debugMonitorNotifyAll(threadLock);
1315
1316 return error;
1317}
1318
1319
1320/*
1321 * This function must be called after preSuspend and before postSuspend.
1322 */
1323static jvmtiError
1324commonSuspendList(JNIEnv *env, jint initCount, jthread *initList)
1325{
1326 jvmtiError error;
1327 jint i;
1328 jint reqCnt;
1329 jthread *reqList;
1330
1331 error = JVMTI_ERROR_NONE;
1332 reqCnt = 0;
1333 reqList = newArray(initCount, sizeof(jthread));
1334 if (reqList == NULL((void*)0)) {
1335 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"request list"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("request list"==
((void*)0)?"":"request list"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1335); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "request list"); }
;
1336 }
1337
1338 /*
1339 * Go through the initial list and see if we have anything to suspend.
1340 */
1341 for (i = 0; i < initCount; i++) {
1342 ThreadNode *node;
1343
1344 /*
1345 * If the thread is not between its start and end events, we should
1346 * still suspend it. To keep track of things, add the thread
1347 * to a separate list of threads so that we'll resume it later.
1348 */
1349 node = findThread(&runningThreads, initList[i]);
1350 if (node == NULL((void*)0)) {
1351 node = insertThread(env, &otherThreads, initList[i]);
1352 }
1353
1354 if (node->isDebugThread) {
1355 /* Ignore requests for suspending debugger threads */
1356 continue;
1357 }
1358
1359 /*
1360 * Just increment the suspend count if we are waiting
1361 * for a deferred suspend or if this is a nested suspend.
1362 */
1363 if (node->suspendOnStart || node->suspendCount > 0) {
1364 node->suspendCount++;
1365 continue;
1366 }
1367
1368 if (node->suspendCount == 0) {
1369 /* thread is not suspended yet so put it on the request list */
1370 reqList[reqCnt++] = initList[i];
1371 }
1372 }
1373
1374 if (reqCnt > 0) {
1375 jvmtiError *results = newArray(reqCnt, sizeof(jvmtiError));
1376
1377 if (results == NULL((void*)0)) {
1378 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"suspend list results"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("suspend list results"
==((void*)0)?"":"suspend list results"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1378); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+8)), "suspend list results"); }
;
1379 }
1380
1381 /*
1382 * We have something to suspend so try to do it.
1383 */
1384 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThreadList)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1384), log_message_end ("%s()","SuspendThreadList")):((void)
0)),(gdata->jvmti))))->SuspendThreadList))
1385 (gdata->jvmti, reqCnt, reqList, results);
1386 for (i = 0; i < reqCnt; i++) {
1387 ThreadNode *node;
1388
1389 node = findThread(NULL((void*)0), reqList[i]);
1390 if (node == NULL((void*)0)) {
1391 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in thread tables"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+23))), ((jvmtiError)(JVMTI_ERROR_MAX+64+23)), ("missing entry in thread tables"
==((void*)0)?"":"missing entry in thread tables"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1391); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+23)), "missing entry in thread tables"); }
;
1392 }
1393 LOG_MISC(("thread=%p suspended as part of list", node->thread))((gdata->log_flags & (0x00000008)) ?(log_message_begin
("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1393), log_message_end ("thread=%p suspended as part of list"
, node->thread)):((void)0))
;
1394
1395 if (results[i] == JVMTI_ERROR_NONE) {
1396 /* thread was suspended as requested */
1397 node->toBeResumed = JNI_TRUE1;
1398 } else if (results[i] == JVMTI_ERROR_THREAD_SUSPENDED) {
1399 /*
1400 * If the thread was suspended by another app thread,
1401 * do nothing and report no error (we won't resume it later).
1402 */
1403 results[i] = JVMTI_ERROR_NONE;
1404 } else if (results[i] == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1405 /*
1406 * This error means that the suspend request failed
1407 * because the thread is either a zombie or not yet
1408 * started. In either case, we ignore the error. If the
1409 * thread is a zombie, suspend/resume are no-ops. If the
1410 * thread is not started, it will be suspended for real
1411 * during the processing of its thread start event.
1412 */
1413 node->suspendOnStart = JNI_TRUE1;
1414 results[i] = JVMTI_ERROR_NONE;
1415 }
1416
1417 /* count real, app and deferred (suspendOnStart) suspensions */
1418 if (results[i] == JVMTI_ERROR_NONE) {
1419 node->suspendCount++;
1420 }
1421 }
1422 deleteArray(results);
1423 }
1424 deleteArray(reqList);
1425
1426 debugMonitorNotifyAll(threadLock);
1427
1428 return error;
1429}
1430
1431static jvmtiError
1432commonResume(jthread thread)
1433{
1434 jvmtiError error;
1435 ThreadNode *node;
1436
1437 /*
1438 * The thread is normally between its start and end events, but if
1439 * not, check the auxiliary list used by threadControl_suspendThread.
1440 */
1441 node = findThread(NULL((void*)0), thread);
1442#if 0
1443 tty_message("commonResume: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1444#endif
1445
1446 /*
1447 * If the node is in neither list, the debugger never suspended
1448 * this thread, so do nothing.
1449 */
1450 error = JVMTI_ERROR_NONE;
1451 if (node != NULL((void*)0)) {
1452 error = resumeThreadByNode(node);
1453 }
1454 return error;
1455}
1456
1457
1458jvmtiError
1459threadControl_suspendThread(jthread thread, jboolean deferred)
1460{
1461 jvmtiError error;
1462 JNIEnv *env;
1463
1464 env = getEnv();
1465
1466 log_debugee_location("threadControl_suspendThread()", thread, NULL((void*)0), 0);
1467
1468 preSuspend();
1469 error = commonSuspend(env, thread, deferred);
1470 postSuspend();
1471
1472 return error;
1473}
1474
1475jvmtiError
1476threadControl_resumeThread(jthread thread, jboolean do_unblock)
1477{
1478 jvmtiError error;
1479 JNIEnv *env;
1480
1481 env = getEnv();
1482
1483 log_debugee_location("threadControl_resumeThread()", thread, NULL((void*)0), 0);
1484
1485 eventHandler_lock(); /* for proper lock order */
1486 debugMonitorEnter(threadLock);
1487 error = commonResume(thread);
1488 removeResumed(env, &otherThreads);
1489 debugMonitorExit(threadLock);
1490 eventHandler_unlock();
1491
1492 if (do_unblock) {
1493 /* let eventHelper.c: commandLoop() know we resumed one thread */
1494 unblockCommandLoop();
1495 }
1496
1497 return error;
1498}
1499
1500jvmtiError
1501threadControl_suspendCount(jthread thread, jint *count)
1502{
1503 jvmtiError error;
1504 ThreadNode *node;
1505
1506 debugMonitorEnter(threadLock);
1507
1508 node = findThread(&runningThreads, thread);
1509 if (node == NULL((void*)0)) {
1510 node = findThread(&otherThreads, thread);
1511 }
1512
1513 error = JVMTI_ERROR_NONE;
1514 if (node != NULL((void*)0)) {
1515 *count = node->suspendCount;
1516 } else {
1517 /*
1518 * If the node is in neither list, the debugger never suspended
1519 * this thread, so the suspend count is 0.
1520 */
1521 *count = 0;
1522 }
1523
1524 debugMonitorExit(threadLock);
1525
1526 return error;
1527}
1528
1529static jboolean
1530contains(JNIEnv *env, jthread *list, jint count, jthread item)
1531{
1532 int i;
1533
1534 for (i = 0; i < count; i++) {
1535 if (isSameObject(env, list[i], item)) {
1536 return JNI_TRUE1;
1537 }
1538 }
1539 return JNI_FALSE0;
1540}
1541
1542
1543typedef struct {
1544 jthread *list;
1545 jint count;
1546} SuspendAllArg;
1547
1548static jvmtiError
1549suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1550{
1551 SuspendAllArg *saArg = (SuspendAllArg *)arg;
1552 jvmtiError error = JVMTI_ERROR_NONE;
1553 jthread *list = saArg->list;
1554 jint count = saArg->count;
1555 if (!contains(env, list, count, node->thread)) {
1556 error = commonSuspend(env, node->thread, JNI_FALSE0);
1557 }
1558 return error;
1559}
1560
1561jvmtiError
1562threadControl_suspendAll(void)
1563{
1564 jvmtiError error;
1565 JNIEnv *env;
1566#if 0
1567 tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount);
1568#endif
1569
1570 env = getEnv();
1571
1572 log_debugee_location("threadControl_suspendAll()", NULL((void*)0), NULL((void*)0), 0);
1573
1574 preSuspend();
1575
1576 /*
1577 * Get a list of all threads and suspend them.
1578 */
1579 WITH_LOCAL_REFS(env, 1)createLocalRefSpace(env, 1); { {
1580
1581 jthread *threads;
1582 jint count;
1583
1584 threads = allThreads(&count);
1585 if (threads == NULL((void*)0)) {
1586 error = AGENT_ERROR_OUT_OF_MEMORY((jvmtiError)(JVMTI_ERROR_MAX+64+8));
1587 goto err;
1588 }
1589 error = commonSuspendList(env, count, threads);
1590 if (error != JVMTI_ERROR_NONE) {
1591 goto err;
1592 }
1593
1594 /*
1595 * Update the suspend count of any threads not yet (or no longer)
1596 * in the thread list above.
1597 */
1598 {
1599 SuspendAllArg arg;
1600 arg.list = threads;
1601 arg.count = count;
1602 error = enumerateOverThreadList(env, &otherThreads,
1603 suspendAllHelper, &arg);
1604 }
1605
1606 if (error == JVMTI_ERROR_NONE) {
1607 /*
1608 * Pin all objects to prevent objects from being
1609 * garbage collected while the VM is suspended.
1610 */
1611 commonRef_pinAll();
1612
1613 suspendAllCount++;
1614 }
1615
1616 err:
1617 jvmtiDeallocate(threads);
1618
1619 } END_WITH_LOCAL_REFS(env)(*((*((((gdata->log_flags & (0x00000002)) ?(log_message_begin
("JNI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1619), log_message_end ("%s()","PopLocalFrame")):((void)0)),
(env))))->PopLocalFrame))(env, ((void*)0)); }
1620
1621 postSuspend();
1622
1623 return error;
1624}
1625
1626static jvmtiError
1627resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1628{
1629 /*
1630 * Since this helper is called with the threadLock held, we
1631 * don't need to recheck to see if the node is still on one
1632 * of the two thread lists.
1633 */
1634 return resumeThreadByNode(node);
1635}
1636
1637jvmtiError
1638threadControl_resumeAll(void)
1639{
1640 jvmtiError error;
1641 JNIEnv *env;
1642#if 0
1643 tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount);
1644#endif
1645
1646 env = getEnv();
1647
1648 log_debugee_location("threadControl_resumeAll()", NULL((void*)0), NULL((void*)0), 0);
1649
1650 eventHandler_lock(); /* for proper lock order */
1651 debugMonitorEnter(threadLock);
1652
1653 /*
1654 * Resume only those threads that the debugger has suspended. All
1655 * such threads must have a node in one of the thread lists, so there's
1656 * no need to get the whole thread list from JVMTI (unlike
1657 * suspendAll).
1658 */
1659 error = commonResumeList(env);
1
Calling 'commonResumeList'
1660 if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL((void*)0))) {
1661 error = enumerateOverThreadList(env, &otherThreads,
1662 resumeHelper, NULL((void*)0));
1663 removeResumed(env, &otherThreads);
1664 }
1665
1666 if (suspendAllCount > 0) {
1667 /*
1668 * Unpin all objects.
1669 */
1670 commonRef_unpinAll();
1671
1672 suspendAllCount--;
1673 }
1674
1675 debugMonitorExit(threadLock);
1676 eventHandler_unlock();
1677 /* let eventHelper.c: commandLoop() know we are resuming */
1678 unblockCommandLoop();
1679
1680 return error;
1681}
1682
1683
1684StepRequest *
1685threadControl_getStepRequest(jthread thread)
1686{
1687 ThreadNode *node;
1688 StepRequest *step;
1689
1690 step = NULL((void*)0);
1691
1692 debugMonitorEnter(threadLock);
1693
1694 node = findThread(&runningThreads, thread);
1695 if (node != NULL((void*)0)) {
1696 step = &node->currentStep;
1697 }
1698
1699 debugMonitorExit(threadLock);
1700
1701 return step;
1702}
1703
1704InvokeRequest *
1705threadControl_getInvokeRequest(jthread thread)
1706{
1707 ThreadNode *node;
1708 InvokeRequest *request;
1709
1710 request = NULL((void*)0);
1711
1712 debugMonitorEnter(threadLock);
1713
1714 node = findThread(&runningThreads, thread);
1715 if (node != NULL((void*)0)) {
1716 request = &node->currentInvoke;
1717 }
1718
1719 debugMonitorExit(threadLock);
1720
1721 return request;
1722}
1723
1724jvmtiError
1725threadControl_addDebugThread(jthread thread)
1726{
1727 jvmtiError error;
1728
1729 debugMonitorEnter(threadLock);
1730 if (debugThreadCount >= MAX_DEBUG_THREADS10) {
1731 error = AGENT_ERROR_OUT_OF_MEMORY((jvmtiError)(JVMTI_ERROR_MAX+64+8));
1732 } else {
1733 JNIEnv *env;
1734
1735 env = getEnv();
1736 debugThreads[debugThreadCount] = NULL((void*)0);
1737 saveGlobalRef(env, thread, &(debugThreads[debugThreadCount]));
1738 if (debugThreads[debugThreadCount] == NULL((void*)0)) {
1739 error = AGENT_ERROR_OUT_OF_MEMORY((jvmtiError)(JVMTI_ERROR_MAX+64+8));
1740 } else {
1741 debugThreadCount++;
1742 error = JVMTI_ERROR_NONE;
1743 }
1744 }
1745 debugMonitorExit(threadLock);
1746 return error;
1747}
1748
1749static jvmtiError
1750threadControl_removeDebugThread(jthread thread)
1751{
1752 jvmtiError error;
1753 JNIEnv *env;
1754 int i;
1755
1756 error = AGENT_ERROR_INVALID_THREAD((jvmtiError)(JVMTI_ERROR_MAX+64+23));
1757 env = getEnv();
1758
1759 debugMonitorEnter(threadLock);
1760 for (i = 0; i< debugThreadCount; i++) {
1761 if (isSameObject(env, thread, debugThreads[i])) {
1762 int j;
1763
1764 tossGlobalRef(env, &(debugThreads[i]));
1765 for (j = i+1; j < debugThreadCount; j++) {
1766 debugThreads[j-1] = debugThreads[j];
1767 }
1768 debugThreadCount--;
1769 error = JVMTI_ERROR_NONE;
1770 break;
1771 }
1772 }
1773 debugMonitorExit(threadLock);
1774 return error;
1775}
1776
1777jboolean
1778threadControl_isDebugThread(jthread thread)
1779{
1780 int i;
1781 jboolean rc;
1782 JNIEnv *env;
1783
1784 rc = JNI_FALSE0;
1785 env = getEnv();
1786
1787 debugMonitorEnter(threadLock);
1788 for (i = 0; i < debugThreadCount; i++) {
1789 if (isSameObject(env, thread, debugThreads[i])) {
1790 rc = JNI_TRUE1;
1791 break;
1792 }
1793 }
1794 debugMonitorExit(threadLock);
1795 return rc;
1796}
1797
1798static void
1799initLocks(void)
1800{
1801 if (popFrameEventLock == NULL((void*)0)) {
1802 popFrameEventLock = debugMonitorCreate("JDWP PopFrame Event Lock");
1803 popFrameProceedLock = debugMonitorCreate("JDWP PopFrame Proceed Lock");
1804 }
1805}
1806
1807static jboolean
1808getPopFrameThread(jthread thread)
1809{
1810 jboolean popFrameThread;
1811
1812 debugMonitorEnter(threadLock);
1813 {
1814 ThreadNode *node;
1815
1816 node = findThread(NULL((void*)0), thread);
1817 if (node == NULL((void*)0)) {
1818 popFrameThread = JNI_FALSE0;
1819 } else {
1820 popFrameThread = node->popFrameThread;
1821 }
1822 }
1823 debugMonitorExit(threadLock);
1824
1825 return popFrameThread;
1826}
1827
1828static void
1829setPopFrameThread(jthread thread, jboolean value)
1830{
1831 debugMonitorEnter(threadLock);
1832 {
1833 ThreadNode *node;
1834
1835 node = findThread(NULL((void*)0), thread);
1836 if (node == NULL((void*)0)) {
1837 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("entry in thread table"
==((void*)0)?"":"entry in thread table"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1837); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "entry in thread table"); }
;
1838 } else {
1839 node->popFrameThread = value;
1840 }
1841 }
1842 debugMonitorExit(threadLock);
1843}
1844
1845static jboolean
1846getPopFrameEvent(jthread thread)
1847{
1848 jboolean popFrameEvent;
1849
1850 debugMonitorEnter(threadLock);
1851 {
1852 ThreadNode *node;
1853
1854 node = findThread(NULL((void*)0), thread);
1855 if (node == NULL((void*)0)) {
1856 popFrameEvent = JNI_FALSE0;
1857 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("entry in thread table"
==((void*)0)?"":"entry in thread table"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1857); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "entry in thread table"); }
;
1858 } else {
1859 popFrameEvent = node->popFrameEvent;
1860 }
1861 }
1862 debugMonitorExit(threadLock);
1863
1864 return popFrameEvent;
1865}
1866
1867static void
1868setPopFrameEvent(jthread thread, jboolean value)
1869{
1870 debugMonitorEnter(threadLock);
1871 {
1872 ThreadNode *node;
1873
1874 node = findThread(NULL((void*)0), thread);
1875 if (node == NULL((void*)0)) {
1876 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("entry in thread table"
==((void*)0)?"":"entry in thread table"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1876); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "entry in thread table"); }
;
1877 } else {
1878 node->popFrameEvent = value;
1879 node->frameGeneration++; /* Increment on each resume */
1880 }
1881 }
1882 debugMonitorExit(threadLock);
1883}
1884
1885static jboolean
1886getPopFrameProceed(jthread thread)
1887{
1888 jboolean popFrameProceed;
1889
1890 debugMonitorEnter(threadLock);
1891 {
1892 ThreadNode *node;
1893
1894 node = findThread(NULL((void*)0), thread);
1895 if (node == NULL((void*)0)) {
1896 popFrameProceed = JNI_FALSE0;
1897 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("entry in thread table"
==((void*)0)?"":"entry in thread table"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1897); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "entry in thread table"); }
;
1898 } else {
1899 popFrameProceed = node->popFrameProceed;
1900 }
1901 }
1902 debugMonitorExit(threadLock);
1903
1904 return popFrameProceed;
1905}
1906
1907static void
1908setPopFrameProceed(jthread thread, jboolean value)
1909{
1910 debugMonitorEnter(threadLock);
1911 {
1912 ThreadNode *node;
1913
1914 node = findThread(NULL((void*)0), thread);
1915 if (node == NULL((void*)0)) {
1916 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("entry in thread table"
==((void*)0)?"":"entry in thread table"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 1916); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "entry in thread table"); }
;
1917 } else {
1918 node->popFrameProceed = value;
1919 }
1920 }
1921 debugMonitorExit(threadLock);
1922}
1923
1924/**
1925 * Special event handler for events on the popped thread
1926 * that occur during the pop operation.
1927 */
1928static void
1929popFrameCompleteEvent(jthread thread)
1930{
1931 debugMonitorEnter(popFrameProceedLock);
1932 {
1933 /* notify that we got the event */
1934 debugMonitorEnter(popFrameEventLock);
1935 {
1936 setPopFrameEvent(thread, JNI_TRUE1);
1937 debugMonitorNotify(popFrameEventLock);
1938 }
1939 debugMonitorExit(popFrameEventLock);
1940
1941 /* make sure we get suspended again */
1942 setPopFrameProceed(thread, JNI_FALSE0);
1943 while (getPopFrameProceed(thread) == JNI_FALSE0) {
1944 debugMonitorWait(popFrameProceedLock);
1945 }
1946 }
1947 debugMonitorExit(popFrameProceedLock);
1948}
1949
1950/**
1951 * Pop one frame off the stack of thread.
1952 * popFrameEventLock is already held
1953 */
1954static jvmtiError
1955popOneFrame(jthread thread)
1956{
1957 jvmtiError error;
1958
1959 error = JVMTI_FUNC_PTR(gdata->jvmti,PopFrame)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1959), log_message_end ("%s()","PopFrame")):((void)0)),(gdata
->jvmti))))->PopFrame))
(gdata->jvmti, thread);
1960 if (error != JVMTI_ERROR_NONE) {
1961 return error;
1962 }
1963
1964 /* resume the popped thread so that the pop occurs and so we */
1965 /* will get the event (step or method entry) after the pop */
1966 LOG_MISC(("thread=%p resumed in popOneFrame", thread))((gdata->log_flags & (0x00000008)) ?(log_message_begin
("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1966), log_message_end ("thread=%p resumed in popOneFrame", thread
)):((void)0))
;
1967 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1967), log_message_end ("%s()","ResumeThread")):((void)0)),(
gdata->jvmti))))->ResumeThread))
(gdata->jvmti, thread);
1968 if (error != JVMTI_ERROR_NONE) {
1969 return error;
1970 }
1971
1972 /* wait for the event to occur */
1973 setPopFrameEvent(thread, JNI_FALSE0);
1974 while (getPopFrameEvent(thread) == JNI_FALSE0) {
1975 debugMonitorWait(popFrameEventLock);
1976 }
1977
1978 /* make sure not to suspend until the popped thread is on the wait */
1979 debugMonitorEnter(popFrameProceedLock);
1980 {
1981 /* return popped thread to suspended state */
1982 LOG_MISC(("thread=%p suspended in popOneFrame", thread))((gdata->log_flags & (0x00000008)) ?(log_message_begin
("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1982), log_message_end ("thread=%p suspended in popOneFrame"
, thread)):((void)0))
;
1983 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,1983), log_message_end ("%s()","SuspendThread")):((void)0)),
(gdata->jvmti))))->SuspendThread))
(gdata->jvmti, thread);
1984
1985 /* notify popped thread so it can proceed when resumed */
1986 setPopFrameProceed(thread, JNI_TRUE1);
1987 debugMonitorNotify(popFrameProceedLock);
1988 }
1989 debugMonitorExit(popFrameProceedLock);
1990
1991 return error;
1992}
1993
1994/**
1995 * pop frames of the stack of 'thread' until 'frame' is popped.
1996 */
1997jvmtiError
1998threadControl_popFrames(jthread thread, FrameNumber fnum)
1999{
2000 jvmtiError error;
2001 jvmtiEventMode prevStepMode;
2002 jint framesPopped = 0;
2003 jint popCount;
2004 jboolean prevInvokeRequestMode;
2005
2006 log_debugee_location("threadControl_popFrames()", thread, NULL((void*)0), 0);
2007
2008 initLocks();
2009
2010 /* compute the number of frames to pop */
2011 popCount = fnum+1;
2012 if (popCount < 1) {
2013 return AGENT_ERROR_NO_MORE_FRAMES((jvmtiError)(JVMTI_ERROR_MAX+64+26));
2014 }
2015
2016 /* enable instruction level single step, but first note prev value */
2017 prevStepMode = threadControl_getInstructionStepMode(thread);
2018
2019 /*
2020 * Fix bug 6517249. The pop processing will disable invokes,
2021 * so remember if invokes are enabled now and restore
2022 * that state after we finish popping.
2023 */
2024 prevInvokeRequestMode = invoker_isEnabled(thread);
2025
2026 error = threadControl_setEventMode(JVMTI_ENABLE,
2027 EI_SINGLE_STEP, thread);
2028 if (error != JVMTI_ERROR_NONE) {
2029 return error;
2030 }
2031
2032 /* Inform eventHandler logic we are in a popFrame for this thread */
2033 debugMonitorEnter(popFrameEventLock);
2034 {
2035 setPopFrameThread(thread, JNI_TRUE1);
2036 /* pop frames using single step */
2037 while (framesPopped++ < popCount) {
2038 error = popOneFrame(thread);
2039 if (error != JVMTI_ERROR_NONE) {
2040 break;
2041 }
2042 }
2043 setPopFrameThread(thread, JNI_FALSE0);
2044 }
2045 debugMonitorExit(popFrameEventLock);
2046
2047 /* Reset StepRequest info (fromLine and stackDepth) after popframes
2048 * only if stepping is enabled.
2049 */
2050 if (prevStepMode == JVMTI_ENABLE) {
2051 stepControl_resetRequest(thread);
2052 }
2053
2054 if (prevInvokeRequestMode) {
2055 invoker_enableInvokeRequests(thread);
2056 }
2057
2058 /* restore state */
2059 (void)threadControl_setEventMode(prevStepMode,
2060 EI_SINGLE_STEP, thread);
2061
2062 return error;
2063}
2064
2065/* Check to see if any events are being consumed by a popFrame(). */
2066static jboolean
2067checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread)
2068{
2069 if ( getPopFrameThread(thread) ) {
2070 switch (ei) {
2071 case EI_THREAD_START:
2072 /* Excuse me? */
2073 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+1))), ((jvmtiError)(JVMTI_ERROR_MAX+64+1)), ("thread start during pop frame"
==((void*)0)?"":"thread start during pop frame"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 2073); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+1)), "thread start during pop frame"); }
;
2074 break;
2075 case EI_THREAD_END:
2076 /* Thread wants to end? let it. */
2077 setPopFrameThread(thread, JNI_FALSE0);
2078 popFrameCompleteEvent(thread);
2079 break;
2080 case EI_SINGLE_STEP:
2081 /* This is an event we requested to mark the */
2082 /* completion of the pop frame */
2083 popFrameCompleteEvent(thread);
2084 return JNI_TRUE1;
2085 case EI_BREAKPOINT:
2086 case EI_EXCEPTION:
2087 case EI_FIELD_ACCESS:
2088 case EI_FIELD_MODIFICATION:
2089 case EI_METHOD_ENTRY:
2090 case EI_METHOD_EXIT:
2091 /* Tell event handler to assume event has been consumed. */
2092 return JNI_TRUE1;
2093 default:
2094 break;
2095 }
2096 }
2097 /* Pretend we were never called */
2098 return JNI_FALSE0;
2099}
2100
2101struct bag *
2102threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject currentException)
2103{
2104 ThreadNode *node;
2105 JNIEnv *env;
2106 struct bag *eventBag;
2107 jthread threadToSuspend;
2108 jboolean consumed;
2109 EventIndex ei = evinfo->ei;
2110 jthread thread = evinfo->thread;
2111
2112 env = getEnv();
2113 threadToSuspend = NULL((void*)0);
2114
2115 log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL((void*)0), 0);
2116
2117 /* Events during pop commands may need to be ignored here. */
2118 consumed = checkForPopFrameEvents(env, ei, thread);
2119 if ( consumed ) {
2120 /* Always restore any exception (see below). */
2121 if (currentException != NULL((void*)0)) {
2122 JNI_FUNC_PTR(env,Throw)(*((*((((gdata->log_flags & (0x00000002)) ?(log_message_begin
("JNI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2122), log_message_end ("%s()","Throw")):((void)0)), (env)))
)->Throw))
(env, currentException);
2123 } else {
2124 JNI_FUNC_PTR(env,ExceptionClear)(*((*((((gdata->log_flags & (0x00000002)) ?(log_message_begin
("JNI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2124), log_message_end ("%s()","ExceptionClear")):((void)0))
, (env))))->ExceptionClear))
(env);
2125 }
2126 return NULL((void*)0);
2127 }
2128
2129 debugMonitorEnter(threadLock);
2130
2131 /*
2132 * Check the list of unknown threads maintained by suspend
2133 * and resume. If this thread is currently present in the
2134 * list, it should be
2135 * moved to the runningThreads list, since it is a
2136 * well-known thread now.
2137 */
2138 node = findThread(&otherThreads, thread);
2139 if (node != NULL((void*)0)) {
2140 moveNode(&otherThreads, &runningThreads, node);
2141 /* Now that we know the thread has started, we can set its TLS.*/
2142 setThreadLocalStorage(thread, (void*)node);
2143 } else {
2144 /*
2145 * Get a thread node for the reporting thread. For thread start
2146 * events, or if this event precedes a thread start event,
2147 * the thread node may need to be created.
2148 *
2149 * It is possible for certain events (notably method entry/exit)
2150 * to precede thread start for some VM implementations.
2151 */
2152 node = insertThread(env, &runningThreads, thread);
2153 }
2154
2155 if (ei == EI_THREAD_START) {
2156 node->isStarted = JNI_TRUE1;
2157 processDeferredEventModes(env, thread, node);
2158 }
2159
2160 node->current_ei = ei;
2161 eventBag = node->eventBag;
2162 if (node->suspendOnStart) {
2163 threadToSuspend = node->thread;
2164 }
2165 debugMonitorExit(threadLock);
2166
2167 if (threadToSuspend != NULL((void*)0)) {
2168 /*
2169 * An attempt was made to suspend this thread before it started.
2170 * We must suspend it now, before it starts to run. This must
2171 * be done with no locks held.
2172 */
2173 eventHelper_suspendThread(sessionID, threadToSuspend);
2174 }
2175
2176 return eventBag;
2177}
2178
2179static void
2180doPendingTasks(JNIEnv *env, ThreadNode *node)
2181{
2182 /* Deferred breakpoint handling for Thread.resume() */
2183 if (node->handlingAppResume) {
2184 jthread resumer = node->thread;
2185 jthread resumee = getResumee(resumer);
2186
2187 if (resumer != NULL((void*)0)) {
2188 /*
2189 * trackAppResume indirectly aquires handlerLock. For proper lock
2190 * ordering handlerLock has to be acquired before threadLock.
2191 */
2192 debugMonitorExit(threadLock);
2193 eventHandler_lock();
2194 debugMonitorEnter(threadLock);
2195
2196 /*
2197 * Track the resuming thread by marking it as being within
2198 * a resume and by setting up for notification on
2199 * a frame pop or exception. We won't allow the debugger
2200 * to suspend threads while any thread is within a
2201 * call to resume. This (along with the block below)
2202 * ensures that when the debugger
2203 * suspends a thread it will remain suspended.
2204 */
2205 trackAppResume(resumer);
2206
2207 /*
2208 * handlerLock is not needed anymore. We must release it before calling
2209 * blockOnDebuggerSuspend() because it is required for resumes done by
2210 * the debugger. If resumee is currently suspended by the debugger, then
2211 * blockOnDebuggerSuspend() will block until a debugger resume is done.
2212 * If it blocks while holding the handlerLock, then the resume will deadlock.
2213 */
2214 eventHandler_unlock();
2215 }
2216
2217 if (resumee != NULL((void*)0)) {
2218 /*
2219 * Hold up any attempt to resume as long as the debugger
2220 * has suspended the resumee.
2221 */
2222 blockOnDebuggerSuspend(resumee);
2223 }
2224
2225 node->handlingAppResume = JNI_FALSE0;
2226
2227 /*
2228 * The blocks exit condition: resumee's suspendCount == 0.
2229 *
2230 * Debugger suspends are blocked if any thread is executing
2231 * Thread.resume(), i.e. !handlingAppResume && frameDepth > 0.
2232 */
2233 }
2234
2235 /*
2236 * Take care of any pending interrupts/stops, and clear out
2237 * info on pending interrupts/stops.
2238 */
2239 if (node->pendingInterrupt) {
2240 JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2240), log_message_end ("%s()","InterruptThread")):((void)0)
),(gdata->jvmti))))->InterruptThread))
2241 (gdata->jvmti, node->thread);
2242 /*
2243 * TO DO: Log error
2244 */
2245 node->pendingInterrupt = JNI_FALSE0;
2246 }
2247
2248 if (node->pendingStop != NULL((void*)0)) {
2249 JVMTI_FUNC_PTR(gdata->jvmti,StopThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2249), log_message_end ("%s()","StopThread")):((void)0)),(gdata
->jvmti))))->StopThread))
2250 (gdata->jvmti, node->thread, node->pendingStop);
2251 /*
2252 * TO DO: Log error
2253 */
2254 tossGlobalRef(env, &(node->pendingStop));
2255 }
2256}
2257
2258void
2259threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
2260 struct bag *eventBag)
2261{
2262 ThreadNode *node;
2263
2264 log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL((void*)0), 0);
2265
2266 if (ei == EI_THREAD_END) {
2267 eventHandler_lock(); /* for proper lock order */
2268 }
2269 debugMonitorEnter(threadLock);
2270
2271 node = findThread(&runningThreads, thread);
2272 if (node == NULL((void*)0)) {
2273 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]"
, jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64
+21))), ((jvmtiError)(JVMTI_ERROR_MAX+64+21)), ("thread list corrupted"
==((void*)0)?"":"thread list corrupted"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 2273); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX
+64+21)), "thread list corrupted"); }
;
2274 } else {
2275 JNIEnv *env;
2276
2277 env = getEnv();
2278 if (ei == EI_THREAD_END) {
2279 jboolean inResume = (node->resumeFrameDepth > 0);
2280 removeThread(env, &runningThreads, thread);
2281 node = NULL((void*)0); /* has been freed */
2282
2283 /*
2284 * Clean up mechanism used to detect end of
2285 * resume.
2286 */
2287 if (inResume) {
2288 notifyAppResumeComplete();
2289 }
2290 } else {
2291 /* No point in doing this if the thread is about to die.*/
2292 doPendingTasks(env, node);
2293 node->eventBag = eventBag;
2294 node->current_ei = 0;
2295 }
2296 }
2297
2298 debugMonitorExit(threadLock);
2299 if (ei == EI_THREAD_END) {
2300 eventHandler_unlock();
2301 }
2302}
2303
2304/* Returns JDWP flavored status and status flags. */
2305jvmtiError
2306threadControl_applicationThreadStatus(jthread thread,
2307 jdwpThreadStatus *pstatus, jint *statusFlags)
2308{
2309 ThreadNode *node;
2310 jvmtiError error;
2311 jint state;
2312
2313 log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL((void*)0), 0);
2314
2315 debugMonitorEnter(threadLock);
2316
2317 error = threadState(thread, &state);
2318 *pstatus = map2jdwpThreadStatus(state);
2319 *statusFlags = map2jdwpSuspendStatus(state);
2320
2321 if (error == JVMTI_ERROR_NONE) {
2322 node = findThread(&runningThreads, thread);
2323 if ((node != NULL((void*)0)) && HANDLING_EVENT(node)((node)->current_ei != 0)) {
2324 /*
2325 * While processing an event, an application thread is always
2326 * considered to be running even if its handler happens to be
2327 * cond waiting on an internal debugger monitor, etc.
2328 *
2329 * Leave suspend status untouched since it is not possible
2330 * to distinguish debugger suspends from app suspends.
2331 */
2332 *pstatus = JDWP_THREAD_STATUS(RUNNING)1;
2333 }
2334 }
2335
2336 debugMonitorExit(threadLock);
2337
2338 return error;
2339}
2340
2341jvmtiError
2342threadControl_interrupt(jthread thread)
2343{
2344 ThreadNode *node;
2345 jvmtiError error;
2346
2347 error = JVMTI_ERROR_NONE;
2348
2349 log_debugee_location("threadControl_interrupt()", thread, NULL((void*)0), 0);
2350
2351 debugMonitorEnter(threadLock);
2352
2353 node = findThread(&runningThreads, thread);
2354 if ((node == NULL((void*)0)) || !HANDLING_EVENT(node)((node)->current_ei != 0)) {
2355 error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2355), log_message_end ("%s()","InterruptThread")):((void)0)
),(gdata->jvmti))))->InterruptThread))
2356 (gdata->jvmti, thread);
2357 } else {
2358 /*
2359 * Hold any interrupts until after the event is processed.
2360 */
2361 node->pendingInterrupt = JNI_TRUE1;
2362 }
2363
2364 debugMonitorExit(threadLock);
2365
2366 return error;
2367}
2368
2369void
2370threadControl_clearCLEInfo(JNIEnv *env, jthread thread)
2371{
2372 ThreadNode *node;
2373
2374 debugMonitorEnter(threadLock);
2375
2376 node = findThread(&runningThreads, thread);
2377 if (node != NULL((void*)0)) {
2378 node->cleInfo.ei = 0;
2379 if (node->cleInfo.clazz != NULL((void*)0)) {
2380 tossGlobalRef(env, &(node->cleInfo.clazz));
2381 }
2382 }
2383
2384 debugMonitorExit(threadLock);
2385}
2386
2387jboolean
2388threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz,
2389 jmethodID method, jlocation location)
2390{
2391 ThreadNode *node;
2392 jboolean result;
2393
2394 result = JNI_FALSE0;
2395
2396 debugMonitorEnter(threadLock);
2397
2398 node = findThread(&runningThreads, thread);
2399 if (node != NULL((void*)0) && node->cleInfo.ei != 0 &&
2400 node->cleInfo.method == method &&
2401 node->cleInfo.location == location &&
2402 (isSameObject(env, node->cleInfo.clazz, clazz))) {
2403 result = JNI_TRUE1; /* we have a match */
2404 }
2405
2406 debugMonitorExit(threadLock);
2407
2408 return result;
2409}
2410
2411void
2412threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
2413 jclass clazz, jmethodID method, jlocation location)
2414{
2415 ThreadNode *node;
2416
2417 debugMonitorEnter(threadLock);
2418
2419 node = findThread(&runningThreads, thread);
2420 if (node != NULL((void*)0)) {
2421 node->cleInfo.ei = ei;
2422 /* Create a class ref that will live beyond */
2423 /* the end of this call */
2424 saveGlobalRef(env, clazz, &(node->cleInfo.clazz));
2425 /* if returned clazz is NULL, we just won't match */
2426 node->cleInfo.method = method;
2427 node->cleInfo.location = location;
2428 }
2429
2430 debugMonitorExit(threadLock);
2431}
2432
2433void
2434threadControl_setPendingInterrupt(jthread thread)
2435{
2436 ThreadNode *node;
2437
2438 debugMonitorEnter(threadLock);
2439
2440 node = findThread(&runningThreads, thread);
2441 if (node != NULL((void*)0)) {
2442 node->pendingInterrupt = JNI_TRUE1;
2443 }
2444
2445 debugMonitorExit(threadLock);
2446}
2447
2448jvmtiError
2449threadControl_stop(jthread thread, jobject throwable)
2450{
2451 ThreadNode *node;
2452 jvmtiError error;
2453
2454 error = JVMTI_ERROR_NONE;
2455
2456 log_debugee_location("threadControl_stop()", thread, NULL((void*)0), 0);
2457
2458 debugMonitorEnter(threadLock);
2459
2460 node = findThread(&runningThreads, thread);
2461 if ((node == NULL((void*)0)) || !HANDLING_EVENT(node)((node)->current_ei != 0)) {
2462 error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2462), log_message_end ("%s()","StopThread")):((void)0)),(gdata
->jvmti))))->StopThread))
2463 (gdata->jvmti, thread, throwable);
2464 } else {
2465 JNIEnv *env;
2466
2467 /*
2468 * Hold any stops until after the event is processed.
2469 */
2470 env = getEnv();
2471 saveGlobalRef(env, throwable, &(node->pendingStop));
2472 }
2473
2474 debugMonitorExit(threadLock);
2475
2476 return error;
2477}
2478
2479static jvmtiError
2480detachHelper(JNIEnv *env, ThreadNode *node, void *arg)
2481{
2482 invoker_detach(&node->currentInvoke);
2483 return JVMTI_ERROR_NONE;
2484}
2485
2486void
2487threadControl_detachInvokes(void)
2488{
2489 JNIEnv *env;
2490
2491 env = getEnv();
2492 invoker_lock(); /* for proper lock order */
2493 debugMonitorEnter(threadLock);
2494 (void)enumerateOverThreadList(env, &runningThreads, detachHelper, NULL((void*)0));
2495 debugMonitorExit(threadLock);
2496 invoker_unlock();
2497}
2498
2499static jvmtiError
2500resetHelper(JNIEnv *env, ThreadNode *node, void *arg)
2501{
2502 if (node->toBeResumed) {
2503 LOG_MISC(("thread=%p resumed", node->thread))((gdata->log_flags & (0x00000008)) ?(log_message_begin
("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2503), log_message_end ("thread=%p resumed", node->thread
)):((void)0))
;
2504 (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2504), log_message_end ("%s()","ResumeThread")):((void)0)),(
gdata->jvmti))))->ResumeThread))
(gdata->jvmti, node->thread);
2505 node->frameGeneration++; /* Increment on each resume */
2506 }
2507 stepControl_clearRequest(node->thread, &node->currentStep);
2508 node->toBeResumed = JNI_FALSE0;
2509 node->suspendCount = 0;
2510 node->suspendOnStart = JNI_FALSE0;
2511
2512 return JVMTI_ERROR_NONE;
2513}
2514
2515void
2516threadControl_reset(void)
2517{
2518 JNIEnv *env;
2519
2520 env = getEnv();
2521 eventHandler_lock(); /* for proper lock order */
2522 debugMonitorEnter(threadLock);
2523 (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL((void*)0));
2524 (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL((void*)0));
2525
2526 removeResumed(env, &otherThreads);
2527
2528 freeDeferredEventModes(env);
2529
2530 suspendAllCount = 0;
2531
2532 /* Everything should have been resumed */
2533 JDI_ASSERT(otherThreads.first == NULL)do { if (gdata && gdata->assertOn && !(otherThreads
.first == ((void*)0))) { jdiAssertionFailed("/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
, 2533, "otherThreads.first == NULL"); } } while (0)
;
2534
2535 /* Threads could be waiting in blockOnDebuggerSuspend */
2536 debugMonitorNotifyAll(threadLock);
2537 debugMonitorExit(threadLock);
2538 eventHandler_unlock();
2539}
2540
2541jvmtiEventMode
2542threadControl_getInstructionStepMode(jthread thread)
2543{
2544 ThreadNode *node;
2545 jvmtiEventMode mode;
2546
2547 mode = JVMTI_DISABLE;
2548
2549 debugMonitorEnter(threadLock);
2550 node = findThread(&runningThreads, thread);
2551 if (node != NULL((void*)0)) {
2552 mode = node->instructionStepMode;
2553 }
2554 debugMonitorExit(threadLock);
2555 return mode;
2556}
2557
2558jvmtiError
2559threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2560{
2561 jvmtiError error;
2562
2563 /* Global event */
2564 if ( thread == NULL((void*)0) ) {
2565 error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)(*((*((((gdata->log_flags & (0x00000004))?(log_message_begin
("JVMTI","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c"
,2565), log_message_end ("%s()","SetEventNotificationMode")):
((void)0)),(gdata->jvmti))))->SetEventNotificationMode)
)
2566 (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2567 } else {
2568 /* Thread event */
2569 ThreadNode *node;
2570
2571 debugMonitorEnter(threadLock);
2572 {
2573 node = findThread(&runningThreads, thread);
2574 if ((node == NULL((void*)0)) || (!node->isStarted)) {
2575 JNIEnv *env;
2576
2577 env = getEnv();
2578 error = addDeferredEventMode(env, mode, ei, thread);
2579 } else {
2580 error = threadSetEventNotificationMode(node,
2581 mode, ei, thread);
2582 }
2583 }
2584 debugMonitorExit(threadLock);
2585
2586 }
2587 return error;
2588}
2589
2590/*
2591 * Returns the current thread, if the thread has generated at least
2592 * one event, and has not generated a thread end event.
2593 */
2594jthread
2595threadControl_currentThread(void)
2596{
2597 jthread thread;
2598
2599 debugMonitorEnter(threadLock);
2600 {
2601 ThreadNode *node;
2602
2603 node = findThread(&runningThreads, NULL((void*)0));
2604 thread = (node == NULL((void*)0)) ? NULL((void*)0) : node->thread;
2605 }
2606 debugMonitorExit(threadLock);
2607
2608 return thread;
2609}
2610
2611jlong
2612threadControl_getFrameGeneration(jthread thread)
2613{
2614 jlong frameGeneration = -1;
2615
2616 debugMonitorEnter(threadLock);
2617 {
2618 ThreadNode *node;
2619
2620 node = findThread(NULL((void*)0), thread);
2621
2622 if (node != NULL((void*)0)) {
2623 frameGeneration = node->frameGeneration;
2624 }
2625 }
2626 debugMonitorExit(threadLock);
2627
2628 return frameGeneration;
2629}
2630
2631/***** debugging *****/
2632
2633#ifdef DEBUG1
2634
2635void
2636threadControl_dumpAllThreads()
2637{
2638 tty_message("Dumping runningThreads:\n");
2639 dumpThreadList(&runningThreads);
2640 tty_message("Dumping otherThreads:\n");
2641 dumpThreadList(&otherThreads);
2642}
2643
2644void
2645threadControl_dumpThread(jthread thread)
2646{
2647 ThreadNode* node = findThread(NULL((void*)0), thread);
2648 if (node == NULL((void*)0)) {
2649 tty_message("Thread not found");
2650 } else {
2651 dumpThread(node);
2652 }
2653}
2654
2655static void
2656dumpThreadList(ThreadList *list)
2657{
2658 ThreadNode *node;
2659 for (node = list->first; node != NULL((void*)0); node = node->next) {
2660 if (!node->isDebugThread) {
2661 dumpThread(node);
2662 }
2663 }
2664}
2665
2666static void
2667dumpThread(ThreadNode *node) {
2668 tty_message(" Thread: node = %p, jthread = %p", node, node->thread);
2669#ifdef DEBUG_THREADNAME
2670 tty_message("\tname: %s", node->name);
2671#endif
2672 // More fields can be printed here when needed. The amount of output is intentionlly
2673 // kept small so it doesn't generate too much output.
2674 tty_message("\tsuspendCount: %d", node->suspendCount);
2675}
2676
2677#endif /* DEBUG */