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