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