1 /*
   2  * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "util.h"
  27 #include "eventHandler.h"
  28 #include "threadControl.h"
  29 #include "commonRef.h"
  30 #include "eventHelper.h"
  31 #include "stepControl.h"
  32 #include "invoker.h"
  33 #include "bag.h"
  34 
  35 #define HANDLING_EVENT(node) ((node)->current_ei != 0)
  36 
  37 /*
  38  * Collection of info for properly handling co-located events.
  39  * If the ei field is non-zero, then one of the possible
  40  * co-located events has been posted and the other fields describe
  41  * the event's location.
  42  *
  43  * See comment above deferEventReport() for an explanation of co-located events.
  44  */
  45 typedef struct CoLocatedEventInfo_ {
  46     EventIndex ei;
  47     jclass    clazz;
  48     jmethodID method;
  49     jlocation location;
  50 } CoLocatedEventInfo;
  51 
  52 /**
  53  * The main data structure in threadControl is the ThreadNode.
  54  * This is a per-thread structure that is allocated on the
  55  * first event that occurs in a thread. It is freed after the
  56  * thread's thread end event has completed processing. The
  57  * structure contains state information on its thread including
  58  * suspend counts. It also acts as a repository for other
  59  * per-thread state such as the current method invocation or
  60  * current step.
  61  *
  62  * suspendCount is the number of outstanding suspends
  63  * from the debugger. suspends from the app itself are
  64  * not included in this count.
  65  */
  66 typedef struct ThreadNode {
  67     jthread thread;
  68     unsigned int toBeResumed : 1;      /* true if this thread was successfully suspended. */
  69     unsigned int pendingInterrupt : 1; /* true if thread is interrupted while handling an event. */
  70     unsigned int isDebugThread : 1;    /* true if this is one of our debug agent threads. */
  71     unsigned int suspendOnStart : 1;   /* true for new threads if we are currently in a VM.suspend(). */
  72     unsigned int isStarted : 1;        /* THREAD_START or VIRTUAL_THREAD_START event received. */
  73     unsigned int is_vthread : 1;
  74     unsigned int popFrameEvent : 1;
  75     unsigned int popFrameProceed : 1;
  76     unsigned int popFrameThread : 1;
  77     unsigned int handlingAppResume : 1;
  78     EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */
  79     jobject pendingStop;   /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */
  80     jint suspendCount;
  81     jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */
  82     jvmtiEventMode instructionStepMode;
  83     StepRequest currentStep;
  84     InvokeRequest currentInvoke;
  85     struct bag *eventBag;       /* Accumulation of JDWP events to be sent as a reply. */
  86     CoLocatedEventInfo cleInfo; /* See comment above deferEventReport() for an explanation. */
  87     struct ThreadNode *next;
  88     struct ThreadNode *prev;
  89     jlong frameGeneration;    /* used to generate a unique frameID. Incremented whenever existing frameID
  90                                  needs to be invalidated, such as when the thread is resumed. */
  91     struct ThreadList *list;  /* Tells us what list this thread is in. */
  92 #ifdef DEBUG_THREADNAME
  93     char name[256];
  94 #endif
  95 } ThreadNode;
  96 
  97 static jint suspendAllCount;
  98 
  99 typedef struct ThreadList {
 100     ThreadNode *first;
 101 } ThreadList;
 102 
 103 /*
 104  * popFrameEventLock is used to notify that the event has been received
 105  */
 106 static jrawMonitorID popFrameEventLock = NULL;
 107 
 108 /*
 109  * popFrameProceedLock is used to assure that the event thread is
 110  * re-suspended immediately after the event is acknowledged.
 111  */
 112 static jrawMonitorID popFrameProceedLock = NULL;
 113 
 114 static jrawMonitorID threadLock;
 115 static jlocation resumeLocation;
 116 static HandlerNode *breakpointHandlerNode;
 117 static HandlerNode *framePopHandlerNode;
 118 static HandlerNode *catchHandlerNode;
 119 
 120 static jvmtiError threadControl_removeDebugThread(jthread thread);
 121 
 122 /*
 123  * Threads which have issued thread start events and not yet issued thread
 124  * end events are maintained in the "runningThreads" list. All other threads known
 125  * to this module are kept in the "otherThreads" list.
 126  */
 127 static ThreadList runningThreads;
 128 static ThreadList otherThreads;
 129 static ThreadList runningVThreads; /* VThreads we have seen. */
 130 
 131 #define MAX_DEBUG_THREADS 10
 132 static int debugThreadCount;
 133 static jthread debugThreads[MAX_DEBUG_THREADS];
 134 
 135 typedef struct DeferredEventMode {
 136     EventIndex ei;
 137     jvmtiEventMode mode;
 138     jthread thread;
 139     struct DeferredEventMode *next;
 140 } DeferredEventMode;
 141 
 142 typedef struct {
 143     DeferredEventMode *first;
 144     DeferredEventMode *last;
 145 } DeferredEventModeList;
 146 
 147 static DeferredEventModeList deferredEventModes;
 148 
 149 #ifdef DEBUG
 150 static void dumpThreadList(ThreadList *list);
 151 static void dumpThread(ThreadNode *node);
 152 #endif
 153 
 154 static jint
 155 getStackDepth(jthread thread)
 156 {
 157     jint count = 0;
 158     jvmtiError error;
 159 
 160     error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
 161                         (gdata->jvmti, thread, &count);
 162     if (error != JVMTI_ERROR_NONE) {
 163         EXIT_ERROR(error, "getting frame count");
 164     }
 165     return count;
 166 }
 167 
 168 /* Get the state of the thread direct from JVMTI */
 169 static jvmtiError
 170 threadState(jthread thread, jint *pstate)
 171 {
 172     *pstate = 0;
 173     return JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState)
 174                         (gdata->jvmti, thread, pstate);
 175 }
 176 
 177 /* Set TLS on a specific jthread to the ThreadNode* */
 178 static void
 179 setThreadLocalStorage(jthread thread, ThreadNode *node)
 180 {
 181     jvmtiError  error;
 182 
 183     error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage)
 184             (gdata->jvmti, thread, (void*)node);
 185     if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE && node == NULL) {
 186         /* Just return. This can happen when clearing the TLS. */
 187         return;
 188     } else if ( error != JVMTI_ERROR_NONE ) {
 189         /* The jthread object must be valid, so this must be a fatal error */
 190         EXIT_ERROR(error, "cannot set thread local storage");
 191     }
 192 }
 193 
 194 /* Get TLS on a specific jthread, which is the ThreadNode* */
 195 static ThreadNode *
 196 getThreadLocalStorage(jthread thread)
 197 {
 198     jvmtiError  error;
 199     ThreadNode *node;
 200 
 201     node = NULL;
 202     error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadLocalStorage)
 203             (gdata->jvmti, thread, (void**)&node);
 204     if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
 205         /* Just return NULL, thread hasn't started yet */
 206         return NULL;
 207     } else if ( error != JVMTI_ERROR_NONE ) {
 208         /* The jthread object must be valid, so this must be a fatal error */
 209         EXIT_ERROR(error, "cannot get thread local storage");
 210     }
 211     return node;
 212 }
 213 
 214 /* Search list for nodes that don't have TLS set and match this thread.
 215  *   It assumed that this logic is never dealing with terminated threads,
 216  *   since the ThreadEnd events always delete the ThreadNode while the
 217  *   jthread is still alive.  So we can only look at the ThreadNode's that
 218  *   have never had their TLS set, making the search much faster.
 219  *   But keep in mind, this kind of search should rarely be needed.
 220  */
 221 static ThreadNode *
 222 nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
 223 {
 224     ThreadNode *node;
 225 
 226     for (node = list->first; node != NULL; node = node->next) {
 227         if (isSameObject(env, node->thread, thread)) {
 228             break;
 229         }
 230     }
 231     return node;
 232 }
 233 
 234 /*
 235  * These functions maintain the linked list of currently running threads and vthreads.
 236  * All assume that the threadLock is held before calling.
 237  */
 238 
 239 /*
 240  * Search for a thread on the list. If list==NULL, search all lists.
 241  */
 242 static ThreadNode *
 243 findThread(ThreadList *list, jthread thread)
 244 {
 245     ThreadNode *node;
 246     JNIEnv *env = getEnv();
 247 
 248     /* Get thread local storage for quick thread -> node access */
 249     node = getThreadLocalStorage(thread);
 250 
 251     if ( node == NULL ) {
 252         /*
 253          * If the thread was not yet started when the ThreadNode was created, then it
 254          * got added to the otherThreads list and its thread local storage was not set.
 255          * Search for it in the otherThreads list.
 256          */
 257         if ( list == NULL || list == &otherThreads ) {
 258             node = nonTlsSearch(getEnv(), &otherThreads, thread);
 259         }
 260         /*
 261          * Normally we can assume that a thread with no TLS will never be in the runningThreads
 262          * list. This is because we always set the TLS when adding to runningThreads.
 263          * However, when a thread exits, its TLS is automatically cleared. Normally this
 264          * is not a problem because the debug agent will first get a THREAD_END event,
 265          * and that will cause the thread to be removed from runningThreads, thus we
 266          * avoid this situation of having a thread in runningThreads, but with no TLS.
 267          *
 268          * However... there is one exception to this. While handling VM_DEATH, the first thing
 269          * the debug agent does is clear all the callbacks. This means we will no longer
 270          * get THREAD_END events as threads exit. This means we might find threads on
 271          * runningThreads with no TLS during VM_DEATH. Essentially the THREAD_END that
 272          * would normally have resulted in removing the thread from runningThreads is
 273          * missed, so the thread remains on runningThreads.
 274          *
 275          * The end result of all this is that if the TLS lookup failed, we still need to check
 276          * if the thread is on runningThreads, but only if JVMTI callbacks have been cleared.
 277          * Otherwise the thread should not be on the runningThreads.
 278          */
 279         if ( !gdata->jvmtiCallBacksCleared ) {
 280             /* The thread better not be on runningThreads if the TLS lookup failed. */
 281             JDI_ASSERT(!nonTlsSearch(getEnv(), &runningThreads, thread));
 282         } else {
 283             /*
 284              * Search the runningThreads list. The TLS lookup may have failed because the
 285              * thread has terminated, but we never got the THREAD_END event.
 286              */
 287             if ( node == NULL ) {
 288                 if ( list == NULL || list == &runningThreads ) {
 289                     node = nonTlsSearch(getEnv(), &runningThreads, thread);
 290                 }
 291             }
 292         }
 293     }
 294 
 295     /* If a list is supplied, only return ones in this list */
 296     if ( node != NULL && list != NULL && node->list != list ) {
 297         return NULL;
 298     }
 299     return node;
 300 }
 301 
 302 /* Search for a running thread, including vthreads. */
 303 static ThreadNode *
 304 findRunningThread(jthread thread)
 305 {
 306     ThreadNode *node;
 307     if (isVThread(thread)) {
 308         node = findThread(&runningVThreads, thread);
 309     } else {
 310         node = findThread(&runningThreads, thread);
 311     }
 312     return node;
 313 }
 314 
 315 /* Remove a ThreadNode from a ThreadList */
 316 static void
 317 removeNode(ThreadList *list, ThreadNode *node)
 318 {
 319     ThreadNode *prev;
 320     ThreadNode *next;
 321 
 322     prev = node->prev;
 323     next = node->next;
 324     if ( prev != NULL ) {
 325         prev->next = next;
 326     }
 327     if ( next != NULL ) {
 328         next->prev = prev;
 329     }
 330     if ( prev == NULL ) {
 331         list->first = next;
 332     }
 333     node->next = NULL;
 334     node->prev = NULL;
 335     node->list = NULL;
 336 }
 337 
 338 /* Add a ThreadNode to a ThreadList */
 339 static void
 340 addNode(ThreadList *list, ThreadNode *node)
 341 {
 342     node->next = NULL;
 343     node->prev = NULL;
 344     node->list = NULL;
 345     if ( list->first == NULL ) {
 346         list->first = node;
 347     } else {
 348         list->first->prev = node;
 349         node->next = list->first;
 350         list->first = node;
 351     }
 352     node->list = list;
 353 }
 354 
 355 static ThreadNode *
 356 insertThread(JNIEnv *env, ThreadList *list, jthread thread)
 357 {
 358     ThreadNode *node;
 359     struct bag *eventBag;
 360     jboolean is_vthread = (list == &runningVThreads);
 361 
 362     node = findThread(list, thread);
 363     if (node == NULL) {
 364         node = jvmtiAllocate(sizeof(*node));
 365         if (node == NULL) {
 366             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 367             return NULL;
 368         }
 369         (void)memset(node, 0, sizeof(*node));
 370         eventBag = eventHelper_createEventBag();
 371         if (eventBag == NULL) {
 372             jvmtiDeallocate(node);
 373             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 374             return NULL;
 375         }
 376 
 377         /*
 378          * Init all flags false, all refs NULL, all counts 0
 379          */
 380 
 381         saveGlobalRef(env, thread, &(node->thread));
 382         if (node->thread == NULL) {
 383             jvmtiDeallocate(node);
 384             bagDestroyBag(eventBag);
 385             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 386             return NULL;
 387         }
 388         if (!is_vthread) {
 389             if (threadControl_isDebugThread(node->thread)) {
 390                 /* Remember if it is a debug thread */
 391                 node->isDebugThread = JNI_TRUE;
 392             } else {
 393                 if (suspendAllCount > 0) {
 394                     /*
 395                      * If there is a pending suspendAll, all new threads should
 396                      * be initialized as if they were suspended by the suspendAll,
 397                      * and the thread will need to be suspended when it starts.
 398                      */
 399                     node->suspendCount = suspendAllCount;
 400                     node->suspendOnStart = JNI_TRUE;
 401                 }
 402             }
 403         } else { /* vthread */
 404             jint vthread_state = 0;
 405             jvmtiError error = threadState(node->thread, &vthread_state);
 406             if (error != JVMTI_ERROR_NONE) {
 407                 EXIT_ERROR(error, "getting thread state");
 408             }
 409             if (suspendAllCount > 0) {
 410                 // Assume the suspendAllCount, just like the regular thread case above.
 411                 node->suspendCount = suspendAllCount;
 412                 if (vthread_state == 0) {
 413                     // If state == 0, then this is a new vthread that has not been started yet.
 414                     // Need to suspendOnStart in that case, just like the regular thread case above.
 415                     node->suspendOnStart = JNI_TRUE;
 416                     list = &otherThreads; // Put on otherThreads list instead of runningVThreads
 417                 }
 418             }
 419             if (vthread_state != 0) {
 420                 // This is an already started vthread that we were not already tracking.
 421                 node->isStarted = JNI_TRUE;
 422             }
 423         }
 424 
 425         node->current_ei = 0;
 426         node->is_vthread = is_vthread;
 427         node->instructionStepMode = JVMTI_DISABLE;
 428         node->eventBag = eventBag;
 429         addNode(list, node);
 430 
 431 #ifdef DEBUG_THREADNAME
 432         {
 433             /* Set the thread name */
 434             jvmtiThreadInfo info;
 435             jvmtiError error;
 436 
 437             memset(&info, 0, sizeof(info));
 438             error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
 439                     (gdata->jvmti, node->thread, &info);
 440             if (info.name != NULL) {
 441                 strncpy(node->name, info.name, sizeof(node->name) - 1);
 442                 jvmtiDeallocate(info.name);
 443             }
 444         }
 445 #endif
 446 
 447         /* Set thread local storage for quick thread -> node access.
 448          *   Threads that are not yet started do not allow setting of TLS. These
 449          *   threads go on the otherThreads list and have their TLS set
 450          *   when moved to the runningThreads list. findThread() knows to look
 451          *   on otherThreads when the TLS lookup fails.
 452          */
 453         if (list != &otherThreads) {
 454             setThreadLocalStorage(node->thread, (void*)node);
 455         }
 456     }
 457 
 458     return node;
 459 }
 460 
 461 static void
 462 clearThread(JNIEnv *env, ThreadNode *node)
 463 {
 464     if (node->pendingStop != NULL) {
 465         tossGlobalRef(env, &(node->pendingStop));
 466     }
 467     stepControl_clearRequest(node->thread, &node->currentStep);
 468     if (node->isDebugThread) {
 469         (void)threadControl_removeDebugThread(node->thread);
 470     }
 471     /* Clear out TLS on this thread (just a cleanup action) */
 472     setThreadLocalStorage(node->thread, NULL);
 473     tossGlobalRef(env, &(node->thread));
 474     bagDestroyBag(node->eventBag);
 475     jvmtiDeallocate(node);
 476 }
 477 
 478 static void
 479 removeThread(JNIEnv *env, ThreadList *list, jthread thread)
 480 {
 481     ThreadNode *node;
 482 
 483     node = findThread(list, thread);
 484     if (node != NULL) {
 485         removeNode(list, node);
 486         clearThread(env, node);
 487     }
 488 }
 489 
 490 static void
 491 removeResumed(JNIEnv *env, ThreadList *list)
 492 {
 493     ThreadNode *node;
 494 
 495     node = list->first;
 496     while (node != NULL) {
 497         ThreadNode *temp = node->next;
 498         if (node->suspendCount == 0) {
 499             removeThread(env, list, node->thread);
 500         }
 501         node = temp;
 502     }
 503 }
 504 
 505 static void
 506 moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node)
 507 {
 508     removeNode(source, node);
 509     // vthread fixme: we should really fix the caller to pass the right list
 510     if (node->is_vthread && dest == &runningThreads) {
 511         dest = &runningVThreads;
 512     }
 513     JDI_ASSERT(findThread(dest, node->thread) == NULL);
 514     addNode(dest, node);
 515 }
 516 
 517 typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);
 518 
 519 static jvmtiError
 520 enumerateOverThreadList(JNIEnv *env, ThreadList *list,
 521                         ThreadEnumerateFunction function, void *arg)
 522 {
 523     ThreadNode *node;
 524     jvmtiError error = JVMTI_ERROR_NONE;
 525 
 526     for (node = list->first; node != NULL; node = node->next) {
 527         error = (*function)(env, node, arg);
 528         if ( error != JVMTI_ERROR_NONE ) {
 529             break;
 530         }
 531     }
 532     return error;
 533 }
 534 
 535 static void
 536 insertEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode)
 537 {
 538     if (list->last != NULL) {
 539         list->last->next = eventMode;
 540     } else {
 541         list->first = eventMode;
 542     }
 543     list->last = eventMode;
 544 }
 545 
 546 static void
 547 removeEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode, DeferredEventMode *prev)
 548 {
 549     if (prev == NULL) {
 550         list->first = eventMode->next;
 551     } else {
 552         prev->next = eventMode->next;
 553     }
 554     if (eventMode->next == NULL) {
 555         list->last = prev;
 556     }
 557 }
 558 
 559 static jvmtiError
 560 addDeferredEventMode(JNIEnv *env, jvmtiEventMode mode, EventIndex ei, jthread thread)
 561 {
 562     DeferredEventMode *eventMode;
 563 
 564     /*LINTED*/
 565     eventMode = jvmtiAllocate((jint)sizeof(DeferredEventMode));
 566     if (eventMode == NULL) {
 567         return AGENT_ERROR_OUT_OF_MEMORY;
 568     }
 569     eventMode->thread = NULL;
 570     saveGlobalRef(env, thread, &(eventMode->thread));
 571     eventMode->mode = mode;
 572     eventMode->ei = ei;
 573     eventMode->next = NULL;
 574     insertEventMode(&deferredEventModes, eventMode);
 575     return JVMTI_ERROR_NONE;
 576 }
 577 
 578 static void
 579 freeDeferredEventModes(JNIEnv *env)
 580 {
 581     DeferredEventMode *eventMode;
 582     eventMode = deferredEventModes.first;
 583     while (eventMode != NULL) {
 584         DeferredEventMode *next;
 585         next = eventMode->next;
 586         tossGlobalRef(env, &(eventMode->thread));
 587         jvmtiDeallocate(eventMode);
 588         eventMode = next;
 589     }
 590     deferredEventModes.first = NULL;
 591     deferredEventModes.last = NULL;
 592 }
 593 
 594 static jvmtiError
 595 threadSetEventNotificationMode(ThreadNode *node,
 596         jvmtiEventMode mode, EventIndex ei, jthread thread)
 597 {
 598     jvmtiError error;
 599 
 600     /* record single step mode */
 601     if (ei == EI_SINGLE_STEP) {
 602         node->instructionStepMode = mode;
 603     }
 604     error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
 605         (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
 606     return error;
 607 }
 608 
 609 static void
 610 processDeferredEventModes(JNIEnv *env, jthread thread, ThreadNode *node)
 611 {
 612     jvmtiError error;
 613     DeferredEventMode *eventMode;
 614     DeferredEventMode *prev;
 615 
 616     prev = NULL;
 617     eventMode = deferredEventModes.first;
 618     while (eventMode != NULL) {
 619         DeferredEventMode *next = eventMode->next;
 620         if (isSameObject(env, thread, eventMode->thread)) {
 621             error = threadSetEventNotificationMode(node,
 622                     eventMode->mode, eventMode->ei, eventMode->thread);
 623             if (error != JVMTI_ERROR_NONE) {
 624                 EXIT_ERROR(error, "cannot process deferred thread event notifications at thread start");
 625             }
 626             removeEventMode(&deferredEventModes, eventMode, prev);
 627             tossGlobalRef(env, &(eventMode->thread));
 628             jvmtiDeallocate(eventMode);
 629         } else {
 630             prev = eventMode;
 631         }
 632         eventMode = next;
 633     }
 634 }
 635 
 636 static void
 637 getLocks(void)
 638 {
 639     /*
 640      * Anything which might be locked as part of the handling of
 641      * a JVMTI event (which means: might be locked by an application
 642      * thread) needs to be grabbed here. This allows thread control
 643      * code to safely suspend and resume the application threads
 644      * while ensuring they don't hold a critical lock.
 645      */
 646 
 647     eventHandler_lock();
 648     invoker_lock();
 649     eventHelper_lock();
 650     stepControl_lock();
 651     commonRef_lock();
 652     debugMonitorEnter(threadLock);
 653 
 654 }
 655 
 656 static void
 657 releaseLocks(void)
 658 {
 659     debugMonitorExit(threadLock);
 660     commonRef_unlock();
 661     stepControl_unlock();
 662     eventHelper_unlock();
 663     invoker_unlock();
 664     eventHandler_unlock();
 665 }
 666 
 667 void
 668 threadControl_initialize(void)
 669 {
 670     jlocation unused;
 671     jvmtiError error;
 672 
 673     suspendAllCount = 0;
 674     runningThreads.first = NULL;
 675     otherThreads.first = NULL;
 676     runningVThreads.first = NULL;
 677     debugThreadCount = 0;
 678     threadLock = debugMonitorCreate("JDWP Thread Lock");
 679     if (gdata->threadClass==NULL) {
 680         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class");
 681     }
 682     if (gdata->threadResume==0) {
 683         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread");
 684     }
 685     /* Get the java.lang.Thread.resume() method beginning location */
 686     error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
 687     if (error != JVMTI_ERROR_NONE) {
 688         EXIT_ERROR(error, "getting method location");
 689     }
 690 }
 691 
 692 static jthread
 693 getResumee(jthread resumingThread)
 694 {
 695     jthread resumee = NULL;
 696     jvmtiError error;
 697     jobject object;
 698     FrameNumber fnum = 0;
 699 
 700     error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
 701                     (gdata->jvmti, resumingThread, fnum, 0, &object);
 702     if (error == JVMTI_ERROR_NONE) {
 703         resumee = object;
 704     }
 705     return resumee;
 706 }
 707 
 708 
 709 static jboolean
 710 pendingAppResume(jboolean includeSuspended)
 711 {
 712     ThreadList *list;
 713     ThreadNode *node;
 714 
 715     list = &runningThreads;
 716     node = list->first;
 717     while (node != NULL) {
 718         if (node->resumeFrameDepth > 0) {
 719             if (includeSuspended) {
 720                 return JNI_TRUE;
 721             } else {
 722                 jvmtiError error;
 723                 jint       state;
 724 
 725                 error = threadState(node->thread, &state);
 726                 if (error != JVMTI_ERROR_NONE) {
 727                     EXIT_ERROR(error, "getting thread state");
 728                 }
 729                 /* !node->handlingAppResume && resumeFrameDepth > 0
 730                  * means the thread has entered Thread.resume() */
 731                 if (!(state & JVMTI_THREAD_STATE_SUSPENDED) &&
 732                     !node->handlingAppResume) {
 733                     return JNI_TRUE;
 734                 }
 735             }
 736         }
 737         node = node->next;
 738         if (node == NULL && list == &runningThreads) {
 739             // We need to look at runningVThreads after we are done with runningThreads.
 740             list = &runningVThreads;
 741             node = list->first;
 742         }
 743     }
 744     return JNI_FALSE;
 745 }
 746 
 747 static void
 748 notifyAppResumeComplete(void)
 749 {
 750     debugMonitorNotifyAll(threadLock);
 751     if (!pendingAppResume(JNI_TRUE)) {
 752         if (framePopHandlerNode != NULL) {
 753             (void)eventHandler_free(framePopHandlerNode);
 754             framePopHandlerNode = NULL;
 755         }
 756         if (catchHandlerNode != NULL) {
 757             (void)eventHandler_free(catchHandlerNode);
 758             catchHandlerNode = NULL;
 759         }
 760     }
 761 }
 762 
 763 /*
 764  * Event handler for FRAME_POP and EXCEPTION_CATCH when in Thread.resume()
 765  * so we can detect its completion.
 766  */
 767 static void
 768 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
 769                           HandlerNode *handlerNode,
 770                           struct bag *eventBag)
 771 {
 772     ThreadNode *node;
 773     jthread     thread;
 774 
 775     thread = evinfo->thread;
 776 
 777     debugMonitorEnter(threadLock);
 778 
 779     node = findRunningThread(thread);
 780     if (node != NULL) {
 781         if (node->resumeFrameDepth > 0) {
 782             jint compareDepth = getStackDepth(thread);
 783             if (evinfo->ei == EI_FRAME_POP) {
 784                 compareDepth--;
 785             }
 786             if (compareDepth < node->resumeFrameDepth) {
 787                 node->resumeFrameDepth = 0;
 788                 notifyAppResumeComplete();
 789             }
 790         }
 791     }
 792 
 793     debugMonitorExit(threadLock);
 794 }
 795 
 796 static void
 797 blockOnDebuggerSuspend(jthread thread)
 798 {
 799     ThreadNode *node;
 800 
 801     node = findThread(NULL, thread);
 802     if (node != NULL) {
 803         while (node && node->suspendCount > 0) {
 804             debugMonitorWait(threadLock);
 805             node = findThread(NULL, thread);
 806         }
 807     }
 808 }
 809 
 810 /*
 811  * The caller is expected to hold threadLock and handlerLock.
 812  * eventHandler_createInternalThreadOnly() can deadlock because of
 813  * wrong lock ordering if the caller does not hold handlerLock.
 814  */
 815 static void
 816 trackAppResume(jthread thread)
 817 {
 818     jvmtiError  error;
 819     FrameNumber fnum;
 820     ThreadNode *node;
 821 
 822     fnum = 0;
 823     node = findRunningThread(thread);
 824     if (node != NULL) {
 825         JDI_ASSERT(node->resumeFrameDepth == 0);
 826         error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
 827                         (gdata->jvmti, thread, fnum);
 828         if (error == JVMTI_ERROR_NONE) {
 829             jint frameDepth = getStackDepth(thread);
 830             if ((frameDepth > 0) && (framePopHandlerNode == NULL)) {
 831                 framePopHandlerNode = eventHandler_createInternalThreadOnly(
 832                                            EI_FRAME_POP,
 833                                            handleAppResumeCompletion,
 834                                            thread);
 835                 catchHandlerNode = eventHandler_createInternalThreadOnly(
 836                                            EI_EXCEPTION_CATCH,
 837                                            handleAppResumeCompletion,
 838                                            thread);
 839                 if ((framePopHandlerNode == NULL) ||
 840                     (catchHandlerNode == NULL)) {
 841                     (void)eventHandler_free(framePopHandlerNode);
 842                     framePopHandlerNode = NULL;
 843                     (void)eventHandler_free(catchHandlerNode);
 844                     catchHandlerNode = NULL;
 845                 }
 846             }
 847             if ((framePopHandlerNode != NULL) &&
 848                 (catchHandlerNode != NULL) &&
 849                 (frameDepth > 0)) {
 850                 node->resumeFrameDepth = frameDepth;
 851             }
 852         }
 853     }
 854 }
 855 
 856 /* Global breakpoint handler for Thread.resume() */
 857 static void
 858 handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo,
 859                           HandlerNode *handlerNode,
 860                           struct bag *eventBag)
 861 {
 862     jthread resumer = evinfo->thread;
 863 
 864     debugMonitorEnter(threadLock);
 865 
 866     /*
 867      * Actual handling has to be deferred. We cannot block right here if the
 868      * target of the resume call is suspended by the debugger since we are
 869      * holding handlerLock which must not be released. See doPendingTasks().
 870      */
 871     if (resumer != NULL) {
 872         ThreadNode* node = findThread(&runningThreads, resumer);
 873         if (node != NULL) {
 874             node->handlingAppResume = JNI_TRUE;
 875         }
 876     }
 877 
 878     debugMonitorExit(threadLock);
 879 }
 880 
 881 void
 882 threadControl_onConnect(void)
 883 {
 884     breakpointHandlerNode = eventHandler_createInternalBreakpoint(
 885                  handleAppResumeBreakpoint, NULL,
 886                  gdata->threadClass, gdata->threadResume, resumeLocation);
 887 }
 888 
 889 void
 890 threadControl_onDisconnect(void)
 891 {
 892     if (breakpointHandlerNode != NULL) {
 893         (void)eventHandler_free(breakpointHandlerNode);
 894         breakpointHandlerNode = NULL;
 895     }
 896     if (framePopHandlerNode != NULL) {
 897         (void)eventHandler_free(framePopHandlerNode);
 898         framePopHandlerNode = NULL;
 899     }
 900     if (catchHandlerNode != NULL) {
 901         (void)eventHandler_free(catchHandlerNode);
 902         catchHandlerNode = NULL;
 903     }
 904 }
 905 
 906 void
 907 threadControl_onHook(void)
 908 {
 909     /*
 910      * As soon as the event hook is in place, we need to initialize
 911      * the thread list with already-existing threads. The threadLock
 912      * has been held since initialize, so we don't need to worry about
 913      * insertions or deletions from the event handlers while we do this
 914      */
 915     JNIEnv *env;
 916 
 917     env = getEnv();
 918 
 919     /*
 920      * Prevent any event processing until OnHook has been called
 921      */
 922     debugMonitorEnter(threadLock);
 923 
 924     WITH_LOCAL_REFS(env, 1) {
 925 
 926         jint threadCount;
 927         jthread *threads;
 928 
 929         threads = allThreads(&threadCount);
 930         if (threads == NULL) {
 931             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table");
 932         } else {
 933 
 934             int i;
 935 
 936             for (i = 0; i < threadCount; i++) {
 937                 ThreadNode *node;
 938                 jthread thread = threads[i];
 939                 node = insertThread(env, &runningThreads, thread);
 940 
 941                 /*
 942                  * This is a tiny bit risky. We have to assume that the
 943                  * pre-existing threads have been started because we
 944                  * can't rely on a thread start event for them. The chances
 945                  * of a problem related to this are pretty slim though, and
 946                  * there's really no choice because without setting this flag
 947                  * there is no way to enable stepping and other events on
 948                  * the threads that already exist (e.g. the finalizer thread).
 949                  */
 950                 node->isStarted = JNI_TRUE;
 951             }
 952             jvmtiDeallocate(threads);
 953         }
 954 
 955     } END_WITH_LOCAL_REFS(env)
 956 
 957     debugMonitorExit(threadLock);
 958 }
 959 
 960 static jvmtiError
 961 commonSuspendByNode(ThreadNode *node)
 962 {
 963     jvmtiError error;
 964 
 965     LOG_MISC(("thread=%p suspended", node->thread));
 966     error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)
 967                 (gdata->jvmti, node->thread);
 968 
 969     /*
 970      * Mark for resume only if suspend succeeded
 971      */
 972     if (error == JVMTI_ERROR_NONE) {
 973         node->toBeResumed = JNI_TRUE;
 974     }
 975 
 976     /*
 977      * If the thread was suspended by another app thread,
 978      * do nothing and report no error (we won't resume it later).
 979      */
 980      if (error == JVMTI_ERROR_THREAD_SUSPENDED) {
 981         error = JVMTI_ERROR_NONE;
 982      }
 983 
 984      return error;
 985 }
 986 
 987 /*
 988  * Deferred suspends happen when the suspend is attempted on a thread
 989  * that is not started. Bookkeeping (suspendCount,etc.)
 990  * is handled by the original request, and once the thread actually
 991  * starts, an actual suspend is attempted. This function does the
 992  * deferred suspend without changing the bookkeeping that is already
 993  * in place.
 994  */
 995 static jint
 996 deferredSuspendThreadByNode(ThreadNode *node)
 997 {
 998     jvmtiError error;
 999 
1000     error = JVMTI_ERROR_NONE;
1001     if (node->isDebugThread) {
1002         /* Ignore requests for suspending debugger threads */
1003         return JVMTI_ERROR_NONE;
1004     }
1005 
1006     /*
1007      * Do the actual suspend only if a subsequent resume hasn't
1008      * made it irrelevant.
1009      */
1010     if (node->suspendCount > 0) {
1011         error = commonSuspendByNode(node);
1012 
1013         /*
1014          * Attempt to clean up from any error by decrementing the
1015          * suspend count. This compensates for the increment that
1016          * happens when suspendOnStart is set to true.
1017          */
1018         if (error != JVMTI_ERROR_NONE) {
1019             node->suspendCount--;
1020         }
1021     }
1022 
1023     node->suspendOnStart = JNI_FALSE;
1024 
1025     debugMonitorNotifyAll(threadLock);
1026 
1027     return error;
1028 }
1029 
1030 static jvmtiError
1031 suspendThreadByNode(ThreadNode *node)
1032 {
1033     jvmtiError error = JVMTI_ERROR_NONE;
1034     if (node->isDebugThread) {
1035         /* Ignore requests for suspending debugger threads */
1036         return JVMTI_ERROR_NONE;
1037     }
1038 
1039     /*
1040      * Just increment the suspend count if we are waiting
1041      * for a deferred suspend.
1042      */
1043     if (node->suspendOnStart) {
1044         node->suspendCount++;
1045         return JVMTI_ERROR_NONE;
1046     }
1047 
1048     if (node->suspendCount == 0) {
1049         error = commonSuspendByNode(node);
1050 
1051         if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1052             /*
1053              * This error means that the thread is either a zombie or not yet
1054              * started. In either case, we ignore the error. If the thread
1055              * is a zombie, suspend/resume are no-ops. If the thread is not
1056              * started, it will be suspended for real during the processing
1057              * of its thread start event.
1058              */
1059             node->suspendOnStart = JNI_TRUE;
1060             error = JVMTI_ERROR_NONE;
1061         }
1062     }
1063 
1064     if (error == JVMTI_ERROR_NONE) {
1065         node->suspendCount++;
1066     }
1067 
1068     debugMonitorNotifyAll(threadLock);
1069 
1070     return error;
1071 }
1072 
1073 static jvmtiError
1074 resumeThreadByNode(ThreadNode *node)
1075 {
1076     jvmtiError error = JVMTI_ERROR_NONE;
1077 
1078     if (node->isDebugThread) {
1079         /* never suspended by debugger => don't ever try to resume */
1080         return JVMTI_ERROR_NONE;
1081     }
1082     if (node->suspendCount > 0) {
1083         node->suspendCount--;
1084         debugMonitorNotifyAll(threadLock);
1085         if ((node->suspendCount == 0) && node->toBeResumed &&
1086             !node->suspendOnStart) {
1087             LOG_MISC(("thread=%p resumed", node->thread));
1088             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
1089                         (gdata->jvmti, node->thread);
1090             node->frameGeneration++; /* Increment on each resume */
1091             node->toBeResumed = JNI_FALSE;
1092             if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
1093                 /*
1094                  * We successfully "suspended" this thread, but
1095                  * we never received a THREAD_START event for it.
1096                  * Since the thread never ran, we can ignore our
1097                  * failure to resume the thread.
1098                  */
1099                 error = JVMTI_ERROR_NONE;
1100             }
1101         }
1102         // vthread fixme: If this is a vthread and suspendCount == 0, we should delete the node.
1103     }
1104 
1105     return error;
1106 }
1107 
1108 /*
1109  * Functions which respond to user requests to suspend/resume
1110  * threads.
1111  * Suspends and resumes add and subtract from a count respectively.
1112  * The thread is only suspended when the count goes from 0 to 1 and
1113  * resumed only when the count goes from 1 to 0.
1114  *
1115  * These functions suspend and resume application threads
1116  * without changing the
1117  * state of threads that were already suspended beforehand.
1118  * They must not be called from an application thread because
1119  * that thread may be suspended somewhere in the  middle of things.
1120  */
1121 static void
1122 preSuspend(void)
1123 {
1124     getLocks();                     /* Avoid debugger deadlocks */
1125 
1126     /*
1127      * Delay any suspend while a call to java.lang.Thread.resume is in
1128      * progress (not including those in suspended threads). The wait is
1129      * timed because the threads suspended through
1130      * java.lang.Thread.suspend won't result in a notify even though
1131      * it may change the result of pendingAppResume()
1132      */
1133     while (pendingAppResume(JNI_FALSE)) {
1134         /*
1135          * This is ugly but we need to release the locks from getLocks
1136          * or else the notify will never happen. The locks must be
1137          * released and reacquired in the right order. else deadlocks
1138          * can happen. It is possible that, during this dance, the
1139          * notify will be missed, but since the wait needs to be timed
1140          * anyway, it won't be a disaster. Note that this code will
1141          * execute only on very rare occasions anyway.
1142          */
1143         releaseLocks();
1144 
1145         debugMonitorEnter(threadLock);
1146         debugMonitorTimedWait(threadLock, 1000);
1147         debugMonitorExit(threadLock);
1148 
1149         getLocks();
1150     }
1151 }
1152 
1153 static void
1154 postSuspend(void)
1155 {
1156     releaseLocks();
1157 }
1158 
1159 /*
1160  * This function must be called after preSuspend and before postSuspend.
1161  */
1162 static jvmtiError
1163 commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1164 {
1165     ThreadNode *node;
1166 
1167     node = findRunningThread(thread);
1168 
1169     if (node == NULL) {
1170         if (isVThread(thread)) {
1171             /*
1172              * Since we don't track all vthreads, it might not be in the list already. Start
1173              * tracking it now.
1174              */
1175             node = insertThread(env, &runningVThreads, thread);
1176         } else {
1177             /*
1178              * If the thread is not between its start and end events, we should
1179              * still suspend it. To keep track of things, add the thread
1180              * to a separate list of threads so that we'll resume it later.
1181              */
1182             node = insertThread(env, &otherThreads, thread);
1183         }
1184     }
1185 
1186 #if 0
1187     tty_message("commonSuspend: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1188 #endif



1189 
1190     if ( deferred ) {
1191         return deferredSuspendThreadByNode(node);
1192     } else {
1193         return suspendThreadByNode(node);
1194     }
1195 }
1196 
1197 
1198 static jvmtiError
1199 resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1200 {
1201     if (node->isDebugThread) {
1202         /* never suspended by debugger => don't ever try to resume */
1203         return JVMTI_ERROR_NONE;
1204     }
1205 
1206     if (node->suspendCount > 1) {
1207         node->suspendCount--;
1208         /* nested suspend so just undo one level */
1209         return JVMTI_ERROR_NONE;
1210     }
1211 
1212     /*
1213      * This thread was marked for suspension since its THREAD_START
1214      * event came in during a suspendAll, but the helper hasn't
1215      * completed the job yet. We decrement the count so the helper
1216      * won't suspend this thread after we are done with the resumeAll.
1217      * Another case to be handled here is when the debugger suspends
1218      * the thread while the app has it suspended. In this case,
1219      * the toBeResumed flag has been cleared indicating that
1220      * the thread should not be resumed when the debugger does a resume.
1221      * In this case, we also have to decrement the suspend count.
1222      * If we don't then when the app resumes the thread and our Thread.resume
1223      * bkpt handler is called, blockOnDebuggerSuspend will not resume
1224      * the thread because suspendCount will be 1 meaning that the
1225      * debugger has the thread suspended.  See bug 6224859.
1226      */
1227     if (node->suspendCount == 1 && (!node->toBeResumed || node->suspendOnStart)) {
1228         node->suspendCount--;
1229         // vthread fixme: If this is a vthread, we should delete the node.
1230         return JVMTI_ERROR_NONE;
1231     }
1232 
1233     if (arg == NULL) {
1234         /* nothing to hard resume so we're done */
1235         return JVMTI_ERROR_NONE;
1236     }
1237 
1238     /*
1239      * This is tricky. A suspendCount of 1 and toBeResumed means that
1240      * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1241      * on this thread. The check for !suspendOnStart is paranoia that
1242      * we inherited from resumeThreadByNode().
1243      */
1244     if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1245         jthread **listPtr = (jthread **)arg;
1246 
1247         **listPtr = node->thread;
1248         (*listPtr)++;
1249     }
1250     return JVMTI_ERROR_NONE;
1251 }
1252 
1253 
1254 static jvmtiError
1255 resumeCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1256 {
1257     if (node->isDebugThread) {
1258         /* never suspended by debugger => don't ever try to resume */
1259         return JVMTI_ERROR_NONE;
1260     }
1261 
1262     /*
1263      * This is tricky. A suspendCount of 1 and toBeResumed means that
1264      * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1265      * on this thread. The check for !suspendOnStart is paranoia that
1266      * we inherited from resumeThreadByNode().
1267      */
1268     if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1269         jint *counter = (jint *)arg;
1270 
1271         (*counter)++;
1272     }
1273     return JVMTI_ERROR_NONE;
1274 }
1275 
1276 static void *
1277 newArray(jint length, size_t nbytes)
1278 {
1279     void *ptr;
1280     ptr = jvmtiAllocate(length*(jint)nbytes);
1281     if ( ptr != NULL ) {
1282         (void)memset(ptr, 0, length*nbytes);
1283     }
1284     return ptr;
1285 }
1286 
1287 static void
1288 deleteArray(void *ptr)
1289 {
1290     jvmtiDeallocate(ptr);
1291 }
1292 
1293 /*
1294  * This function must be called with the threadLock held.
1295  *
1296  * Two facts conspire to make this routine complicated:
1297  *
1298  * 1) the VM doesn't support nested external suspend
1299  * 2) the original resumeAll code structure doesn't retrieve the
1300  *    entire thread list from JVMTI so we use the runningThreads
1301  *    list and two helpers to get the job done.
1302  *
1303  * Because we hold the threadLock, state seen by resumeCountHelper()
1304  * is the same state seen in resumeCopyHelper(). resumeCountHelper()
1305  * just counts up the number of threads to be hard resumed.
1306  * resumeCopyHelper() does the accounting for nested suspends and
1307  * special cases and, finally, populates the list of hard resume
1308  * threads to be passed to ResumeThreadList().
1309  *
1310  * At first glance, you might think that the accounting could be done
1311  * in resumeCountHelper(), but then resumeCopyHelper() would see
1312  * "post-resume" state in the accounting values (suspendCount and
1313  * toBeResumed) and would not be able to distinguish between a thread
1314  * that needs a hard resume versus a thread that is already running.
1315  */
1316 static jvmtiError
1317 commonResumeList(JNIEnv *env)
1318 {
1319     jvmtiError   error;
1320     jint         i;
1321     jint         reqCnt;
1322     jthread     *reqList;
1323     jthread     *reqPtr;
1324     jvmtiError  *results;
1325 
1326     reqCnt = 0;
1327 
1328     /* count number of threads to hard resume */
1329     (void) enumerateOverThreadList(env, &runningThreads, resumeCountHelper,
1330                                    &reqCnt);
1331     (void) enumerateOverThreadList(env, &runningVThreads, resumeCountHelper,
1332                                    &reqCnt);
1333     if (reqCnt == 0) {
1334         /* nothing to hard resume so do just the accounting part */
1335         (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1336                                        NULL);
1337         (void) enumerateOverThreadList(env, &runningVThreads, resumeCopyHelper,
1338                                        NULL);
1339         return JVMTI_ERROR_NONE;
1340     }
1341 
1342     /*LINTED*/
1343     reqList = newArray(reqCnt, sizeof(jthread));
1344     if (reqList == NULL) {
1345         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume request list");
1346     }
1347     /*LINTED*/
1348     results = newArray(reqCnt, sizeof(jvmtiError));
1349     if (results == NULL) {
1350         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume list");
1351     }
1352 
1353     /* copy the jthread values for threads to hard resume */
1354     reqPtr = reqList;
1355     (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1356                                    &reqPtr);
1357     (void) enumerateOverThreadList(env, &runningVThreads, resumeCopyHelper,
1358                                    &reqPtr);
1359 
1360     error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThreadList)
1361                 (gdata->jvmti, reqCnt, reqList, results);
1362     for (i = 0; i < reqCnt; i++) {
1363         ThreadNode *node;
1364 
1365         node = findRunningThread(reqList[i]);
1366         if (node == NULL) {
1367             EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in running thread table");
1368         }
1369         LOG_MISC(("thread=%p resumed as part of list", node->thread));
1370 
1371         /*
1372          * resumeThreadByNode() assumes that JVM/DI ResumeThread()
1373          * always works and does all the accounting updates. We do
1374          * the same here. We also don't clear the error.
1375          */
1376         node->suspendCount--;
1377         node->toBeResumed = JNI_FALSE;
1378         node->frameGeneration++; /* Increment on each resume */
1379 
1380         // vthread fixme: If this is a vthread, we should delete the node.
1381     }
1382     deleteArray(results);
1383     deleteArray(reqList);
1384 
1385     debugMonitorNotifyAll(threadLock);
1386 
1387     return error;
1388 }
1389 
1390 
1391 /*
1392  * This function must be called after preSuspend and before postSuspend.
1393  */
1394 static jvmtiError
1395 commonSuspendList(JNIEnv *env, jint initCount, jthread *initList)
1396 {
1397     jvmtiError  error;
1398     jint        i;
1399     jint        reqCnt;
1400     jthread    *reqList;
1401 
1402     error   = JVMTI_ERROR_NONE;
1403     reqCnt  = 0;
1404     reqList = newArray(initCount, sizeof(jthread));
1405     if (reqList == NULL) {
1406         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"request list");
1407     }
1408 
1409     /*
1410      * Go through the initial list and see if we have anything to suspend.
1411      */
1412     for (i = 0; i < initCount; i++) {
1413         ThreadNode *node;
1414 
1415         /*
1416          * If the thread is not between its start and end events, we should
1417          * still suspend it. To keep track of things, add the thread
1418          * to a separate list of threads so that we'll resume it later.
1419          */
1420         node = findThread(&runningThreads, initList[i]);
1421         if (node == NULL) {
1422             node = insertThread(env, &otherThreads, initList[i]);
1423         }
1424 
1425         if (node->isDebugThread) {
1426             /* Ignore requests for suspending debugger threads */
1427             continue;
1428         }
1429 
1430         /*
1431          * Just increment the suspend count if we are waiting
1432          * for a deferred suspend or if this is a nested suspend.
1433          */
1434         if (node->suspendOnStart || node->suspendCount > 0) {
1435             node->suspendCount++;
1436             continue;
1437         }
1438 
1439         if (node->suspendCount == 0) {
1440             /* thread is not suspended yet so put it on the request list */
1441             reqList[reqCnt++] = initList[i];
1442         }
1443     }
1444 
1445     if (reqCnt > 0) {
1446         jvmtiError *results = newArray(reqCnt, sizeof(jvmtiError));
1447 
1448         if (results == NULL) {
1449             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"suspend list results");
1450         }
1451 
1452         /*
1453          * We have something to suspend so try to do it.
1454          */
1455         error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThreadList)
1456                         (gdata->jvmti, reqCnt, reqList, results);
1457         for (i = 0; i < reqCnt; i++) {
1458             ThreadNode *node;
1459 
1460             node = findThread(NULL, reqList[i]);
1461             if (node == NULL) {
1462                 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in thread tables");
1463             }
1464             LOG_MISC(("thread=%p suspended as part of list", node->thread));
1465 
1466             if (results[i] == JVMTI_ERROR_NONE) {
1467                 /* thread was suspended as requested */
1468                 node->toBeResumed = JNI_TRUE;
1469             } else if (results[i] == JVMTI_ERROR_THREAD_SUSPENDED) {
1470                 /*
1471                  * If the thread was suspended by another app thread,
1472                  * do nothing and report no error (we won't resume it later).
1473                  */
1474                 results[i] = JVMTI_ERROR_NONE;
1475             } else if (results[i] == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1476                 /*
1477                  * This error means that the suspend request failed
1478                  * because the thread is either a zombie or not yet
1479                  * started. In either case, we ignore the error. If the
1480                  * thread is a zombie, suspend/resume are no-ops. If the
1481                  * thread is not started, it will be suspended for real
1482                  * during the processing of its thread start event.
1483                  */
1484                 node->suspendOnStart = JNI_TRUE;
1485                 results[i] = JVMTI_ERROR_NONE;
1486             }
1487 
1488             /* count real, app and deferred (suspendOnStart) suspensions */
1489             if (results[i] == JVMTI_ERROR_NONE) {
1490                 node->suspendCount++;
1491             }
1492         }
1493         deleteArray(results);
1494     }
1495     deleteArray(reqList);
1496 
1497     debugMonitorNotifyAll(threadLock);
1498 
1499     return error;
1500 }
1501 
1502 static jvmtiError
1503 commonResume(jthread thread)
1504 {
1505     jvmtiError  error;
1506     ThreadNode *node;
1507 
1508     /*
1509      * The thread is normally between its start and end events, but if
1510      * not, check the auxiliary list used by threadControl_suspendThread.
1511      */
1512     node = findThread(NULL, thread);
1513 #if 0
1514     tty_message("commonResume: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1515 #endif
1516 
1517     /*
1518      * If the node is in neither list, the debugger never suspended
1519      * this thread, so do nothing.
1520      */
1521     error = JVMTI_ERROR_NONE;
1522     if (node != NULL) {
1523         error = resumeThreadByNode(node);
1524     }
1525     return error;
1526 }
1527 
1528 
1529 jvmtiError
1530 threadControl_suspendThread(jthread thread, jboolean deferred)
1531 {
1532     jvmtiError error;
1533     JNIEnv    *env;
1534 
1535     env = getEnv();
1536 
1537     log_debugee_location("threadControl_suspendThread()", thread, NULL, 0);
1538 
1539     preSuspend();
1540     error = commonSuspend(env, thread, deferred);
1541     postSuspend();
1542 
1543     return error;
1544 }
1545 
1546 jvmtiError
1547 threadControl_resumeThread(jthread thread, jboolean do_unblock)
1548 {
1549     jvmtiError error;
1550     JNIEnv    *env;
1551 
1552     env = getEnv();
1553 
1554     log_debugee_location("threadControl_resumeThread()", thread, NULL, 0);
1555 
1556     eventHandler_lock(); /* for proper lock order */
1557     debugMonitorEnter(threadLock);
1558     error = commonResume(thread);
1559     removeResumed(env, &otherThreads);
1560     debugMonitorExit(threadLock);
1561     eventHandler_unlock();
1562 
1563     if (do_unblock) {
1564         /* let eventHelper.c: commandLoop() know we resumed one thread */
1565         unblockCommandLoop();
1566     }
1567 
1568     return error;
1569 }
1570 
1571 jvmtiError
1572 threadControl_suspendCount(jthread thread, jint *count)
1573 {
1574     jvmtiError  error;
1575     ThreadNode *node;
1576     jboolean is_vthread = isVThread(thread);
1577 
1578     debugMonitorEnter(threadLock);
1579 
1580     if (is_vthread) {
1581         node = findThread(&runningVThreads, thread);
1582     } else {
1583         node = findThread(&runningThreads, thread);
1584     }
1585     if (node == NULL) {
1586         node = findThread(&otherThreads, thread);
1587     }
1588 
1589     error = JVMTI_ERROR_NONE;
1590     if (node != NULL) {
1591         *count = node->suspendCount;
1592     } else {
1593         /*
1594          * If the node is in neither list, the debugger never suspended
1595          * this thread, so the suspend count is 0.
1596          */
1597       if (is_vthread) {
1598           jint vthread_state = 0;
1599           jvmtiError error = threadState(thread, &vthread_state);
1600           if (error != JVMTI_ERROR_NONE) {
1601               EXIT_ERROR(error, "getting thread state");
1602           }
1603           if (vthread_state == 0) {
1604               // If state == 0, then this is a new vthread that has not been started yet.
1605               *count = 0;
1606           } else {
1607               // This is a started vthread that we are not tracking. Use suspendAllCount.
1608               *count = suspendAllCount;
1609           }
1610       } else {
1611         *count = 0;
1612       }
1613     }
1614 
1615     debugMonitorExit(threadLock);
1616 
1617     return error;
1618 }
1619 
1620 static jboolean
1621 contains(JNIEnv *env, jthread *list, jint count, jthread item)
1622 {
1623     int i;
1624 
1625     for (i = 0; i < count; i++) {
1626         if (isSameObject(env, list[i], item)) {
1627             return JNI_TRUE;
1628         }
1629     }
1630     return JNI_FALSE;
1631 }
1632 
1633 
1634 static jvmtiError
1635 incrementSuspendCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1636 {
1637     node->toBeResumed = JNI_TRUE;
1638     node->suspendCount++;
1639     return JVMTI_ERROR_NONE;
1640 }
1641 
1642 typedef struct {
1643     jthread *list;
1644     jint count;
1645 } SuspendAllArg;
1646 
1647 static jvmtiError
1648 suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1649 {
1650     SuspendAllArg *saArg = (SuspendAllArg *)arg;
1651     jvmtiError error = JVMTI_ERROR_NONE;
1652     jthread *list = saArg->list;
1653     jint count = saArg->count;
1654     if (!contains(env, list, count, node->thread)) {
1655         error = commonSuspend(env, node->thread, JNI_FALSE);
1656     }
1657     return error;
1658 }
1659 
1660 jvmtiError
1661 threadControl_suspendAll(void)
1662 {
1663     jvmtiError error;
1664     JNIEnv    *env;
1665 #if 0
1666     tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount);
1667 #endif
1668 
1669     env = getEnv();
1670 
1671     log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0);
1672 
1673     preSuspend();
1674 
1675     /*
1676      * Get a list of all threads and suspend them.
1677      */
1678     WITH_LOCAL_REFS(env, 1) {
1679 
1680         jthread *threads;
1681         jint count;
1682 
1683         if (gdata->vthreadsSupported) {
1684             /* Tell JVMTI to suspend all virtual threads. */
1685             if (suspendAllCount == 0) {
1686                 error = JVMTI_FUNC_PTR(gdata->jvmti, SuspendAllVirtualThreads)
1687                         (gdata->jvmti, 0, NULL);
1688                 if (error != JVMTI_ERROR_NONE) {
1689                     EXIT_ERROR(error, "cannot suspend all virtual threads");
1690                 }
1691                 // We need a notify here just like we do any time we suspend a thread.
1692                 // See commonSuspendList() and suspendThreadByNode().
1693                 debugMonitorNotifyAll(threadLock);
1694             }
1695 
1696             /*
1697              * Increment suspendCount of each virtual thread that we are tracking. Note the
1698              * compliment to this that happens during the resumeAll() is handled by
1699              * commonResumeList(), so it's a bit orthogonal to how we handle incrementing
1700              * the suspendCount.
1701              */
1702             error = enumerateOverThreadList(env, &runningVThreads, incrementSuspendCountHelper, NULL);
1703             JDI_ASSERT(error == JVMTI_ERROR_NONE);
1704         }
1705 
1706         threads = allThreads(&count);
1707         if (threads == NULL) {
1708             error = AGENT_ERROR_OUT_OF_MEMORY;
1709             goto err;
1710         }
1711         error = commonSuspendList(env, count, threads);
1712         if (error != JVMTI_ERROR_NONE) {
1713             goto err;
1714         }
1715 
1716         /*
1717          * Update the suspend count of any threads not yet (or no longer)
1718          * in the thread list above.
1719          */
1720         {
1721             SuspendAllArg arg;
1722             arg.list = threads;
1723             arg.count = count;
1724             error = enumerateOverThreadList(env, &otherThreads,
1725                                             suspendAllHelper, &arg);
1726         }
1727 
1728         if (error == JVMTI_ERROR_NONE) {
1729             /*
1730              * Pin all objects to prevent objects from being
1731              * garbage collected while the VM is suspended.
1732              */
1733             commonRef_pinAll();
1734 
1735             suspendAllCount++;
1736         }
1737 
1738     err:
1739         jvmtiDeallocate(threads);
1740 
1741     } END_WITH_LOCAL_REFS(env)
1742 
1743     postSuspend();
1744 
1745     return error;
1746 }
1747 
1748 static jvmtiError
1749 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1750 {
1751     /*
1752      * Since this helper is called with the threadLock held, we
1753      * don't need to recheck to see if the node is still on one
1754      * of the two thread lists.
1755      */
1756     return resumeThreadByNode(node);
1757 }
1758 
1759 static jvmtiError
1760 excludeCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1761 {
1762     JDI_ASSERT(node->is_vthread);
1763     if (node->suspendCount > 0) {
1764         jint *counter = (jint *)arg;
1765         (*counter)++;
1766     }
1767     return JVMTI_ERROR_NONE;
1768 }
1769 
1770 static jvmtiError
1771 excludeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1772 {
1773     JDI_ASSERT(node->is_vthread);
1774     if (node->suspendCount > 0) {
1775         jthread **listPtr = (jthread **)arg;
1776         **listPtr = node->thread;
1777         (*listPtr)++;
1778     }
1779     return JVMTI_ERROR_NONE;
1780 }
1781 
1782 jvmtiError
1783 threadControl_resumeAll(void)
1784 {
1785     jvmtiError error;
1786     JNIEnv    *env;
1787 #if 0
1788     tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount);
1789 #endif
1790 
1791     env = getEnv();
1792 
1793     log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1794 
1795     eventHandler_lock(); /* for proper lock order */
1796     debugMonitorEnter(threadLock);
1797 
1798     if (gdata->vthreadsSupported) {
1799         if (suspendAllCount == 1) {
1800             jint excludeCnt = 0;
1801             jthread *excludeList = NULL;
1802             /*
1803              * Tell JVMTI to resume all virtual threads except for those we
1804              * are tracking separately. The commonResumeList() call below will
1805              * resume any vthread with a suspendCount == 1, and we want to ignore
1806              * vthreads with a suspendCount > 0. Therefor we don't want
1807              * ResumeAllVirtualThreads resuming these vthreads. We must first
1808              * build a list of them to pass to as the exclude list.
1809              */
1810             enumerateOverThreadList(env, &runningVThreads, excludeCountHelper,
1811                                     &excludeCnt);
1812             if (excludeCnt > 0) {
1813                 excludeList = newArray(excludeCnt, sizeof(jthread));
1814                 if (excludeList == NULL) {
1815                     EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"exclude list");
1816                 }
1817                 {
1818                     jthread *excludeListPtr = excludeList;
1819                     enumerateOverThreadList(env, &runningVThreads, excludeCopyHelper,
1820                                             &excludeListPtr);
1821                 }
1822             }
1823             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeAllVirtualThreads)
1824                     (gdata->jvmti, excludeCnt, excludeList);
1825             if (error != JVMTI_ERROR_NONE) {
1826                 EXIT_ERROR(error, "cannot resume all virtual threads");
1827             }
1828             // We need a notify here just like we do any time we resume a thread.
1829             // See commonResumeList() and resumeThreadByNode().
1830             debugMonitorNotifyAll(threadLock);
1831         }
1832     }
1833 
1834     /*
1835      * Resume only those threads that the debugger has suspended. All
1836      * such threads must have a node in one of the thread lists, so there's
1837      * no need to get the whole thread list from JVMTI (unlike
1838      * suspendAll).
1839      */
1840     error = commonResumeList(env);
1841     if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1842         error = enumerateOverThreadList(env, &otherThreads,
1843                                         resumeHelper, NULL);
1844         removeResumed(env, &otherThreads);
1845     }
1846 
1847     if (suspendAllCount > 0) {
1848         /*
1849          * Unpin all objects.
1850          */
1851         commonRef_unpinAll();
1852 
1853         suspendAllCount--;
1854     }
1855 
1856     debugMonitorExit(threadLock);
1857     eventHandler_unlock();
1858     /* let eventHelper.c: commandLoop() know we are resuming */
1859     unblockCommandLoop();
1860 
1861     return error;
1862 }
1863 
1864 
1865 StepRequest *
1866 threadControl_getStepRequest(jthread thread)
1867 {
1868     ThreadNode  *node;
1869     StepRequest *step;
1870 
1871     step = NULL;
1872 
1873     debugMonitorEnter(threadLock);
1874 
1875     node = findRunningThread(thread);
1876     if (node != NULL) {
1877         step = &node->currentStep;
1878     }
1879 
1880     debugMonitorExit(threadLock);
1881 
1882     return step;
1883 }
1884 
1885 InvokeRequest *
1886 threadControl_getInvokeRequest(jthread thread)
1887 {
1888     ThreadNode    *node;
1889     InvokeRequest *request;
1890 
1891     request = NULL;
1892 
1893     debugMonitorEnter(threadLock);
1894 
1895     node = findRunningThread(thread);
1896     if (node != NULL) {
1897          request = &node->currentInvoke;
1898     }
1899 
1900     debugMonitorExit(threadLock);
1901 
1902     return request;
1903 }
1904 
1905 jvmtiError
1906 threadControl_addDebugThread(jthread thread)
1907 {
1908     jvmtiError error;
1909 
1910     debugMonitorEnter(threadLock);
1911     if (debugThreadCount >= MAX_DEBUG_THREADS) {
1912         error = AGENT_ERROR_OUT_OF_MEMORY;
1913     } else {
1914         JNIEnv    *env;
1915 
1916         env = getEnv();
1917         debugThreads[debugThreadCount] = NULL;
1918         saveGlobalRef(env, thread, &(debugThreads[debugThreadCount]));
1919         if (debugThreads[debugThreadCount] == NULL) {
1920             error = AGENT_ERROR_OUT_OF_MEMORY;
1921         } else {
1922             debugThreadCount++;
1923             error = JVMTI_ERROR_NONE;
1924         }
1925     }
1926     debugMonitorExit(threadLock);
1927     return error;
1928 }
1929 
1930 static jvmtiError
1931 threadControl_removeDebugThread(jthread thread)
1932 {
1933     jvmtiError error;
1934     JNIEnv    *env;
1935     int        i;
1936 
1937     error = AGENT_ERROR_INVALID_THREAD;
1938     env   = getEnv();
1939 
1940     debugMonitorEnter(threadLock);
1941     for (i = 0; i< debugThreadCount; i++) {
1942         if (isSameObject(env, thread, debugThreads[i])) {
1943             int j;
1944 
1945             tossGlobalRef(env, &(debugThreads[i]));
1946             for (j = i+1; j < debugThreadCount; j++) {
1947                 debugThreads[j-1] = debugThreads[j];
1948             }
1949             debugThreadCount--;
1950             error = JVMTI_ERROR_NONE;
1951             break;
1952         }
1953     }
1954     debugMonitorExit(threadLock);
1955     return error;
1956 }
1957 
1958 jboolean
1959 threadControl_isDebugThread(jthread thread)
1960 {
1961     int      i;
1962     jboolean rc;
1963     JNIEnv  *env;
1964 
1965     rc  = JNI_FALSE;
1966     env = getEnv();
1967 
1968     debugMonitorEnter(threadLock);
1969     for (i = 0; i < debugThreadCount; i++) {
1970         if (isSameObject(env, thread, debugThreads[i])) {
1971             rc = JNI_TRUE;
1972             break;
1973         }
1974     }
1975     debugMonitorExit(threadLock);
1976     return rc;
1977 }
1978 
1979 static void
1980 initLocks(void)
1981 {
1982     if (popFrameEventLock == NULL) {
1983         popFrameEventLock = debugMonitorCreate("JDWP PopFrame Event Lock");
1984         popFrameProceedLock = debugMonitorCreate("JDWP PopFrame Proceed Lock");
1985     }
1986 }
1987 
1988 static jboolean
1989 getPopFrameThread(jthread thread)
1990 {
1991     jboolean popFrameThread;
1992 
1993     debugMonitorEnter(threadLock);
1994     {
1995         ThreadNode *node;
1996 
1997         node = findThread(NULL, thread);
1998         if (node == NULL) {
1999             popFrameThread = JNI_FALSE;
2000         } else {
2001             popFrameThread = node->popFrameThread;
2002         }
2003     }
2004     debugMonitorExit(threadLock);
2005 
2006     return popFrameThread;
2007 }
2008 
2009 static void
2010 setPopFrameThread(jthread thread, jboolean value)
2011 {
2012     debugMonitorEnter(threadLock);
2013     {
2014         ThreadNode *node;
2015 
2016         node = findThread(NULL, thread);
2017         if (node == NULL) {
2018             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2019         } else {
2020             node->popFrameThread = value;
2021         }
2022     }
2023     debugMonitorExit(threadLock);
2024 }
2025 
2026 static jboolean
2027 getPopFrameEvent(jthread thread)
2028 {
2029     jboolean popFrameEvent;
2030 
2031     debugMonitorEnter(threadLock);
2032     {
2033         ThreadNode *node;
2034 
2035         node = findThread(NULL, thread);
2036         if (node == NULL) {
2037             popFrameEvent = JNI_FALSE;
2038             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2039         } else {
2040             popFrameEvent = node->popFrameEvent;
2041         }
2042     }
2043     debugMonitorExit(threadLock);
2044 
2045     return popFrameEvent;
2046 }
2047 
2048 static void
2049 setPopFrameEvent(jthread thread, jboolean value)
2050 {
2051     debugMonitorEnter(threadLock);
2052     {
2053         ThreadNode *node;
2054 
2055         node = findThread(NULL, thread);
2056         if (node == NULL) {
2057             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2058         } else {
2059             node->popFrameEvent = value;
2060             node->frameGeneration++; /* Increment on each resume */
2061         }
2062     }
2063     debugMonitorExit(threadLock);
2064 }
2065 
2066 static jboolean
2067 getPopFrameProceed(jthread thread)
2068 {
2069     jboolean popFrameProceed;
2070 
2071     debugMonitorEnter(threadLock);
2072     {
2073         ThreadNode *node;
2074 
2075         node = findThread(NULL, thread);
2076         if (node == NULL) {
2077             popFrameProceed = JNI_FALSE;
2078             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2079         } else {
2080             popFrameProceed = node->popFrameProceed;
2081         }
2082     }
2083     debugMonitorExit(threadLock);
2084 
2085     return popFrameProceed;
2086 }
2087 
2088 static void
2089 setPopFrameProceed(jthread thread, jboolean value)
2090 {
2091     debugMonitorEnter(threadLock);
2092     {
2093         ThreadNode *node;
2094 
2095         node = findThread(NULL, thread);
2096         if (node == NULL) {
2097             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2098         } else {
2099             node->popFrameProceed = value;
2100         }
2101     }
2102     debugMonitorExit(threadLock);
2103 }
2104 
2105 /**
2106  * Special event handler for events on the popped thread
2107  * that occur during the pop operation.
2108  */
2109 static void
2110 popFrameCompleteEvent(jthread thread)
2111 {
2112       debugMonitorEnter(popFrameProceedLock);
2113       {
2114           /* notify that we got the event */
2115           debugMonitorEnter(popFrameEventLock);
2116           {
2117               setPopFrameEvent(thread, JNI_TRUE);
2118               debugMonitorNotify(popFrameEventLock);
2119           }
2120           debugMonitorExit(popFrameEventLock);
2121 
2122           /* make sure we get suspended again */
2123           setPopFrameProceed(thread, JNI_FALSE);
2124           while (getPopFrameProceed(thread) == JNI_FALSE) {
2125               debugMonitorWait(popFrameProceedLock);
2126           }
2127       }
2128       debugMonitorExit(popFrameProceedLock);
2129 }
2130 
2131 /**
2132  * Pop one frame off the stack of thread.
2133  * popFrameEventLock is already held
2134  */
2135 static jvmtiError
2136 popOneFrame(jthread thread)
2137 {
2138     jvmtiError error;
2139 
2140     error = JVMTI_FUNC_PTR(gdata->jvmti,PopFrame)(gdata->jvmti, thread);
2141     if (error != JVMTI_ERROR_NONE) {
2142         return error;
2143     }
2144 
2145     /* resume the popped thread so that the pop occurs and so we */
2146     /* will get the event (step or method entry) after the pop */
2147     LOG_MISC(("thread=%p resumed in popOneFrame", thread));
2148     error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, thread);
2149     if (error != JVMTI_ERROR_NONE) {
2150         return error;
2151     }
2152 
2153     /* wait for the event to occur */
2154     setPopFrameEvent(thread, JNI_FALSE);
2155     while (getPopFrameEvent(thread) == JNI_FALSE) {
2156         debugMonitorWait(popFrameEventLock);
2157     }
2158 
2159     /* make sure not to suspend until the popped thread is on the wait */
2160     debugMonitorEnter(popFrameProceedLock);
2161     {
2162         /* return popped thread to suspended state */
2163         LOG_MISC(("thread=%p suspended in popOneFrame", thread));
2164         error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)(gdata->jvmti, thread);
2165 
2166         /* notify popped thread so it can proceed when resumed */
2167         setPopFrameProceed(thread, JNI_TRUE);
2168         debugMonitorNotify(popFrameProceedLock);
2169     }
2170     debugMonitorExit(popFrameProceedLock);
2171 
2172     return error;
2173 }
2174 
2175 /**
2176  * pop frames of the stack of 'thread' until 'frame' is popped.
2177  */
2178 jvmtiError
2179 threadControl_popFrames(jthread thread, FrameNumber fnum)
2180 {
2181     jvmtiError error;
2182     jvmtiEventMode prevStepMode;
2183     jint framesPopped = 0;
2184     jint popCount;
2185     jboolean prevInvokeRequestMode;
2186 
2187     log_debugee_location("threadControl_popFrames()", thread, NULL, 0);
2188 
2189     initLocks();
2190 
2191     /* compute the number of frames to pop */
2192     popCount = fnum+1;
2193     if (popCount < 1) {
2194         return AGENT_ERROR_NO_MORE_FRAMES;
2195     }
2196 
2197     /* enable instruction level single step, but first note prev value */
2198     prevStepMode = threadControl_getInstructionStepMode(thread);
2199 
2200     /*
2201      * Fix bug 6517249.  The pop processing will disable invokes,
2202      * so remember if invokes are enabled now and restore
2203      * that state after we finish popping.
2204      */
2205     prevInvokeRequestMode = invoker_isEnabled(thread);
2206 
2207     error = threadControl_setEventMode(JVMTI_ENABLE,
2208                                        EI_SINGLE_STEP, thread);
2209     if (error != JVMTI_ERROR_NONE) {
2210         return error;
2211     }
2212 
2213     /* Inform eventHandler logic we are in a popFrame for this thread */
2214     debugMonitorEnter(popFrameEventLock);
2215     {
2216         setPopFrameThread(thread, JNI_TRUE);
2217         /* pop frames using single step */
2218         while (framesPopped++ < popCount) {
2219             error = popOneFrame(thread);
2220             if (error != JVMTI_ERROR_NONE) {
2221                 break;
2222             }
2223         }
2224         setPopFrameThread(thread, JNI_FALSE);
2225     }
2226     debugMonitorExit(popFrameEventLock);
2227 
2228     /*  Reset StepRequest info (fromLine and stackDepth) after popframes
2229      *  only if stepping is enabled.
2230      */
2231     if (prevStepMode == JVMTI_ENABLE) {
2232         stepControl_resetRequest(thread);
2233     }
2234 
2235     if (prevInvokeRequestMode) {
2236         invoker_enableInvokeRequests(thread);
2237     }
2238 
2239     /* restore state */
2240     (void)threadControl_setEventMode(prevStepMode,
2241                                EI_SINGLE_STEP, thread);
2242 
2243     return error;
2244 }
2245 
2246 /* Check to see if any events are being consumed by a popFrame(). */
2247 static jboolean
2248 checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread)
2249 {
2250     if ( getPopFrameThread(thread) ) {
2251         switch (ei) {
2252             case EI_THREAD_START:
2253                 /* Excuse me? */
2254                 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame");
2255                 break;
2256             case EI_THREAD_END:
2257                 /* Thread wants to end? let it. */
2258                 setPopFrameThread(thread, JNI_FALSE);
2259                 popFrameCompleteEvent(thread);
2260                 break;
2261             case EI_VIRTUAL_THREAD_START:
2262             case EI_VIRTUAL_THREAD_END:
2263                 JDI_ASSERT(JNI_FALSE);
2264                 break;
2265             case EI_SINGLE_STEP:
2266                 /* This is an event we requested to mark the */
2267                 /*        completion of the pop frame */
2268                 popFrameCompleteEvent(thread);
2269                 return JNI_TRUE;
2270             case EI_BREAKPOINT:
2271             case EI_EXCEPTION:
2272             case EI_FIELD_ACCESS:
2273             case EI_FIELD_MODIFICATION:
2274             case EI_METHOD_ENTRY:
2275             case EI_METHOD_EXIT:
2276                 /* Tell event handler to assume event has been consumed. */
2277                 return JNI_TRUE;
2278             default:
2279                 break;
2280         }
2281     }
2282     /* Pretend we were never called */
2283     return JNI_FALSE;
2284 }
2285 
2286 struct bag *
2287 threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject currentException)
2288 {
2289     ThreadNode *node;
2290     JNIEnv     *env;
2291     struct bag *eventBag;
2292     jthread     threadToSuspend;
2293     jboolean    consumed;
2294     EventIndex  ei = evinfo->ei;
2295     jthread     thread = evinfo->thread;
2296 
2297     env             = getEnv();
2298     threadToSuspend = NULL;
2299 
2300     log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL, 0);
2301 
2302     /* Events during pop commands may need to be ignored here. */
2303     consumed = checkForPopFrameEvents(env, ei, thread);
2304     if ( consumed ) {
2305         /* Always restore any exception (see below). */
2306         if (currentException != NULL) {
2307             JNI_FUNC_PTR(env,Throw)(env, currentException);
2308         } else {
2309             JNI_FUNC_PTR(env,ExceptionClear)(env);
2310         }
2311         return NULL;
2312     }
2313 
2314     debugMonitorEnter(threadLock);
2315 
2316     /*
2317      * Check the list of unknown threads maintained by suspend
2318      * and resume. If this thread is currently present in the
2319      * list, it should be
2320      * moved to the runningThreads list, since it is a
2321      * well-known thread now.
2322      */
2323     node = findThread(&otherThreads, thread);
2324     if (node != NULL) {
2325         moveNode(&otherThreads, &runningThreads, node);
2326         /* Now that we know the thread has started, we can set its TLS.*/
2327         setThreadLocalStorage(thread, (void*)node);
2328     } else {
2329         /*
2330          * Get a thread node for the reporting thread. For thread start
2331          * events, or if this event precedes a thread start event,
2332          * the thread node may need to be created.
2333          *
2334          * It is possible for certain events (notably method entry/exit)
2335          * to precede thread start for some VM implementations.
2336          */
2337         if (evinfo->is_vthread) {
2338           /* fiber fixme: don't add the vthread if this is an EI_THREAD_START or
2339              EI_THREAD_EXIT event. Otherwise we end up adding every vthread. This
2340              is an issue when notifyVThreads is true, which is the default.
2341           */
2342             node = insertThread(env, &runningVThreads, thread);
2343         } else {
2344             node = insertThread(env, &runningThreads, thread);
2345         }
2346     }
2347 
2348     if (ei == EI_THREAD_START || ei == EI_VIRTUAL_THREAD_START) {
2349         node->isStarted = JNI_TRUE;
2350         processDeferredEventModes(env, thread, node);
2351     }
2352 
2353     node->current_ei = ei;
2354     eventBag = node->eventBag;
2355     if (node->suspendOnStart) {
2356         threadToSuspend = node->thread;
2357     }
2358     debugMonitorExit(threadLock);
2359 
2360     if (threadToSuspend != NULL) {
2361         /*
2362          * An attempt was made to suspend this thread before it started.
2363          * We must suspend it now, before it starts to run. This must
2364          * be done with no locks held.
2365          */
2366         eventHelper_suspendThread(sessionID, threadToSuspend);
2367     }
2368 
2369     return eventBag;
2370 }
2371 
2372 static void
2373 doPendingTasks(JNIEnv *env, ThreadNode *node)
2374 {
2375     /* Deferred breakpoint handling for Thread.resume() */
2376     if (node->handlingAppResume) {
2377         jthread resumer = node->thread;
2378         jthread resumee = getResumee(resumer);
2379 
2380         if (resumer != NULL) {
2381             /*
2382              * trackAppResume indirectly aquires handlerLock. For proper lock
2383              * ordering handlerLock has to be acquired before threadLock.
2384              */
2385             debugMonitorExit(threadLock);
2386             eventHandler_lock();
2387             debugMonitorEnter(threadLock);
2388 
2389             /*
2390              * Track the resuming thread by marking it as being within
2391              * a resume and by setting up for notification on
2392              * a frame pop or exception. We won't allow the debugger
2393              * to suspend threads while any thread is within a
2394              * call to resume. This (along with the block below)
2395              * ensures that when the debugger
2396              * suspends a thread it will remain suspended.
2397              */
2398             trackAppResume(resumer);
2399 
2400             /*
2401              * handlerLock is not needed anymore. We must release it before calling
2402              * blockOnDebuggerSuspend() because it is required for resumes done by
2403              * the debugger. If resumee is currently suspended by the debugger, then
2404              * blockOnDebuggerSuspend() will block until a debugger resume is done.
2405              * If it blocks while holding the handlerLock, then the resume will deadlock.
2406              */
2407             eventHandler_unlock();
2408         }
2409 
2410         if (resumee != NULL) {
2411             /*
2412              * Hold up any attempt to resume as long as the debugger
2413              * has suspended the resumee.
2414              */
2415             blockOnDebuggerSuspend(resumee);
2416         }
2417 
2418         node->handlingAppResume = JNI_FALSE;
2419 
2420         /*
2421          * The blocks exit condition: resumee's suspendCount == 0.
2422          *
2423          * Debugger suspends are blocked if any thread is executing
2424          * Thread.resume(), i.e. !handlingAppResume && frameDepth > 0.
2425          */
2426     }
2427 
2428     /*
2429      * Take care of any pending interrupts/stops, and clear out
2430      * info on pending interrupts/stops.
2431      */
2432     if (node->pendingInterrupt) {
2433         JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2434                         (gdata->jvmti, node->thread);
2435         /*
2436          * TO DO: Log error
2437          */
2438         node->pendingInterrupt = JNI_FALSE;
2439     }
2440 
2441     if (node->pendingStop != NULL) {
2442         JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2443                         (gdata->jvmti, node->thread, node->pendingStop);
2444         /*
2445          * TO DO: Log error
2446          */
2447         tossGlobalRef(env, &(node->pendingStop));
2448     }
2449 }
2450 
2451 void
2452 threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
2453                                  struct bag *eventBag)
2454 {
2455     ThreadNode *node;
2456 
2457     log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0);
2458 
2459     if (ei == EI_THREAD_END) {
2460         eventHandler_lock(); /* for proper lock order */
2461     }
2462     debugMonitorEnter(threadLock);
2463 
2464     node = findRunningThread(thread);
2465     if (node == NULL) {
2466         EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2467     } else {
2468         JNIEnv *env;
2469 
2470         env = getEnv();
2471         if (ei == EI_THREAD_END) {
2472             jboolean inResume = (node->resumeFrameDepth > 0);
2473             if (isVThread(thread)) {
2474                 removeThread(env, &runningVThreads, thread);
2475             } else {
2476                 removeThread(env, &runningThreads, thread);
2477             }
2478             node = NULL;   /* has been freed */
2479 
2480             /*
2481              * Clean up mechanism used to detect end of
2482              * resume.
2483              */
2484             if (inResume) {
2485                 notifyAppResumeComplete();
2486             }
2487         } else {
2488             /* No point in doing this if the thread is about to die.*/
2489             doPendingTasks(env, node);
2490             node->eventBag = eventBag;
2491             node->current_ei = 0;
2492         }
2493     }
2494 
2495     debugMonitorExit(threadLock);
2496     if (ei == EI_THREAD_END) {
2497         eventHandler_unlock();
2498     }
2499 }
2500 
2501 /* Returns JDWP flavored status and status flags. */
2502 jvmtiError
2503 threadControl_applicationThreadStatus(jthread thread,
2504                         jdwpThreadStatus *pstatus, jint *statusFlags)
2505 {
2506     ThreadNode *node;
2507     jvmtiError  error;
2508     jint        state;
2509 
2510     log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2511 
2512     debugMonitorEnter(threadLock);
2513 
2514     error = threadState(thread, &state);
2515     *pstatus = map2jdwpThreadStatus(state);
2516     *statusFlags = map2jdwpSuspendStatus(state);
2517 
2518     if (error == JVMTI_ERROR_NONE) {
2519         node = findRunningThread(thread);
2520         if ((node != NULL) && HANDLING_EVENT(node)) {
2521             /*
2522              * While processing an event, an application thread is always
2523              * considered to be running even if its handler happens to be
2524              * cond waiting on an internal debugger monitor, etc.
2525              *
2526              * Leave suspend status untouched since it is not possible
2527              * to distinguish debugger suspends from app suspends.
2528              */
2529             *pstatus = JDWP_THREAD_STATUS(RUNNING);
2530         }
2531     }
2532 #if 0
2533     tty_message("status %s: node(%p) suspendCount(%d) %d %d %s",
2534                 isVThread(thread) ? "vthread" : "thread",
2535                 node, node->suspendCount, *pstatus, *statusFlags, node->name);
2536 #endif
2537 
2538     debugMonitorExit(threadLock);
2539 
2540     return error;
2541 }
2542 
2543 jvmtiError
2544 threadControl_interrupt(jthread thread)
2545 {
2546     ThreadNode *node;
2547     jvmtiError  error;
2548 
2549     // vthread fixme: should this work for vthreads?
2550     JDI_ASSERT(!isVThread(thread));
2551 
2552     error = JVMTI_ERROR_NONE;
2553 
2554     log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2555 
2556     debugMonitorEnter(threadLock);
2557 
2558     node = findThread(&runningThreads, thread);
2559     if ((node == NULL) || !HANDLING_EVENT(node)) {
2560         error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2561                         (gdata->jvmti, thread);
2562     } else {
2563         /*
2564          * Hold any interrupts until after the event is processed.
2565          */
2566         node->pendingInterrupt = JNI_TRUE;
2567     }
2568 
2569     debugMonitorExit(threadLock);
2570 
2571     return error;
2572 }
2573 
2574 void
2575 threadControl_clearCLEInfo(JNIEnv *env, jthread thread)
2576 {
2577     ThreadNode *node;
2578 
2579     debugMonitorEnter(threadLock);
2580 
2581     node = findRunningThread(thread);
2582     if (node != NULL) {
2583         node->cleInfo.ei = 0;
2584         if (node->cleInfo.clazz != NULL) {
2585             tossGlobalRef(env, &(node->cleInfo.clazz));
2586         }
2587     }
2588 
2589     debugMonitorExit(threadLock);
2590 }
2591 
2592 jboolean
2593 threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz,
2594                          jmethodID method, jlocation location)
2595 {
2596     ThreadNode *node;
2597     jboolean    result;
2598 
2599     result = JNI_FALSE;
2600 
2601     debugMonitorEnter(threadLock);
2602 
2603     node = findRunningThread(thread);
2604     if (node != NULL && node->cleInfo.ei != 0 &&
2605         node->cleInfo.method == method &&
2606         node->cleInfo.location == location &&
2607         (isSameObject(env, node->cleInfo.clazz, clazz))) {
2608         result = JNI_TRUE; /* we have a match */
2609     }
2610 
2611     debugMonitorExit(threadLock);
2612 
2613     return result;
2614 }
2615 
2616 void
2617 threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
2618                           jclass clazz, jmethodID method, jlocation location)
2619 {
2620     ThreadNode *node;
2621 
2622     debugMonitorEnter(threadLock);
2623 
2624     node = findRunningThread(thread);
2625     if (node != NULL) {
2626         node->cleInfo.ei = ei;
2627         /* Create a class ref that will live beyond */
2628         /* the end of this call */
2629         saveGlobalRef(env, clazz, &(node->cleInfo.clazz));
2630         /* if returned clazz is NULL, we just won't match */
2631         node->cleInfo.method    = method;
2632         node->cleInfo.location  = location;
2633     }
2634 
2635     debugMonitorExit(threadLock);
2636 }
2637 
2638 void
2639 threadControl_setPendingInterrupt(jthread thread)
2640 {
2641     ThreadNode *node;
2642 
2643     // vthread fixme: should this work for vthreads?
2644     JDI_ASSERT(!isVThread(thread));
2645 
2646     debugMonitorEnter(threadLock);
2647 
2648     node = findThread(&runningThreads, thread);
2649     if (node != NULL) {
2650         node->pendingInterrupt = JNI_TRUE;
2651     }
2652 
2653     debugMonitorExit(threadLock);
2654 }
2655 
2656 jvmtiError
2657 threadControl_stop(jthread thread, jobject throwable)
2658 {
2659     ThreadNode *node;
2660     jvmtiError  error;
2661 
2662     // vthread fixme: should this work for vthreads?
2663     JDI_ASSERT(!isVThread(thread));
2664 
2665     error = JVMTI_ERROR_NONE;
2666 
2667     log_debugee_location("threadControl_stop()", thread, NULL, 0);
2668 
2669     debugMonitorEnter(threadLock);
2670 
2671     node = findThread(&runningThreads, thread);
2672     if ((node == NULL) || !HANDLING_EVENT(node)) {
2673         error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2674                         (gdata->jvmti, thread, throwable);
2675     } else {
2676         JNIEnv *env;
2677 
2678         /*
2679          * Hold any stops until after the event is processed.
2680          */
2681         env = getEnv();
2682         saveGlobalRef(env, throwable, &(node->pendingStop));
2683     }
2684 
2685     debugMonitorExit(threadLock);
2686 
2687     return error;
2688 }
2689 
2690 static jvmtiError
2691 detachHelper(JNIEnv *env, ThreadNode *node, void *arg)
2692 {
2693     invoker_detach(&node->currentInvoke);
2694     return JVMTI_ERROR_NONE;
2695 }
2696 
2697 void
2698 threadControl_detachInvokes(void)
2699 {
2700     JNIEnv *env;
2701 
2702     env = getEnv();
2703     invoker_lock(); /* for proper lock order */
2704     debugMonitorEnter(threadLock);
2705     (void)enumerateOverThreadList(env, &runningThreads, detachHelper, NULL);
2706     debugMonitorExit(threadLock);
2707     invoker_unlock();
2708 }
2709 
2710 static jvmtiError
2711 resetHelper(JNIEnv *env, ThreadNode *node, void *arg)
2712 {
2713     if (node->toBeResumed) {
2714         LOG_MISC(("thread=%p resumed", node->thread));
2715         (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, node->thread);
2716         node->frameGeneration++; /* Increment on each resume */
2717     }
2718     stepControl_clearRequest(node->thread, &node->currentStep);
2719     node->toBeResumed = JNI_FALSE;
2720     node->suspendCount = 0;
2721     node->suspendOnStart = JNI_FALSE;
2722 
2723     return JVMTI_ERROR_NONE;
2724 }
2725 
2726 void
2727 threadControl_reset(void)
2728 {
2729     JNIEnv *env;
2730 
2731     env = getEnv();
2732     eventHandler_lock(); /* for proper lock order */
2733     debugMonitorEnter(threadLock);
2734 
2735     if (gdata->vthreadsSupported) {
2736         if (suspendAllCount > 0) {
2737             /* Tell JVMTI to resume all virtual threads. */
2738             jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeAllVirtualThreads)
2739               (gdata->jvmti, 0, NULL);
2740             if (error != JVMTI_ERROR_NONE) {
2741                 EXIT_ERROR(error, "cannot resume all virtual threads");
2742             }
2743         }
2744     }
2745 
2746     (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2747     (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);
2748     (void)enumerateOverThreadList(env, &runningVThreads, resetHelper, NULL);
2749 
2750     removeResumed(env, &otherThreads);
2751 
2752     freeDeferredEventModes(env);
2753 
2754     suspendAllCount = 0;
2755 
2756     /* Everything should have been resumed */
2757     JDI_ASSERT(otherThreads.first == NULL);
2758 
2759     /* Threads could be waiting in blockOnDebuggerSuspend */
2760     debugMonitorNotifyAll(threadLock);
2761     debugMonitorExit(threadLock);
2762     eventHandler_unlock();
2763 }
2764 
2765 jvmtiEventMode
2766 threadControl_getInstructionStepMode(jthread thread)
2767 {
2768     ThreadNode    *node;
2769     jvmtiEventMode mode;
2770 
2771     mode = JVMTI_DISABLE;
2772 
2773     debugMonitorEnter(threadLock);
2774     node = findRunningThread(thread);
2775     if (node != NULL) {
2776         mode = node->instructionStepMode;
2777     }
2778     debugMonitorExit(threadLock);
2779     return mode;
2780 }
2781 
2782 jvmtiError
2783 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2784 {
2785     jvmtiError error;
2786 
2787     /* Global event */
2788     if ( thread == NULL ) {
2789         error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2790                     (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2791     } else {
2792         /* Thread event */
2793         ThreadNode *node;
2794 
2795         debugMonitorEnter(threadLock);
2796         {
2797             node = findRunningThread(thread);
2798             if ((node == NULL) || (!node->isStarted)) {
2799                 JNIEnv *env;
2800 
2801                 env = getEnv();
2802                 error = addDeferredEventMode(env, mode, ei, thread);
2803             } else {
2804                 error = threadSetEventNotificationMode(node,
2805                         mode, ei, thread);
2806             }
2807         }
2808         debugMonitorExit(threadLock);
2809 
2810     }
2811     return error;
2812 }
2813 
2814 /*
2815  * Returns the current thread, if the thread has generated at least
2816  * one event, and has not generated a thread end event.
2817  */
2818 jthread
2819 threadControl_currentThread(void)
2820 {
2821     jthread thread;
2822 
2823     debugMonitorEnter(threadLock);
2824     {
2825         ThreadNode *node;
2826 
2827         node = findThread(&runningThreads, NULL);
2828         thread = (node == NULL) ? NULL : node->thread;
2829     }
2830     debugMonitorExit(threadLock);
2831 
2832     return thread;
2833 }
2834 
2835 jlong
2836 threadControl_getFrameGeneration(jthread thread)
2837 {
2838     jlong frameGeneration = -1;
2839 
2840     debugMonitorEnter(threadLock);
2841     {
2842         ThreadNode *node;
2843 
2844         node = findThread(NULL, thread);
2845 
2846         if (node != NULL) {
2847             frameGeneration = node->frameGeneration;
2848         }
2849     }
2850     debugMonitorExit(threadLock);
2851 
2852     return frameGeneration;
2853 }
2854 
2855 jthread *
2856 threadControl_allVThreads(jint *numVThreads)
2857 {
2858     JNIEnv *env;
2859     ThreadNode *node;
2860     jthread* vthreads;
2861 
2862     env = getEnv();
2863     debugMonitorEnter(threadLock);
2864 
2865     /* Count the number of vthreads */
2866     /* vthread fixme: we should keep a running total so no counting is needed. */
2867     *numVThreads = 0;
2868     for (node = runningVThreads.first; node != NULL; node = node->next) {
2869         (*numVThreads)++;
2870     }
2871 
2872     /* Allocate and fill in the vthreads array. */
2873     vthreads = jvmtiAllocate(*numVThreads * sizeof(jthread*));
2874     if (vthreads != NULL) {
2875         int i = 0;
2876         for (node = runningVThreads.first; node != NULL;  node = node->next) {
2877             vthreads[i++] = node->thread;
2878         }
2879     }
2880 
2881     debugMonitorExit(threadLock);
2882 
2883     return vthreads;
2884 }
2885 
2886 jboolean threadControl_isKnownVThread(jthread vthread) {
2887     ThreadNode *vthreadNode;
2888     debugMonitorEnter(threadLock);
2889     vthreadNode = findThread(&runningVThreads, vthread);
2890     debugMonitorExit(threadLock);
2891     return vthreadNode != NULL;
2892 }
2893 
2894 void
2895 threadControl_addVThread(jthread vthread)
2896 {
2897     ThreadNode *vthreadNode;
2898     debugMonitorEnter(threadLock);
2899     vthreadNode = insertThread(getEnv(), &runningVThreads, vthread);
2900     debugMonitorExit(threadLock);
2901 }
2902 
2903 /***** debugging *****/
2904 
2905 #ifdef DEBUG
2906 
2907 void
2908 threadControl_dumpAllThreads()
2909 {
2910     tty_message("Dumping runningThreads:");
2911     dumpThreadList(&runningThreads);
2912     tty_message("\nDumping runningVThreads:");
2913     dumpThreadList(&runningVThreads);
2914     tty_message("\nDumping otherThreads:");
2915     dumpThreadList(&otherThreads);
2916 }
2917 
2918 void
2919 threadControl_dumpThread(jthread thread)
2920 {
2921     ThreadNode* node = findThread(NULL, thread);
2922     if (node == NULL) {
2923         tty_message("Thread not found");
2924     } else {
2925         dumpThread(node);
2926     }
2927 }
2928 
2929 static void
2930 dumpThreadList(ThreadList *list)
2931 {
2932     ThreadNode *node;
2933     for (node = list->first; node != NULL; node = node->next) {
2934         if (!node->isDebugThread) {
2935             dumpThread(node);
2936         }
2937     }
2938 }
2939 
2940 static void
2941 dumpThread(ThreadNode *node) {
2942     tty_message("  Thread: node = %p, jthread = %p", node, node->thread);
2943 #ifdef DEBUG_THREADNAME
2944     tty_message("\tname: %s", node->name);
2945 #endif
2946     // More fields can be printed here when needed. The amount of output is intentionlly
2947     // kept small so it doesn't generate too much output.
2948     tty_message("\tsuspendCount: %d", node->suspendCount);
2949 }
2950 
2951 #endif /* DEBUG */
--- EOF ---