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 */
43typedef 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 */
64typedef 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
89static jint suspendAllCount;
90
91typedef struct ThreadList {
92    ThreadNode *first;
93} ThreadList;
94
95/*
96 * popFrameEventLock is used to notify that the event has been received
97 */
98static 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 */
104static jrawMonitorID popFrameProceedLock = NULL;
105
106static jrawMonitorID threadLock;
107static jlocation resumeLocation;
108static HandlerNode *breakpointHandlerNode;
109static HandlerNode *framePopHandlerNode;
110static HandlerNode *catchHandlerNode;
111
112static 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 */
119static ThreadList runningThreads;
120static ThreadList otherThreads;
121
122#define MAX_DEBUG_THREADS 10
123static int debugThreadCount;
124static jthread debugThreads[MAX_DEBUG_THREADS];
125
126typedef struct DeferredEventMode {
127    EventIndex ei;
128    jvmtiEventMode mode;
129    jthread thread;
130    struct DeferredEventMode *next;
131} DeferredEventMode;
132
133typedef struct {
134    DeferredEventMode *first;
135    DeferredEventMode *last;
136} DeferredEventModeList;
137
138static DeferredEventModeList deferredEventModes;
139
140static jint
141getStackDepth(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 */
155static jvmtiError
156threadState(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* */
164static void
165setThreadLocalStorage(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* */
181static ThreadNode *
182getThreadLocalStorage(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 */
207static ThreadNode *
208nonTlsSearch(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 */
225static ThreadNode *
226findThread(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 */
262static void
263removeNode(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 */
285static void
286addNode(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
301static ThreadNode *
302insertThread(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
362static void
363clearThread(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
379static void
380removeThread(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
391static void
392removeResumed(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
406static void
407moveNode(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
414typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);
415
416static jvmtiError
417enumerateOverThreadList(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
432static void
433insertEventMode(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
443static void
444removeEventMode(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
456static jvmtiError
457addDeferredEventMode(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
475static void
476freeDeferredEventModes(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
491static jvmtiError
492threadSetEventNotificationMode(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
506static void
507processDeferredEventModes(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
533static void
534getLocks(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
553static void
554releaseLocks(void)
555{
556    debugMonitorExit(threadLock);
557    commonRef_unlock();
558    stepControl_unlock();
559    eventHelper_unlock();
560    invoker_unlock();
561    eventHandler_unlock();
562}
563
564void
565threadControl_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
588static jthread
589getResumee(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
605static jboolean
606pendingAppResume(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
635static void
636notifyAppResumeComplete(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
651static void
652handleAppResumeCompletion(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
680static void
681blockOnDebuggerSuspend(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
694static void
695trackAppResume(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
735static void
736handleAppResumeBreakpoint(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
768void
769threadControl_onConnect(void)
770{
771    breakpointHandlerNode = eventHandler_createInternalBreakpoint(
772                 handleAppResumeBreakpoint, NULL,
773                 gdata->threadClass, gdata->threadResume, resumeLocation);
774}
775
776void
777threadControl_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
793void
794threadControl_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
846static jvmtiError
847commonSuspendByNode(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 */
881static jint
882deferredSuspendThreadByNode(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
916static jvmtiError
917suspendThreadByNode(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
959static jvmtiError
960resumeThreadByNode(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 */
1006static void
1007preSuspend(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
1038static void
1039postSuspend(void)
1040{
1041    releaseLocks();
1042}
1043
1044/*
1045 * This function must be called after preSuspend and before postSuspend.
1046 */
1047static jvmtiError
1048commonSuspend(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
1070static jvmtiError
1071resumeCopyHelper(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
1125static jvmtiError
1126resumeCountHelper(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
1147static void *
1148newArray(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
1158static void
1159deleteArray(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 */
1187static jvmtiError
1188commonResumeList(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 */
1257static jvmtiError
1258commonSuspendList(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
1366static jvmtiError
1367commonResume(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
1390jvmtiError
1391threadControl_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
1407jvmtiError
1408threadControl_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
1432jvmtiError
1433threadControl_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
1461static jboolean
1462contains(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
1475typedef struct {
1476    jthread *list;
1477    jint count;
1478} SuspendAllArg;
1479
1480static jvmtiError
1481suspendAllHelper(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
1493jvmtiError
1494threadControl_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
1561static jvmtiError
1562resumeHelper(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
1572jvmtiError
1573threadControl_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
1616StepRequest *
1617threadControl_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
1636InvokeRequest *
1637threadControl_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
1656jvmtiError
1657threadControl_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
1681static jvmtiError
1682threadControl_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
1709jboolean
1710threadControl_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
1730static void
1731initLocks(void)
1732{
1733    if (popFrameEventLock == NULL) {
1734        popFrameEventLock = debugMonitorCreate("JDWP PopFrame Event Lock");
1735        popFrameProceedLock = debugMonitorCreate("JDWP PopFrame Proceed Lock");
1736    }
1737}
1738
1739static jboolean
1740getPopFrameThread(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
1760static void
1761setPopFrameThread(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
1777static jboolean
1778getPopFrameEvent(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
1799static void
1800setPopFrameEvent(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
1817static jboolean
1818getPopFrameProceed(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
1839static void
1840setPopFrameProceed(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 */
1860static void
1861popFrameCompleteEvent(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 */
1886static jvmtiError
1887popOneFrame(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 */
1929jvmtiError
1930threadControl_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(). */
1998static jboolean
1999checkForPopFrameEvents(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
2033struct bag *
2034threadControl_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
2107static void
2108doPendingTasks(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
2133void
2134threadControl_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. */
2180jvmtiError
2181threadControl_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
2216jvmtiError
2217threadControl_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
2244void
2245threadControl_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
2262jboolean
2263threadControl_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
2286void
2287threadControl_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
2308void
2309threadControl_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
2323jvmtiError
2324threadControl_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
2354static jvmtiError
2355detachHelper(JNIEnv *env, ThreadNode *node, void *arg)
2356{
2357    invoker_detach(&node->currentInvoke);
2358    return JVMTI_ERROR_NONE;
2359}
2360
2361void
2362threadControl_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
2374static jvmtiError
2375resetHelper(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
2390void
2391threadControl_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
2414jvmtiEventMode
2415threadControl_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
2431jvmtiError
2432threadControl_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 */
2467jthread 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
2483jlong
2484threadControl_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