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 // ANDROID-CHANGED: On ART 'this' is not always in register 0. We just use GetLocalInstance in
597 // all cases.
598 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInstance)
599 (gdata->jvmti, resumingThread, fnum, &object);
600 if (error == JVMTI_ERROR_NONE) {
601 resumee = object;
602 }
603 return resumee;
604 }
605
606
607 static jboolean
pendingAppResume(jboolean includeSuspended)608 pendingAppResume(jboolean includeSuspended)
609 {
610 ThreadList *list;
611 ThreadNode *node;
612
613 list = &runningThreads;
614 node = list->first;
615 while (node != NULL) {
616 if (node->resumeFrameDepth > 0) {
617 if (includeSuspended) {
618 return JNI_TRUE;
619 } else {
620 jvmtiError error;
621 jint state;
622
623 error = threadState(node->thread, &state);
624 if (error != JVMTI_ERROR_NONE) {
625 EXIT_ERROR(error, "getting thread state");
626 }
627 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
628 return JNI_TRUE;
629 }
630 }
631 }
632 node = node->next;
633 }
634 return JNI_FALSE;
635 }
636
637 static void
notifyAppResumeComplete(void)638 notifyAppResumeComplete(void)
639 {
640 debugMonitorNotifyAll(threadLock);
641 if (!pendingAppResume(JNI_TRUE)) {
642 if (framePopHandlerNode != NULL) {
643 (void)eventHandler_free(framePopHandlerNode);
644 framePopHandlerNode = NULL;
645 }
646 if (catchHandlerNode != NULL) {
647 (void)eventHandler_free(catchHandlerNode);
648 catchHandlerNode = NULL;
649 }
650 }
651 }
652
653 static void
handleAppResumeCompletion(JNIEnv * env,EventInfo * evinfo,HandlerNode * handlerNode,struct bag * eventBag)654 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
655 HandlerNode *handlerNode,
656 struct bag *eventBag)
657 {
658 ThreadNode *node;
659 jthread thread;
660
661 thread = evinfo->thread;
662
663 debugMonitorEnter(threadLock);
664
665 node = findThread(&runningThreads, thread);
666 if (node != NULL) {
667 if (node->resumeFrameDepth > 0) {
668 jint compareDepth = getStackDepth(thread);
669 if (evinfo->ei == EI_FRAME_POP) {
670 compareDepth--;
671 }
672 if (compareDepth < node->resumeFrameDepth) {
673 node->resumeFrameDepth = 0;
674 notifyAppResumeComplete();
675 }
676 }
677 }
678
679 debugMonitorExit(threadLock);
680 }
681
682 static void
blockOnDebuggerSuspend(jthread thread)683 blockOnDebuggerSuspend(jthread thread)
684 {
685 ThreadNode *node;
686
687 node = findThread(NULL, thread);
688 if (node != NULL) {
689 while (node && node->suspendCount > 0) {
690 debugMonitorWait(threadLock);
691 node = findThread(NULL, thread);
692 }
693 }
694 }
695
696 static void
trackAppResume(jthread thread)697 trackAppResume(jthread thread)
698 {
699 jvmtiError error;
700 FrameNumber fnum;
701 ThreadNode *node;
702
703 fnum = 0;
704 node = findThread(&runningThreads, thread);
705 if (node != NULL) {
706 JDI_ASSERT(node->resumeFrameDepth == 0);
707 error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
708 (gdata->jvmti, thread, fnum);
709 if (error == JVMTI_ERROR_NONE) {
710 jint frameDepth = getStackDepth(thread);
711 if ((frameDepth > 0) && (framePopHandlerNode == NULL)) {
712 framePopHandlerNode = eventHandler_createInternalThreadOnly(
713 EI_FRAME_POP,
714 handleAppResumeCompletion,
715 thread);
716 catchHandlerNode = eventHandler_createInternalThreadOnly(
717 EI_EXCEPTION_CATCH,
718 handleAppResumeCompletion,
719 thread);
720 if ((framePopHandlerNode == NULL) ||
721 (catchHandlerNode == NULL)) {
722 (void)eventHandler_free(framePopHandlerNode);
723 framePopHandlerNode = NULL;
724 (void)eventHandler_free(catchHandlerNode);
725 catchHandlerNode = NULL;
726 }
727 }
728 if ((framePopHandlerNode != NULL) &&
729 (catchHandlerNode != NULL) &&
730 (frameDepth > 0)) {
731 node->resumeFrameDepth = frameDepth;
732 }
733 }
734 }
735 }
736
737 static void
handleAppResumeBreakpoint(JNIEnv * env,EventInfo * evinfo,HandlerNode * handlerNode,struct bag * eventBag)738 handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo,
739 HandlerNode *handlerNode,
740 struct bag *eventBag)
741 {
742 jthread resumer = evinfo->thread;
743 jthread resumee = getResumee(resumer);
744
745 debugMonitorEnter(threadLock);
746 if (resumee != NULL) {
747 /*
748 * Hold up any attempt to resume as long as the debugger
749 * has suspended the resumee.
750 */
751 blockOnDebuggerSuspend(resumee);
752 }
753
754 if (resumer != NULL) {
755 /*
756 * Track the resuming thread by marking it as being within
757 * a resume and by setting up for notification on
758 * a frame pop or exception. We won't allow the debugger
759 * to suspend threads while any thread is within a
760 * call to resume. This (along with the block above)
761 * ensures that when the debugger
762 * suspends a thread it will remain suspended.
763 */
764 trackAppResume(resumer);
765 }
766
767 debugMonitorExit(threadLock);
768 }
769
770 void
threadControl_onConnect(void)771 threadControl_onConnect(void)
772 {
773 breakpointHandlerNode = eventHandler_createInternalBreakpoint(
774 handleAppResumeBreakpoint, NULL,
775 gdata->threadClass, gdata->threadResume, resumeLocation);
776 }
777
778 void
threadControl_onDisconnect(void)779 threadControl_onDisconnect(void)
780 {
781 if (breakpointHandlerNode != NULL) {
782 (void)eventHandler_free(breakpointHandlerNode);
783 breakpointHandlerNode = NULL;
784 }
785 if (framePopHandlerNode != NULL) {
786 (void)eventHandler_free(framePopHandlerNode);
787 framePopHandlerNode = NULL;
788 }
789 if (catchHandlerNode != NULL) {
790 (void)eventHandler_free(catchHandlerNode);
791 catchHandlerNode = NULL;
792 }
793 }
794
795 void
threadControl_onHook(void)796 threadControl_onHook(void)
797 {
798 /*
799 * As soon as the event hook is in place, we need to initialize
800 * the thread list with already-existing threads. The threadLock
801 * has been held since initialize, so we don't need to worry about
802 * insertions or deletions from the event handlers while we do this
803 */
804 JNIEnv *env;
805
806 env = getEnv();
807
808 /*
809 * Prevent any event processing until OnHook has been called
810 */
811 debugMonitorEnter(threadLock);
812
813 WITH_LOCAL_REFS(env, 1) {
814
815 jint threadCount;
816 jthread *threads;
817
818 threads = allThreads(&threadCount);
819 if (threads == NULL) {
820 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table");
821 } else {
822
823 int i;
824
825 for (i = 0; i < threadCount; i++) {
826 ThreadNode *node;
827 jthread thread = threads[i];
828 node = insertThread(env, &runningThreads, thread);
829
830 /*
831 * This is a tiny bit risky. We have to assume that the
832 * pre-existing threads have been started because we
833 * can't rely on a thread start event for them. The chances
834 * of a problem related to this are pretty slim though, and
835 * there's really no choice because without setting this flag
836 * there is no way to enable stepping and other events on
837 * the threads that already exist (e.g. the finalizer thread).
838 */
839 node->isStarted = JNI_TRUE;
840 }
841 }
842
843 } END_WITH_LOCAL_REFS(env)
844
845 debugMonitorExit(threadLock);
846 }
847
848 static jvmtiError
commonSuspendByNode(ThreadNode * node)849 commonSuspendByNode(ThreadNode *node)
850 {
851 jvmtiError error;
852
853 LOG_MISC(("thread=%p suspended", node->thread));
854 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)
855 (gdata->jvmti, node->thread);
856
857 /*
858 * Mark for resume only if suspend succeeded
859 */
860 if (error == JVMTI_ERROR_NONE) {
861 node->toBeResumed = JNI_TRUE;
862 }
863
864 /*
865 * If the thread was suspended by another app thread,
866 * do nothing and report no error (we won't resume it later).
867 */
868 if (error == JVMTI_ERROR_THREAD_SUSPENDED) {
869 error = JVMTI_ERROR_NONE;
870 }
871
872 return error;
873 }
874
875 /*
876 * Deferred suspends happen when the suspend is attempted on a thread
877 * that is not started. Bookkeeping (suspendCount,etc.)
878 * is handled by the original request, and once the thread actually
879 * starts, an actual suspend is attempted. This function does the
880 * deferred suspend without changing the bookkeeping that is already
881 * in place.
882 */
883 static jint
deferredSuspendThreadByNode(ThreadNode * node)884 deferredSuspendThreadByNode(ThreadNode *node)
885 {
886 jvmtiError error;
887
888 error = JVMTI_ERROR_NONE;
889 if (node->isDebugThread) {
890 /* Ignore requests for suspending debugger threads */
891 return JVMTI_ERROR_NONE;
892 }
893
894 /*
895 * Do the actual suspend only if a subsequent resume hasn't
896 * made it irrelevant.
897 */
898 if (node->suspendCount > 0) {
899 error = commonSuspendByNode(node);
900
901 /*
902 * Attempt to clean up from any error by decrementing the
903 * suspend count. This compensates for the increment that
904 * happens when suspendOnStart is set to true.
905 */
906 if (error != JVMTI_ERROR_NONE) {
907 node->suspendCount--;
908 }
909 }
910
911 node->suspendOnStart = JNI_FALSE;
912
913 debugMonitorNotifyAll(threadLock);
914
915 return error;
916 }
917
918 static jvmtiError
suspendThreadByNode(ThreadNode * node)919 suspendThreadByNode(ThreadNode *node)
920 {
921 jvmtiError error = JVMTI_ERROR_NONE;
922 if (node->isDebugThread) {
923 /* Ignore requests for suspending debugger threads */
924 return JVMTI_ERROR_NONE;
925 }
926
927 /*
928 * Just increment the suspend count if we are waiting
929 * for a deferred suspend.
930 */
931 if (node->suspendOnStart) {
932 node->suspendCount++;
933 return JVMTI_ERROR_NONE;
934 }
935
936 if (node->suspendCount == 0) {
937 error = commonSuspendByNode(node);
938
939 if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
940 /*
941 * This error means that the thread is either a zombie or not yet
942 * started. In either case, we ignore the error. If the thread
943 * is a zombie, suspend/resume are no-ops. If the thread is not
944 * started, it will be suspended for real during the processing
945 * of its thread start event.
946 */
947 node->suspendOnStart = JNI_TRUE;
948 error = JVMTI_ERROR_NONE;
949 }
950 }
951
952 if (error == JVMTI_ERROR_NONE) {
953 node->suspendCount++;
954 }
955
956 debugMonitorNotifyAll(threadLock);
957
958 return error;
959 }
960
961 static jvmtiError
resumeThreadByNode(ThreadNode * node)962 resumeThreadByNode(ThreadNode *node)
963 {
964 jvmtiError error = JVMTI_ERROR_NONE;
965
966 if (node->isDebugThread) {
967 /* never suspended by debugger => don't ever try to resume */
968 return JVMTI_ERROR_NONE;
969 }
970 if (node->suspendCount > 0) {
971 node->suspendCount--;
972 debugMonitorNotifyAll(threadLock);
973 if ((node->suspendCount == 0) && node->toBeResumed &&
974 !node->suspendOnStart) {
975 LOG_MISC(("thread=%p resumed", node->thread));
976 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
977 (gdata->jvmti, node->thread);
978 node->frameGeneration++; /* Increment on each resume */
979 node->toBeResumed = JNI_FALSE;
980 if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
981 /*
982 * We successfully "suspended" this thread, but
983 * we never received a THREAD_START event for it.
984 * Since the thread never ran, we can ignore our
985 * failure to resume the thread.
986 */
987 error = JVMTI_ERROR_NONE;
988 }
989 }
990 }
991
992 return error;
993 }
994
995 /*
996 * Functions which respond to user requests to suspend/resume
997 * threads.
998 * Suspends and resumes add and subtract from a count respectively.
999 * The thread is only suspended when the count goes from 0 to 1 and
1000 * resumed only when the count goes from 1 to 0.
1001 *
1002 * These functions suspend and resume application threads
1003 * without changing the
1004 * state of threads that were already suspended beforehand.
1005 * They must not be called from an application thread because
1006 * that thread may be suspended somewhere in the middle of things.
1007 */
1008 static void
preSuspend(void)1009 preSuspend(void)
1010 {
1011 getLocks(); /* Avoid debugger deadlocks */
1012
1013 /*
1014 * Delay any suspend while a call to java.lang.Thread.resume is in
1015 * progress (not including those in suspended threads). The wait is
1016 * timed because the threads suspended through
1017 * java.lang.Thread.suspend won't result in a notify even though
1018 * it may change the result of pendingAppResume()
1019 */
1020 while (pendingAppResume(JNI_FALSE)) {
1021 /*
1022 * This is ugly but we need to release the locks from getLocks
1023 * or else the notify will never happen. The locks must be
1024 * released and reacquired in the right order. else deadlocks
1025 * can happen. It is possible that, during this dance, the
1026 * notify will be missed, but since the wait needs to be timed
1027 * anyway, it won't be a disaster. Note that this code will
1028 * execute only on very rare occasions anyway.
1029 */
1030 releaseLocks();
1031
1032 debugMonitorEnter(threadLock);
1033 debugMonitorTimedWait(threadLock, 1000);
1034 debugMonitorExit(threadLock);
1035
1036 getLocks();
1037 }
1038 }
1039
1040 static void
postSuspend(void)1041 postSuspend(void)
1042 {
1043 releaseLocks();
1044 }
1045
1046 /*
1047 * This function must be called after preSuspend and before postSuspend.
1048 */
1049 static jvmtiError
commonSuspend(JNIEnv * env,jthread thread,jboolean deferred)1050 commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1051 {
1052 ThreadNode *node;
1053
1054 /*
1055 * If the thread is not between its start and end events, we should
1056 * still suspend it. To keep track of things, add the thread
1057 * to a separate list of threads so that we'll resume it later.
1058 */
1059 node = findThread(&runningThreads, thread);
1060 if (node == NULL) {
1061 node = insertThread(env, &otherThreads, thread);
1062 }
1063
1064 if ( deferred ) {
1065 return deferredSuspendThreadByNode(node);
1066 } else {
1067 return suspendThreadByNode(node);
1068 }
1069 }
1070
1071
1072 static jvmtiError
resumeCopyHelper(JNIEnv * env,ThreadNode * node,void * arg)1073 resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1074 {
1075 if (node->isDebugThread) {
1076 /* never suspended by debugger => don't ever try to resume */
1077 return JVMTI_ERROR_NONE;
1078 }
1079
1080 if (node->suspendCount > 1) {
1081 node->suspendCount--;
1082 /* nested suspend so just undo one level */
1083 return JVMTI_ERROR_NONE;
1084 }
1085
1086 /*
1087 * This thread was marked for suspension since its THREAD_START
1088 * event came in during a suspendAll, but the helper hasn't
1089 * completed the job yet. We decrement the count so the helper
1090 * won't suspend this thread after we are done with the resumeAll.
1091 * Another case to be handled here is when the debugger suspends
1092 * the thread while the app has it suspended. In this case,
1093 * the toBeResumed flag has been cleared indicating that
1094 * the thread should not be resumed when the debugger does a resume.
1095 * In this case, we also have to decrement the suspend count.
1096 * If we don't then when the app resumes the thread and our Thread.resume
1097 * bkpt handler is called, blockOnDebuggerSuspend will not resume
1098 * the thread because suspendCount will be 1 meaning that the
1099 * debugger has the thread suspended. See bug 6224859.
1100 */
1101 if (node->suspendCount == 1 && (!node->toBeResumed || node->suspendOnStart)) {
1102 node->suspendCount--;
1103 return JVMTI_ERROR_NONE;
1104 }
1105
1106 if (arg == NULL) {
1107 /* nothing to hard resume so we're done */
1108 return JVMTI_ERROR_NONE;
1109 }
1110
1111 /*
1112 * This is tricky. A suspendCount of 1 and toBeResumed means that
1113 * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1114 * on this thread. The check for !suspendOnStart is paranoia that
1115 * we inherited from resumeThreadByNode().
1116 */
1117 if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1118 jthread **listPtr = (jthread **)arg;
1119
1120 **listPtr = node->thread;
1121 (*listPtr)++;
1122 }
1123 return JVMTI_ERROR_NONE;
1124 }
1125
1126
1127 static jvmtiError
resumeCountHelper(JNIEnv * env,ThreadNode * node,void * arg)1128 resumeCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1129 {
1130 if (node->isDebugThread) {
1131 /* never suspended by debugger => don't ever try to resume */
1132 return JVMTI_ERROR_NONE;
1133 }
1134
1135 /*
1136 * This is tricky. A suspendCount of 1 and toBeResumed means that
1137 * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1138 * on this thread. The check for !suspendOnStart is paranoia that
1139 * we inherited from resumeThreadByNode().
1140 */
1141 if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1142 jint *counter = (jint *)arg;
1143
1144 (*counter)++;
1145 }
1146 return JVMTI_ERROR_NONE;
1147 }
1148
1149 static void *
newArray(jint length,size_t nbytes)1150 newArray(jint length, size_t nbytes)
1151 {
1152 void *ptr;
1153 ptr = jvmtiAllocate(length*(jint)nbytes);
1154 if ( ptr != NULL ) {
1155 (void)memset(ptr, 0, length*nbytes);
1156 }
1157 return ptr;
1158 }
1159
1160 static void
deleteArray(void * ptr)1161 deleteArray(void *ptr)
1162 {
1163 jvmtiDeallocate(ptr);
1164 }
1165
1166 /*
1167 * This function must be called with the threadLock held.
1168 *
1169 * Two facts conspire to make this routine complicated:
1170 *
1171 * 1) the VM doesn't support nested external suspend
1172 * 2) the original resumeAll code structure doesn't retrieve the
1173 * entire thread list from JVMTI so we use the runningThreads
1174 * list and two helpers to get the job done.
1175 *
1176 * Because we hold the threadLock, state seen by resumeCountHelper()
1177 * is the same state seen in resumeCopyHelper(). resumeCountHelper()
1178 * just counts up the number of threads to be hard resumed.
1179 * resumeCopyHelper() does the accounting for nested suspends and
1180 * special cases and, finally, populates the list of hard resume
1181 * threads to be passed to ResumeThreadList().
1182 *
1183 * At first glance, you might think that the accounting could be done
1184 * in resumeCountHelper(), but then resumeCopyHelper() would see
1185 * "post-resume" state in the accounting values (suspendCount and
1186 * toBeResumed) and would not be able to distinguish between a thread
1187 * that needs a hard resume versus a thread that is already running.
1188 */
1189 static jvmtiError
commonResumeList(JNIEnv * env)1190 commonResumeList(JNIEnv *env)
1191 {
1192 jvmtiError error;
1193 jint i;
1194 jint reqCnt;
1195 jthread *reqList;
1196 jthread *reqPtr;
1197 jvmtiError *results;
1198
1199 reqCnt = 0;
1200
1201 /* count number of threads to hard resume */
1202 (void) enumerateOverThreadList(env, &runningThreads, resumeCountHelper,
1203 &reqCnt);
1204 if (reqCnt == 0) {
1205 /* nothing to hard resume so do just the accounting part */
1206 (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1207 NULL);
1208 return JVMTI_ERROR_NONE;
1209 }
1210
1211 /*LINTED*/
1212 reqList = newArray(reqCnt, sizeof(jthread));
1213 if (reqList == NULL) {
1214 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume request list");
1215 }
1216 /*LINTED*/
1217 results = newArray(reqCnt, sizeof(jvmtiError));
1218 if (results == NULL) {
1219 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume list");
1220 }
1221
1222 /* copy the jthread values for threads to hard resume */
1223 reqPtr = reqList;
1224 (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1225 &reqPtr);
1226
1227 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThreadList)
1228 (gdata->jvmti, reqCnt, reqList, results);
1229 for (i = 0; i < reqCnt; i++) {
1230 ThreadNode *node;
1231
1232 node = findThread(&runningThreads, reqList[i]);
1233 if (node == NULL) {
1234 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in running thread table");
1235 }
1236 LOG_MISC(("thread=%p resumed as part of list", node->thread));
1237
1238 /*
1239 * resumeThreadByNode() assumes that JVM/DI ResumeThread()
1240 * always works and does all the accounting updates. We do
1241 * the same here. We also don't clear the error.
1242 */
1243 node->suspendCount--;
1244 node->toBeResumed = JNI_FALSE;
1245 node->frameGeneration++; /* Increment on each resume */
1246 }
1247 deleteArray(results);
1248 deleteArray(reqList);
1249
1250 debugMonitorNotifyAll(threadLock);
1251
1252 return error;
1253 }
1254
1255
1256 /*
1257 * This function must be called after preSuspend and before postSuspend.
1258 */
1259 static jvmtiError
commonSuspendList(JNIEnv * env,jint initCount,jthread * initList)1260 commonSuspendList(JNIEnv *env, jint initCount, jthread *initList)
1261 {
1262 jvmtiError error;
1263 jint i;
1264 jint reqCnt;
1265 jthread *reqList;
1266
1267 error = JVMTI_ERROR_NONE;
1268 reqCnt = 0;
1269 reqList = newArray(initCount, sizeof(jthread));
1270 if (reqList == NULL) {
1271 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"request list");
1272 }
1273
1274 /*
1275 * Go through the initial list and see if we have anything to suspend.
1276 */
1277 for (i = 0; i < initCount; i++) {
1278 ThreadNode *node;
1279
1280 /*
1281 * If the thread is not between its start and end events, we should
1282 * still suspend it. To keep track of things, add the thread
1283 * to a separate list of threads so that we'll resume it later.
1284 */
1285 node = findThread(&runningThreads, initList[i]);
1286 if (node == NULL) {
1287 node = insertThread(env, &otherThreads, initList[i]);
1288 }
1289
1290 if (node->isDebugThread) {
1291 /* Ignore requests for suspending debugger threads */
1292 continue;
1293 }
1294
1295 /*
1296 * Just increment the suspend count if we are waiting
1297 * for a deferred suspend or if this is a nested suspend.
1298 */
1299 if (node->suspendOnStart || node->suspendCount > 0) {
1300 node->suspendCount++;
1301 continue;
1302 }
1303
1304 if (node->suspendCount == 0) {
1305 /* thread is not suspended yet so put it on the request list */
1306 reqList[reqCnt++] = initList[i];
1307 }
1308 }
1309
1310 if (reqCnt > 0) {
1311 jvmtiError *results = newArray(reqCnt, sizeof(jvmtiError));
1312
1313 if (results == NULL) {
1314 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"suspend list results");
1315 }
1316
1317 /*
1318 * We have something to suspend so try to do it.
1319 */
1320 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThreadList)
1321 (gdata->jvmti, reqCnt, reqList, results);
1322 for (i = 0; i < reqCnt; i++) {
1323 ThreadNode *node;
1324
1325 node = findThread(NULL, reqList[i]);
1326 if (node == NULL) {
1327 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in thread tables");
1328 }
1329 LOG_MISC(("thread=%p suspended as part of list", node->thread));
1330
1331 if (results[i] == JVMTI_ERROR_NONE) {
1332 /* thread was suspended as requested */
1333 node->toBeResumed = JNI_TRUE;
1334 } else if (results[i] == JVMTI_ERROR_THREAD_SUSPENDED) {
1335 /*
1336 * If the thread was suspended by another app thread,
1337 * do nothing and report no error (we won't resume it later).
1338 */
1339 results[i] = JVMTI_ERROR_NONE;
1340 } else if (results[i] == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1341 /*
1342 * This error means that the suspend request failed
1343 * because the thread is either a zombie or not yet
1344 * started. In either case, we ignore the error. If the
1345 * thread is a zombie, suspend/resume are no-ops. If the
1346 * thread is not started, it will be suspended for real
1347 * during the processing of its thread start event.
1348 */
1349 node->suspendOnStart = JNI_TRUE;
1350 results[i] = JVMTI_ERROR_NONE;
1351 }
1352
1353 /* count real, app and deferred (suspendOnStart) suspensions */
1354 if (results[i] == JVMTI_ERROR_NONE) {
1355 node->suspendCount++;
1356 }
1357 }
1358 deleteArray(results);
1359 }
1360 deleteArray(reqList);
1361
1362 debugMonitorNotifyAll(threadLock);
1363
1364 return error;
1365 }
1366
1367
1368 static jvmtiError
commonResume(jthread thread)1369 commonResume(jthread thread)
1370 {
1371 jvmtiError error;
1372 ThreadNode *node;
1373
1374 /*
1375 * The thread is normally between its start and end events, but if
1376 * not, check the auxiliary list used by threadControl_suspendThread.
1377 */
1378 node = findThread(NULL, thread);
1379
1380 /*
1381 * If the node is in neither list, the debugger never suspended
1382 * this thread, so do nothing.
1383 */
1384 error = JVMTI_ERROR_NONE;
1385 if (node != NULL) {
1386 error = resumeThreadByNode(node);
1387 }
1388 return error;
1389 }
1390
1391
1392 jvmtiError
threadControl_suspendThread(jthread thread,jboolean deferred)1393 threadControl_suspendThread(jthread thread, jboolean deferred)
1394 {
1395 jvmtiError error;
1396 JNIEnv *env;
1397
1398 env = getEnv();
1399
1400 log_debugee_location("threadControl_suspendThread()", thread, NULL, 0);
1401
1402 preSuspend();
1403 error = commonSuspend(env, thread, deferred);
1404 postSuspend();
1405
1406 return error;
1407 }
1408
1409 jvmtiError
threadControl_resumeThread(jthread thread,jboolean do_unblock)1410 threadControl_resumeThread(jthread thread, jboolean do_unblock)
1411 {
1412 jvmtiError error;
1413 JNIEnv *env;
1414
1415 env = getEnv();
1416
1417 log_debugee_location("threadControl_resumeThread()", thread, NULL, 0);
1418
1419 eventHandler_lock(); /* for proper lock order */
1420 debugMonitorEnter(threadLock);
1421 error = commonResume(thread);
1422 removeResumed(env, &otherThreads);
1423 debugMonitorExit(threadLock);
1424 eventHandler_unlock();
1425
1426 if (do_unblock) {
1427 /* let eventHelper.c: commandLoop() know we resumed one thread */
1428 unblockCommandLoop();
1429 }
1430
1431 return error;
1432 }
1433
1434 jvmtiError
threadControl_suspendCount(jthread thread,jint * count)1435 threadControl_suspendCount(jthread thread, jint *count)
1436 {
1437 jvmtiError error;
1438 ThreadNode *node;
1439
1440 debugMonitorEnter(threadLock);
1441
1442 node = findThread(&runningThreads, thread);
1443 if (node == NULL) {
1444 node = findThread(&otherThreads, thread);
1445 }
1446
1447 error = JVMTI_ERROR_NONE;
1448 if (node != NULL) {
1449 *count = node->suspendCount;
1450 } else {
1451 /*
1452 * If the node is in neither list, the debugger never suspended
1453 * this thread, so the suspend count is 0.
1454 */
1455 *count = 0;
1456 }
1457
1458 debugMonitorExit(threadLock);
1459
1460 return error;
1461 }
1462
1463 static jboolean
contains(JNIEnv * env,jthread * list,jint count,jthread item)1464 contains(JNIEnv *env, jthread *list, jint count, jthread item)
1465 {
1466 int i;
1467
1468 for (i = 0; i < count; i++) {
1469 if (isSameObject(env, list[i], item)) {
1470 return JNI_TRUE;
1471 }
1472 }
1473 return JNI_FALSE;
1474 }
1475
1476
1477 typedef struct {
1478 jthread *list;
1479 jint count;
1480 } SuspendAllArg;
1481
1482 static jvmtiError
suspendAllHelper(JNIEnv * env,ThreadNode * node,void * arg)1483 suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1484 {
1485 SuspendAllArg *saArg = (SuspendAllArg *)arg;
1486 jvmtiError error = JVMTI_ERROR_NONE;
1487 jthread *list = saArg->list;
1488 jint count = saArg->count;
1489 if (!contains(env, list, count, node->thread)) {
1490 error = commonSuspend(env, node->thread, JNI_FALSE);
1491 }
1492 return error;
1493 }
1494
1495 jvmtiError
threadControl_suspendAll(void)1496 threadControl_suspendAll(void)
1497 {
1498 jvmtiError error;
1499 JNIEnv *env;
1500
1501 env = getEnv();
1502
1503 log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0);
1504
1505 preSuspend();
1506
1507 /*
1508 * Get a list of all threads and suspend them.
1509 */
1510 WITH_LOCAL_REFS(env, 1) {
1511
1512 jthread *threads;
1513 jint count;
1514
1515 threads = allThreads(&count);
1516 if (threads == NULL) {
1517 error = AGENT_ERROR_OUT_OF_MEMORY;
1518 goto err;
1519 }
1520 if (canSuspendResumeThreadLists()) {
1521 error = commonSuspendList(env, count, threads);
1522 if (error != JVMTI_ERROR_NONE) {
1523 goto err;
1524 }
1525 } else {
1526
1527 int i;
1528
1529 for (i = 0; i < count; i++) {
1530 error = commonSuspend(env, threads[i], JNI_FALSE);
1531
1532 if (error != JVMTI_ERROR_NONE) {
1533 goto err;
1534 }
1535 }
1536 }
1537
1538 /*
1539 * Update the suspend count of any threads not yet (or no longer)
1540 * in the thread list above.
1541 */
1542 {
1543 SuspendAllArg arg;
1544 arg.list = threads;
1545 arg.count = count;
1546 error = enumerateOverThreadList(env, &otherThreads,
1547 suspendAllHelper, &arg);
1548 }
1549
1550 if (error == JVMTI_ERROR_NONE) {
1551 suspendAllCount++;
1552 }
1553
1554 err: ;
1555
1556 } END_WITH_LOCAL_REFS(env)
1557
1558 postSuspend();
1559
1560 return error;
1561 }
1562
1563 static jvmtiError
resumeHelper(JNIEnv * env,ThreadNode * node,void * ignored)1564 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1565 {
1566 /*
1567 * Since this helper is called with the threadLock held, we
1568 * don't need to recheck to see if the node is still on one
1569 * of the two thread lists.
1570 */
1571 return resumeThreadByNode(node);
1572 }
1573
1574 jvmtiError
threadControl_resumeAll(void)1575 threadControl_resumeAll(void)
1576 {
1577 jvmtiError error;
1578 JNIEnv *env;
1579
1580 env = getEnv();
1581
1582 log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1583
1584 eventHandler_lock(); /* for proper lock order */
1585 debugMonitorEnter(threadLock);
1586
1587 /*
1588 * Resume only those threads that the debugger has suspended. All
1589 * such threads must have a node in one of the thread lists, so there's
1590 * no need to get the whole thread list from JVMTI (unlike
1591 * suspendAll).
1592 */
1593 if (canSuspendResumeThreadLists()) {
1594 error = commonResumeList(env);
1595 } else {
1596 error = enumerateOverThreadList(env, &runningThreads,
1597 resumeHelper, NULL);
1598 }
1599 if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1600 error = enumerateOverThreadList(env, &otherThreads,
1601 resumeHelper, NULL);
1602 removeResumed(env, &otherThreads);
1603 }
1604
1605 if (suspendAllCount > 0) {
1606 suspendAllCount--;
1607 }
1608
1609 debugMonitorExit(threadLock);
1610 eventHandler_unlock();
1611 /* let eventHelper.c: commandLoop() know we are resuming */
1612 unblockCommandLoop();
1613
1614 return error;
1615 }
1616
1617
1618 StepRequest *
threadControl_getStepRequest(jthread thread)1619 threadControl_getStepRequest(jthread thread)
1620 {
1621 ThreadNode *node;
1622 StepRequest *step;
1623
1624 step = NULL;
1625
1626 debugMonitorEnter(threadLock);
1627
1628 node = findThread(&runningThreads, thread);
1629 if (node != NULL) {
1630 step = &node->currentStep;
1631 }
1632
1633 debugMonitorExit(threadLock);
1634
1635 return step;
1636 }
1637
1638 InvokeRequest *
threadControl_getInvokeRequest(jthread thread)1639 threadControl_getInvokeRequest(jthread thread)
1640 {
1641 ThreadNode *node;
1642 InvokeRequest *request;
1643
1644 request = NULL;
1645
1646 debugMonitorEnter(threadLock);
1647
1648 node = findThread(&runningThreads, thread);
1649 if (node != NULL) {
1650 request = &node->currentInvoke;
1651 }
1652
1653 debugMonitorExit(threadLock);
1654
1655 return request;
1656 }
1657
1658 jvmtiError
threadControl_addDebugThread(jthread thread)1659 threadControl_addDebugThread(jthread thread)
1660 {
1661 jvmtiError error;
1662
1663 debugMonitorEnter(threadLock);
1664 if (debugThreadCount >= MAX_DEBUG_THREADS) {
1665 error = AGENT_ERROR_OUT_OF_MEMORY;
1666 } else {
1667 JNIEnv *env;
1668
1669 env = getEnv();
1670 debugThreads[debugThreadCount] = NULL;
1671 saveGlobalRef(env, thread, &(debugThreads[debugThreadCount]));
1672 if (debugThreads[debugThreadCount] == NULL) {
1673 error = AGENT_ERROR_OUT_OF_MEMORY;
1674 } else {
1675 debugThreadCount++;
1676 error = JVMTI_ERROR_NONE;
1677 }
1678 }
1679 debugMonitorExit(threadLock);
1680 return error;
1681 }
1682
1683 static jvmtiError
threadControl_removeDebugThread(jthread thread)1684 threadControl_removeDebugThread(jthread thread)
1685 {
1686 jvmtiError error;
1687 JNIEnv *env;
1688 int i;
1689
1690 error = AGENT_ERROR_INVALID_THREAD;
1691 env = getEnv();
1692
1693 debugMonitorEnter(threadLock);
1694 for (i = 0; i< debugThreadCount; i++) {
1695 if (isSameObject(env, thread, debugThreads[i])) {
1696 int j;
1697
1698 tossGlobalRef(env, &(debugThreads[i]));
1699 for (j = i+1; j < debugThreadCount; j++) {
1700 debugThreads[j-1] = debugThreads[j];
1701 }
1702 debugThreadCount--;
1703 error = JVMTI_ERROR_NONE;
1704 break;
1705 }
1706 }
1707 debugMonitorExit(threadLock);
1708 return error;
1709 }
1710
1711 jboolean
threadControl_isDebugThread(jthread thread)1712 threadControl_isDebugThread(jthread thread)
1713 {
1714 int i;
1715 jboolean rc;
1716 JNIEnv *env;
1717
1718 rc = JNI_FALSE;
1719 env = getEnv();
1720
1721 debugMonitorEnter(threadLock);
1722 for (i = 0; i < debugThreadCount; i++) {
1723 if (isSameObject(env, thread, debugThreads[i])) {
1724 rc = JNI_TRUE;
1725 break;
1726 }
1727 }
1728 debugMonitorExit(threadLock);
1729 return rc;
1730 }
1731
1732 static void
initLocks(void)1733 initLocks(void)
1734 {
1735 if (popFrameEventLock == NULL) {
1736 popFrameEventLock = debugMonitorCreate("JDWP PopFrame Event Lock");
1737 popFrameProceedLock = debugMonitorCreate("JDWP PopFrame Proceed Lock");
1738 }
1739 }
1740
1741 static jboolean
getPopFrameThread(jthread thread)1742 getPopFrameThread(jthread thread)
1743 {
1744 jboolean popFrameThread;
1745
1746 debugMonitorEnter(threadLock);
1747 {
1748 ThreadNode *node;
1749
1750 node = findThread(NULL, thread);
1751 if (node == NULL) {
1752 popFrameThread = JNI_FALSE;
1753 } else {
1754 popFrameThread = node->popFrameThread;
1755 }
1756 }
1757 debugMonitorExit(threadLock);
1758
1759 return popFrameThread;
1760 }
1761
1762 static void
setPopFrameThread(jthread thread,jboolean value)1763 setPopFrameThread(jthread thread, jboolean value)
1764 {
1765 debugMonitorEnter(threadLock);
1766 {
1767 ThreadNode *node;
1768
1769 node = findThread(NULL, thread);
1770 if (node == NULL) {
1771 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
1772 } else {
1773 node->popFrameThread = value;
1774 }
1775 }
1776 debugMonitorExit(threadLock);
1777 }
1778
1779 static jboolean
getPopFrameEvent(jthread thread)1780 getPopFrameEvent(jthread thread)
1781 {
1782 jboolean popFrameEvent;
1783
1784 debugMonitorEnter(threadLock);
1785 {
1786 ThreadNode *node;
1787
1788 node = findThread(NULL, thread);
1789 if (node == NULL) {
1790 popFrameEvent = JNI_FALSE;
1791 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
1792 } else {
1793 popFrameEvent = node->popFrameEvent;
1794 }
1795 }
1796 debugMonitorExit(threadLock);
1797
1798 return popFrameEvent;
1799 }
1800
1801 static void
setPopFrameEvent(jthread thread,jboolean value)1802 setPopFrameEvent(jthread thread, jboolean value)
1803 {
1804 debugMonitorEnter(threadLock);
1805 {
1806 ThreadNode *node;
1807
1808 node = findThread(NULL, thread);
1809 if (node == NULL) {
1810 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
1811 } else {
1812 node->popFrameEvent = value;
1813 node->frameGeneration++; /* Increment on each resume */
1814 }
1815 }
1816 debugMonitorExit(threadLock);
1817 }
1818
1819 static jboolean
getPopFrameProceed(jthread thread)1820 getPopFrameProceed(jthread thread)
1821 {
1822 jboolean popFrameProceed;
1823
1824 debugMonitorEnter(threadLock);
1825 {
1826 ThreadNode *node;
1827
1828 node = findThread(NULL, thread);
1829 if (node == NULL) {
1830 popFrameProceed = JNI_FALSE;
1831 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
1832 } else {
1833 popFrameProceed = node->popFrameProceed;
1834 }
1835 }
1836 debugMonitorExit(threadLock);
1837
1838 return popFrameProceed;
1839 }
1840
1841 static void
setPopFrameProceed(jthread thread,jboolean value)1842 setPopFrameProceed(jthread thread, jboolean value)
1843 {
1844 debugMonitorEnter(threadLock);
1845 {
1846 ThreadNode *node;
1847
1848 node = findThread(NULL, thread);
1849 if (node == NULL) {
1850 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
1851 } else {
1852 node->popFrameProceed = value;
1853 }
1854 }
1855 debugMonitorExit(threadLock);
1856 }
1857
1858 /**
1859 * Special event handler for events on the popped thread
1860 * that occur during the pop operation.
1861 */
1862 static void
popFrameCompleteEvent(jthread thread)1863 popFrameCompleteEvent(jthread thread)
1864 {
1865 debugMonitorEnter(popFrameProceedLock);
1866 {
1867 /* notify that we got the event */
1868 debugMonitorEnter(popFrameEventLock);
1869 {
1870 setPopFrameEvent(thread, JNI_TRUE);
1871 debugMonitorNotify(popFrameEventLock);
1872 }
1873 debugMonitorExit(popFrameEventLock);
1874
1875 /* make sure we get suspended again */
1876 setPopFrameProceed(thread, JNI_FALSE);
1877 while (getPopFrameProceed(thread) == JNI_FALSE) {
1878 debugMonitorWait(popFrameProceedLock);
1879 }
1880 }
1881 debugMonitorExit(popFrameProceedLock);
1882 }
1883
1884 /**
1885 * Pop one frame off the stack of thread.
1886 * popFrameEventLock is already held
1887 */
1888 static jvmtiError
popOneFrame(jthread thread)1889 popOneFrame(jthread thread)
1890 {
1891 jvmtiError error;
1892
1893 error = JVMTI_FUNC_PTR(gdata->jvmti,PopFrame)(gdata->jvmti, thread);
1894 if (error != JVMTI_ERROR_NONE) {
1895 return error;
1896 }
1897
1898 /* resume the popped thread so that the pop occurs and so we */
1899 /* will get the event (step or method entry) after the pop */
1900 LOG_MISC(("thread=%p resumed in popOneFrame", thread));
1901 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, thread);
1902 if (error != JVMTI_ERROR_NONE) {
1903 return error;
1904 }
1905
1906 /* wait for the event to occur */
1907 setPopFrameEvent(thread, JNI_FALSE);
1908 while (getPopFrameEvent(thread) == JNI_FALSE) {
1909 debugMonitorWait(popFrameEventLock);
1910 }
1911
1912 /* make sure not to suspend until the popped thread is on the wait */
1913 debugMonitorEnter(popFrameProceedLock);
1914 {
1915 /* return popped thread to suspended state */
1916 LOG_MISC(("thread=%p suspended in popOneFrame", thread));
1917 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)(gdata->jvmti, thread);
1918
1919 /* notify popped thread so it can proceed when resumed */
1920 setPopFrameProceed(thread, JNI_TRUE);
1921 debugMonitorNotify(popFrameProceedLock);
1922 }
1923 debugMonitorExit(popFrameProceedLock);
1924
1925 return error;
1926 }
1927
1928 /**
1929 * pop frames of the stack of 'thread' until 'frame' is popped.
1930 */
1931 jvmtiError
threadControl_popFrames(jthread thread,FrameNumber fnum)1932 threadControl_popFrames(jthread thread, FrameNumber fnum)
1933 {
1934 jvmtiError error;
1935 jvmtiEventMode prevStepMode;
1936 jint framesPopped = 0;
1937 jint popCount;
1938 jboolean prevInvokeRequestMode;
1939
1940 log_debugee_location("threadControl_popFrames()", thread, NULL, 0);
1941
1942 initLocks();
1943
1944 /* compute the number of frames to pop */
1945 popCount = fnum+1;
1946 if (popCount < 1) {
1947 return AGENT_ERROR_NO_MORE_FRAMES;
1948 }
1949
1950 /* enable instruction level single step, but first note prev value */
1951 prevStepMode = threadControl_getInstructionStepMode(thread);
1952
1953 /*
1954 * Fix bug 6517249. The pop processing will disable invokes,
1955 * so remember if invokes are enabled now and restore
1956 * that state after we finish popping.
1957 */
1958 prevInvokeRequestMode = invoker_isEnabled(thread);
1959
1960 error = threadControl_setEventMode(JVMTI_ENABLE,
1961 EI_SINGLE_STEP, thread);
1962 if (error != JVMTI_ERROR_NONE) {
1963 return error;
1964 }
1965
1966 /* Inform eventHandler logic we are in a popFrame for this thread */
1967 debugMonitorEnter(popFrameEventLock);
1968 {
1969 setPopFrameThread(thread, JNI_TRUE);
1970 /* pop frames using single step */
1971 while (framesPopped++ < popCount) {
1972 error = popOneFrame(thread);
1973 if (error != JVMTI_ERROR_NONE) {
1974 break;
1975 }
1976 }
1977 setPopFrameThread(thread, JNI_FALSE);
1978 }
1979 debugMonitorExit(popFrameEventLock);
1980
1981 /* Reset StepRequest info (fromLine and stackDepth) after popframes
1982 * only if stepping is enabled.
1983 */
1984 if (prevStepMode == JVMTI_ENABLE) {
1985 stepControl_resetRequest(thread);
1986 }
1987
1988 if (prevInvokeRequestMode) {
1989 invoker_enableInvokeRequests(thread);
1990 }
1991
1992 /* restore state */
1993 (void)threadControl_setEventMode(prevStepMode,
1994 EI_SINGLE_STEP, thread);
1995
1996 return error;
1997 }
1998
1999 /* Check to see if any events are being consumed by a popFrame(). */
2000 static jboolean
checkForPopFrameEvents(JNIEnv * env,EventIndex ei,jthread thread)2001 checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread)
2002 {
2003 if ( getPopFrameThread(thread) ) {
2004 switch (ei) {
2005 case EI_THREAD_START:
2006 /* Excuse me? */
2007 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame");
2008 break;
2009 case EI_THREAD_END:
2010 /* Thread wants to end? let it. */
2011 setPopFrameThread(thread, JNI_FALSE);
2012 popFrameCompleteEvent(thread);
2013 break;
2014 case EI_SINGLE_STEP:
2015 /* This is an event we requested to mark the */
2016 /* completion of the pop frame */
2017 popFrameCompleteEvent(thread);
2018 return JNI_TRUE;
2019 case EI_BREAKPOINT:
2020 case EI_EXCEPTION:
2021 case EI_FIELD_ACCESS:
2022 case EI_FIELD_MODIFICATION:
2023 case EI_METHOD_ENTRY:
2024 case EI_METHOD_EXIT:
2025 /* Tell event handler to assume event has been consumed. */
2026 return JNI_TRUE;
2027 default:
2028 break;
2029 }
2030 }
2031 /* Pretend we were never called */
2032 return JNI_FALSE;
2033 }
2034
2035 struct bag *
threadControl_onEventHandlerEntry(jbyte sessionID,EventIndex ei,jthread thread,jobject currentException)2036 threadControl_onEventHandlerEntry(jbyte sessionID, EventIndex ei, jthread thread, jobject currentException)
2037 {
2038 ThreadNode *node;
2039 JNIEnv *env;
2040 struct bag *eventBag;
2041 jthread threadToSuspend;
2042 jboolean consumed;
2043
2044 env = getEnv();
2045 threadToSuspend = NULL;
2046
2047 log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL, 0);
2048
2049 /* Events during pop commands may need to be ignored here. */
2050 consumed = checkForPopFrameEvents(env, ei, thread);
2051 if ( consumed ) {
2052 /* Always restore any exception (see below). */
2053 if (currentException != NULL) {
2054 JNI_FUNC_PTR(env,Throw)(env, currentException);
2055 } else {
2056 JNI_FUNC_PTR(env,ExceptionClear)(env);
2057 }
2058 return NULL;
2059 }
2060
2061 debugMonitorEnter(threadLock);
2062
2063 /*
2064 * Check the list of unknown threads maintained by suspend
2065 * and resume. If this thread is currently present in the
2066 * list, it should be
2067 * moved to the runningThreads list, since it is a
2068 * well-known thread now.
2069 */
2070 node = findThread(&otherThreads, thread);
2071 if (node != NULL) {
2072 moveNode(&otherThreads, &runningThreads, node);
2073 } else {
2074 /*
2075 * Get a thread node for the reporting thread. For thread start
2076 * events, or if this event precedes a thread start event,
2077 * the thread node may need to be created.
2078 *
2079 * It is possible for certain events (notably method entry/exit)
2080 * to precede thread start for some VM implementations.
2081 */
2082 node = insertThread(env, &runningThreads, thread);
2083 }
2084
2085 if (ei == EI_THREAD_START) {
2086 node->isStarted = JNI_TRUE;
2087 processDeferredEventModes(env, thread, node);
2088 }
2089
2090 node->current_ei = ei;
2091 eventBag = node->eventBag;
2092 if (node->suspendOnStart) {
2093 threadToSuspend = node->thread;
2094 }
2095 debugMonitorExit(threadLock);
2096
2097 if (threadToSuspend != NULL) {
2098 /*
2099 * An attempt was made to suspend this thread before it started.
2100 * We must suspend it now, before it starts to run. This must
2101 * be done with no locks held.
2102 */
2103 eventHelper_suspendThread(sessionID, threadToSuspend);
2104 }
2105
2106 return eventBag;
2107 }
2108
2109 static void
doPendingTasks(JNIEnv * env,ThreadNode * node)2110 doPendingTasks(JNIEnv *env, ThreadNode *node)
2111 {
2112 /*
2113 * Take care of any pending interrupts/stops, and clear out
2114 * info on pending interrupts/stops.
2115 */
2116 if (node->pendingInterrupt) {
2117 JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2118 (gdata->jvmti, node->thread);
2119 /*
2120 * TO DO: Log error
2121 */
2122 node->pendingInterrupt = JNI_FALSE;
2123 }
2124
2125 if (node->pendingStop != NULL) {
2126 JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2127 (gdata->jvmti, node->thread, node->pendingStop);
2128 /*
2129 * TO DO: Log error
2130 */
2131 tossGlobalRef(env, &(node->pendingStop));
2132 }
2133 }
2134
2135 void
threadControl_onEventHandlerExit(EventIndex ei,jthread thread,struct bag * eventBag)2136 threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
2137 struct bag *eventBag)
2138 {
2139 ThreadNode *node;
2140
2141 log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0);
2142
2143 if (ei == EI_THREAD_END) {
2144 eventHandler_lock(); /* for proper lock order */
2145 }
2146 debugMonitorEnter(threadLock);
2147
2148 node = findThread(&runningThreads, thread);
2149 if (node == NULL) {
2150 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2151 } else {
2152 JNIEnv *env;
2153
2154 env = getEnv();
2155 if (ei == EI_THREAD_END) {
2156 jboolean inResume = (node->resumeFrameDepth > 0);
2157 removeThread(env, &runningThreads, thread);
2158 node = NULL; /* has been freed */
2159
2160 /*
2161 * Clean up mechanism used to detect end of
2162 * resume.
2163 */
2164 if (inResume) {
2165 notifyAppResumeComplete();
2166 }
2167 } else {
2168 /* No point in doing this if the thread is about to die.*/
2169 doPendingTasks(env, node);
2170 node->eventBag = eventBag;
2171 node->current_ei = 0;
2172 }
2173 }
2174
2175 debugMonitorExit(threadLock);
2176 if (ei == EI_THREAD_END) {
2177 eventHandler_unlock();
2178 }
2179 }
2180
2181 /* Returns JDWP flavored status and status flags. */
2182 jvmtiError
threadControl_applicationThreadStatus(jthread thread,jdwpThreadStatus * pstatus,jint * statusFlags)2183 threadControl_applicationThreadStatus(jthread thread,
2184 jdwpThreadStatus *pstatus, jint *statusFlags)
2185 {
2186 ThreadNode *node;
2187 jvmtiError error;
2188 jint state;
2189
2190 log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2191
2192 debugMonitorEnter(threadLock);
2193
2194 error = threadState(thread, &state);
2195 *pstatus = map2jdwpThreadStatus(state);
2196 *statusFlags = map2jdwpSuspendStatus(state);
2197
2198 if (error == JVMTI_ERROR_NONE) {
2199 node = findThread(&runningThreads, thread);
2200 if ((node != NULL) && HANDLING_EVENT(node)) {
2201 /*
2202 * While processing an event, an application thread is always
2203 * considered to be running even if its handler happens to be
2204 * cond waiting on an internal debugger monitor, etc.
2205 *
2206 * Leave suspend status untouched since it is not possible
2207 * to distinguish debugger suspends from app suspends.
2208 */
2209 *pstatus = JDWP_THREAD_STATUS(RUNNING);
2210 }
2211 }
2212
2213 debugMonitorExit(threadLock);
2214
2215 return error;
2216 }
2217
2218 jvmtiError
threadControl_interrupt(jthread thread)2219 threadControl_interrupt(jthread thread)
2220 {
2221 ThreadNode *node;
2222 jvmtiError error;
2223
2224 error = JVMTI_ERROR_NONE;
2225
2226 log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2227
2228 debugMonitorEnter(threadLock);
2229
2230 node = findThread(&runningThreads, thread);
2231 if ((node == NULL) || !HANDLING_EVENT(node)) {
2232 error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2233 (gdata->jvmti, thread);
2234 } else {
2235 /*
2236 * Hold any interrupts until after the event is processed.
2237 */
2238 node->pendingInterrupt = JNI_TRUE;
2239 }
2240
2241 debugMonitorExit(threadLock);
2242
2243 return error;
2244 }
2245
2246 void
threadControl_clearCLEInfo(JNIEnv * env,jthread thread)2247 threadControl_clearCLEInfo(JNIEnv *env, jthread thread)
2248 {
2249 ThreadNode *node;
2250
2251 debugMonitorEnter(threadLock);
2252
2253 node = findThread(&runningThreads, thread);
2254 if (node != NULL) {
2255 node->cleInfo.ei = 0;
2256 if (node->cleInfo.clazz != NULL) {
2257 tossGlobalRef(env, &(node->cleInfo.clazz));
2258 }
2259 }
2260
2261 debugMonitorExit(threadLock);
2262 }
2263
2264 jboolean
threadControl_cmpCLEInfo(JNIEnv * env,jthread thread,jclass clazz,jmethodID method,jlocation location)2265 threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz,
2266 jmethodID method, jlocation location)
2267 {
2268 ThreadNode *node;
2269 jboolean result;
2270
2271 result = JNI_FALSE;
2272
2273 debugMonitorEnter(threadLock);
2274
2275 node = findThread(&runningThreads, thread);
2276 if (node != NULL && node->cleInfo.ei != 0 &&
2277 node->cleInfo.method == method &&
2278 node->cleInfo.location == location &&
2279 (isSameObject(env, node->cleInfo.clazz, clazz))) {
2280 result = JNI_TRUE; /* we have a match */
2281 }
2282
2283 debugMonitorExit(threadLock);
2284
2285 return result;
2286 }
2287
2288 void
threadControl_saveCLEInfo(JNIEnv * env,jthread thread,EventIndex ei,jclass clazz,jmethodID method,jlocation location)2289 threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
2290 jclass clazz, jmethodID method, jlocation location)
2291 {
2292 ThreadNode *node;
2293
2294 debugMonitorEnter(threadLock);
2295
2296 node = findThread(&runningThreads, thread);
2297 if (node != NULL) {
2298 node->cleInfo.ei = ei;
2299 /* Create a class ref that will live beyond */
2300 /* the end of this call */
2301 saveGlobalRef(env, clazz, &(node->cleInfo.clazz));
2302 /* if returned clazz is NULL, we just won't match */
2303 node->cleInfo.method = method;
2304 node->cleInfo.location = location;
2305 }
2306
2307 debugMonitorExit(threadLock);
2308 }
2309
2310 void
threadControl_setPendingInterrupt(jthread thread)2311 threadControl_setPendingInterrupt(jthread thread)
2312 {
2313 ThreadNode *node;
2314
2315 debugMonitorEnter(threadLock);
2316
2317 node = findThread(&runningThreads, thread);
2318 if (node != NULL) {
2319 node->pendingInterrupt = JNI_TRUE;
2320 }
2321
2322 debugMonitorExit(threadLock);
2323 }
2324
2325 jvmtiError
threadControl_stop(jthread thread,jobject throwable)2326 threadControl_stop(jthread thread, jobject throwable)
2327 {
2328 ThreadNode *node;
2329 jvmtiError error;
2330
2331 error = JVMTI_ERROR_NONE;
2332
2333 log_debugee_location("threadControl_stop()", thread, NULL, 0);
2334
2335 debugMonitorEnter(threadLock);
2336
2337 node = findThread(&runningThreads, thread);
2338 if ((node == NULL) || !HANDLING_EVENT(node)) {
2339 error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2340 (gdata->jvmti, thread, throwable);
2341 } else {
2342 JNIEnv *env;
2343
2344 /*
2345 * Hold any stops until after the event is processed.
2346 */
2347 env = getEnv();
2348 saveGlobalRef(env, throwable, &(node->pendingStop));
2349 }
2350
2351 debugMonitorExit(threadLock);
2352
2353 return error;
2354 }
2355
2356 static jvmtiError
detachHelper(JNIEnv * env,ThreadNode * node,void * arg)2357 detachHelper(JNIEnv *env, ThreadNode *node, void *arg)
2358 {
2359 invoker_detach(&node->currentInvoke);
2360 return JVMTI_ERROR_NONE;
2361 }
2362
2363 void
threadControl_detachInvokes(void)2364 threadControl_detachInvokes(void)
2365 {
2366 JNIEnv *env;
2367
2368 env = getEnv();
2369 invoker_lock(); /* for proper lock order */
2370 debugMonitorEnter(threadLock);
2371 (void)enumerateOverThreadList(env, &runningThreads, detachHelper, NULL);
2372 debugMonitorExit(threadLock);
2373 invoker_unlock();
2374 }
2375
2376 static jvmtiError
resetHelper(JNIEnv * env,ThreadNode * node,void * arg)2377 resetHelper(JNIEnv *env, ThreadNode *node, void *arg)
2378 {
2379 if (node->toBeResumed) {
2380 LOG_MISC(("thread=%p resumed", node->thread));
2381 (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, node->thread);
2382 node->frameGeneration++; /* Increment on each resume */
2383 }
2384 stepControl_clearRequest(node->thread, &node->currentStep);
2385 node->toBeResumed = JNI_FALSE;
2386 node->suspendCount = 0;
2387 node->suspendOnStart = JNI_FALSE;
2388
2389 return JVMTI_ERROR_NONE;
2390 }
2391
2392 void
threadControl_reset(void)2393 threadControl_reset(void)
2394 {
2395 JNIEnv *env;
2396
2397 env = getEnv();
2398 eventHandler_lock(); /* for proper lock order */
2399 debugMonitorEnter(threadLock);
2400 (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2401 (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);
2402
2403 removeResumed(env, &otherThreads);
2404
2405 freeDeferredEventModes(env);
2406
2407 suspendAllCount = 0;
2408
2409 /* Everything should have been resumed */
2410 JDI_ASSERT(otherThreads.first == NULL);
2411
2412 debugMonitorExit(threadLock);
2413 eventHandler_unlock();
2414 }
2415
2416 jvmtiEventMode
threadControl_getInstructionStepMode(jthread thread)2417 threadControl_getInstructionStepMode(jthread thread)
2418 {
2419 ThreadNode *node;
2420 jvmtiEventMode mode;
2421
2422 mode = JVMTI_DISABLE;
2423
2424 debugMonitorEnter(threadLock);
2425 node = findThread(&runningThreads, thread);
2426 if (node != NULL) {
2427 mode = node->instructionStepMode;
2428 }
2429 debugMonitorExit(threadLock);
2430 return mode;
2431 }
2432
2433 jvmtiError
threadControl_setEventMode(jvmtiEventMode mode,EventIndex ei,jthread thread)2434 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2435 {
2436 jvmtiError error;
2437
2438 /* Global event */
2439 if ( thread == NULL ) {
2440 error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2441 (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2442 } else {
2443 /* Thread event */
2444 ThreadNode *node;
2445
2446 debugMonitorEnter(threadLock);
2447 {
2448 node = findThread(&runningThreads, thread);
2449 if ((node == NULL) || (!node->isStarted)) {
2450 JNIEnv *env;
2451
2452 env = getEnv();
2453 error = addDeferredEventMode(env, mode, ei, thread);
2454 } else {
2455 error = threadSetEventNotificationMode(node,
2456 mode, ei, thread);
2457 }
2458 }
2459 debugMonitorExit(threadLock);
2460
2461 }
2462 return error;
2463 }
2464
2465 /*
2466 * Returns the current thread, if the thread has generated at least
2467 * one event, and has not generated a thread end event.
2468 */
threadControl_currentThread(void)2469 jthread threadControl_currentThread(void)
2470 {
2471 jthread thread;
2472
2473 debugMonitorEnter(threadLock);
2474 {
2475 ThreadNode *node;
2476
2477 node = findThread(&runningThreads, NULL);
2478 thread = (node == NULL) ? NULL : node->thread;
2479 }
2480 debugMonitorExit(threadLock);
2481
2482 return thread;
2483 }
2484
2485 jlong
threadControl_getFrameGeneration(jthread thread)2486 threadControl_getFrameGeneration(jthread thread)
2487 {
2488 jlong frameGeneration = -1;
2489
2490 debugMonitorEnter(threadLock);
2491 {
2492 ThreadNode *node;
2493
2494 node = findThread(NULL, thread);
2495
2496 if (node != NULL) {
2497 frameGeneration = node->frameGeneration;
2498 }
2499 }
2500 debugMonitorExit(threadLock);
2501
2502 return frameGeneration;
2503 }
2504