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     EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */
  78     jobject pendingStop;   /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */
  79     jint suspendCount;
  80     jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */
  81     jvmtiEventMode instructionStepMode;
  82     StepRequest currentStep;
  83     InvokeRequest currentInvoke;
  84     struct bag *eventBag;       /* Accumulation of JDWP events to be sent as a reply. */
  85     CoLocatedEventInfo cleInfo; /* See comment above deferEventReport() for an explanation. */
  86     struct ThreadNode *next;
  87     struct ThreadNode *prev;
  88     jlong frameGeneration;    /* used to generate a unique frameID. Incremented whenever existing frameID
  89                                  needs to be invalidated, such as when the thread is resumed. */
  90     struct ThreadList *list;  /* Tells us what list this thread is in. */
  91 #ifdef DEBUG_THREADNAME
  92     char name[256];
  93 #endif
  94 } ThreadNode;
  95 
  96 static jint suspendAllCount;
  97 
  98 typedef struct ThreadList {
  99     ThreadNode *first;
 100 } ThreadList;
 101 
 102 /*
 103  * popFrameEventLock is used to notify that the event has been received
 104  */
 105 static jrawMonitorID popFrameEventLock = NULL;
 106 
 107 /*
 108  * popFrameProceedLock is used to assure that the event thread is
 109  * re-suspended immediately after the event is acknowledged.
 110  */
 111 static jrawMonitorID popFrameProceedLock = NULL;
 112 
 113 static jrawMonitorID threadLock;
 114 static jlocation resumeLocation;
 115 static HandlerNode *breakpointHandlerNode;
 116 static HandlerNode *framePopHandlerNode;
 117 static HandlerNode *catchHandlerNode;
 118 
 119 static jvmtiError threadControl_removeDebugThread(jthread thread);
 120 
 121 /*
 122  * Threads which have issued thread start events and not yet issued thread
 123  * end events are maintained in the "runningThreads" list. All other threads known
 124  * to this module are kept in the "otherThreads" list.
 125  */
 126 static ThreadList runningThreads;
 127 static ThreadList otherThreads;
 128 static ThreadList runningVThreads; /* VThreads we have seen. */
 129 
 130 #define MAX_DEBUG_THREADS 10
 131 static int debugThreadCount;
 132 static jthread debugThreads[MAX_DEBUG_THREADS];
 133 
 134 typedef struct DeferredEventMode {
 135     EventIndex ei;
 136     jvmtiEventMode mode;
 137     jthread thread;
 138     struct DeferredEventMode *next;
 139 } DeferredEventMode;
 140 
 141 typedef struct {
 142     DeferredEventMode *first;
 143     DeferredEventMode *last;
 144 } DeferredEventModeList;
 145 
 146 static DeferredEventModeList deferredEventModes;
 147 
 148 #ifdef DEBUG
 149 static void dumpThreadList(ThreadList *list);
 150 static void dumpThread(ThreadNode *node);
 151 #endif
 152 
 153 static jint
 154 getStackDepth(jthread thread)
 155 {
 156     jint count = 0;
 157     jvmtiError error;
 158 
 159     error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
 160                         (gdata->jvmti, thread, &count);
 161     if (error != JVMTI_ERROR_NONE) {
 162         EXIT_ERROR(error, "getting frame count");
 163     }
 164     return count;
 165 }
 166 
 167 /* Get the state of the thread direct from JVMTI */
 168 static jvmtiError
 169 threadState(jthread thread, jint *pstate)
 170 {
 171     *pstate = 0;
 172     return JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState)
 173                         (gdata->jvmti, thread, pstate);
 174 }
 175 
 176 /* Set TLS on a specific jthread to the ThreadNode* */
 177 static void
 178 setThreadLocalStorage(jthread thread, ThreadNode *node)
 179 {
 180     jvmtiError  error;
 181 
 182     error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage)
 183             (gdata->jvmti, thread, (void*)node);
 184     if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE && node == NULL) {
 185         /* Just return. This can happen when clearing the TLS. */
 186         return;
 187     } else if ( error != JVMTI_ERROR_NONE ) {
 188         /* The jthread object must be valid, so this must be a fatal error */
 189         EXIT_ERROR(error, "cannot set thread local storage");
 190     }
 191 }
 192 
 193 /* Get TLS on a specific jthread, which is the ThreadNode* */
 194 static ThreadNode *
 195 getThreadLocalStorage(jthread thread)
 196 {
 197     jvmtiError  error;
 198     ThreadNode *node;
 199 
 200     node = NULL;
 201     error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadLocalStorage)
 202             (gdata->jvmti, thread, (void**)&node);
 203     if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
 204         /* Just return NULL, thread hasn't started yet */
 205         return NULL;
 206     } else if ( error != JVMTI_ERROR_NONE ) {
 207         /* The jthread object must be valid, so this must be a fatal error */
 208         EXIT_ERROR(error, "cannot get thread local storage");
 209     }
 210     return node;
 211 }
 212 
 213 /* Search list for nodes that don't have TLS set and match this thread.
 214  *   It assumed that this logic is never dealing with terminated threads,
 215  *   since the ThreadEnd events always delete the ThreadNode while the
 216  *   jthread is still alive.  So we can only look at the ThreadNode's that
 217  *   have never had their TLS set, making the search much faster.
 218  *   But keep in mind, this kind of search should rarely be needed.
 219  */
 220 static ThreadNode *
 221 nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
 222 {
 223     ThreadNode *node;
 224 
 225     for (node = list->first; node != NULL; node = node->next) {
 226         if (isSameObject(env, node->thread, thread)) {
 227             break;
 228         }
 229     }
 230     return node;
 231 }
 232 
 233 /*
 234  * These functions maintain the linked list of currently running threads and vthreads.
 235  * All assume that the threadLock is held before calling.
 236  */
 237 
 238 /*
 239  * Search for a thread on the list. If list==NULL, search all lists.
 240  */
 241 static ThreadNode *
 242 findThread(ThreadList *list, jthread thread)
 243 {
 244     ThreadNode *node;
 245     JNIEnv *env = getEnv();
 246 
 247     /* Get thread local storage for quick thread -> node access */
 248     node = getThreadLocalStorage(thread);
 249 
 250     if ( node == NULL ) {
 251         /*
 252          * If the thread was not yet started when the ThreadNode was created, then it
 253          * got added to the otherThreads list and its thread local storage was not set.
 254          * Search for it in the otherThreads list.
 255          */
 256         if ( list == NULL || list == &otherThreads ) {
 257             node = nonTlsSearch(getEnv(), &otherThreads, thread);
 258         }
 259         /*
 260          * Normally we can assume that a thread with no TLS will never be in the runningThreads
 261          * list. This is because we always set the TLS when adding to runningThreads.
 262          * However, when a thread exits, its TLS is automatically cleared. Normally this
 263          * is not a problem because the debug agent will first get a THREAD_END event,
 264          * and that will cause the thread to be removed from runningThreads, thus we
 265          * avoid this situation of having a thread in runningThreads, but with no TLS.
 266          *
 267          * However... there is one exception to this. While handling VM_DEATH, the first thing
 268          * the debug agent does is clear all the callbacks. This means we will no longer
 269          * get THREAD_END events as threads exit. This means we might find threads on
 270          * runningThreads with no TLS during VM_DEATH. Essentially the THREAD_END that
 271          * would normally have resulted in removing the thread from runningThreads is
 272          * missed, so the thread remains on runningThreads.
 273          *
 274          * The end result of all this is that if the TLS lookup failed, we still need to check
 275          * if the thread is on runningThreads, but only if JVMTI callbacks have been cleared.
 276          * Otherwise the thread should not be on the runningThreads.
 277          */
 278         if ( !gdata->jvmtiCallBacksCleared ) {
 279             /* The thread better not be on runningThreads if the TLS lookup failed. */
 280             JDI_ASSERT(!nonTlsSearch(getEnv(), &runningThreads, thread));
 281         } else {
 282             /*
 283              * Search the runningThreads list. The TLS lookup may have failed because the
 284              * thread has terminated, but we never got the THREAD_END event.
 285              */
 286             if ( node == NULL ) {
 287                 if ( list == NULL || list == &runningThreads ) {
 288                     node = nonTlsSearch(getEnv(), &runningThreads, thread);
 289                 }
 290             }
 291         }
 292     }
 293 
 294     /* If a list is supplied, only return ones in this list */
 295     if ( node != NULL && list != NULL && node->list != list ) {
 296         return NULL;
 297     }
 298     return node;
 299 }
 300 
 301 /* Search for a running thread, including vthreads. */
 302 static ThreadNode *
 303 findRunningThread(jthread thread)
 304 {
 305     ThreadNode *node;
 306     if (isVThread(thread)) {
 307         node = findThread(&runningVThreads, thread);
 308     } else {
 309         node = findThread(&runningThreads, thread);
 310     }
 311     return node;
 312 }
 313 
 314 /* Remove a ThreadNode from a ThreadList */
 315 static void
 316 removeNode(ThreadList *list, ThreadNode *node)
 317 {
 318     ThreadNode *prev;
 319     ThreadNode *next;
 320 
 321     prev = node->prev;
 322     next = node->next;
 323     if ( prev != NULL ) {
 324         prev->next = next;
 325     }
 326     if ( next != NULL ) {
 327         next->prev = prev;
 328     }
 329     if ( prev == NULL ) {
 330         list->first = next;
 331     }
 332     node->next = NULL;
 333     node->prev = NULL;
 334     node->list = NULL;
 335 }
 336 
 337 /* Add a ThreadNode to a ThreadList */
 338 static void
 339 addNode(ThreadList *list, ThreadNode *node)
 340 {
 341     node->next = NULL;
 342     node->prev = NULL;
 343     node->list = NULL;
 344     if ( list->first == NULL ) {
 345         list->first = node;
 346     } else {
 347         list->first->prev = node;
 348         node->next = list->first;
 349         list->first = node;
 350     }
 351     node->list = list;
 352 }
 353 
 354 static ThreadNode *
 355 insertThread(JNIEnv *env, ThreadList *list, jthread thread)
 356 {
 357     ThreadNode *node;
 358     struct bag *eventBag;
 359     jboolean is_vthread = (list == &runningVThreads);
 360 
 361     node = findThread(list, thread);
 362     if (node == NULL) {
 363         node = jvmtiAllocate(sizeof(*node));
 364         if (node == NULL) {
 365             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 366             return NULL;
 367         }
 368         (void)memset(node, 0, sizeof(*node));
 369         eventBag = eventHelper_createEventBag();
 370         if (eventBag == NULL) {
 371             jvmtiDeallocate(node);
 372             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 373             return NULL;
 374         }
 375 
 376         /*
 377          * Init all flags false, all refs NULL, all counts 0
 378          */
 379 
 380         saveGlobalRef(env, thread, &(node->thread));
 381         if (node->thread == NULL) {
 382             jvmtiDeallocate(node);
 383             bagDestroyBag(eventBag);
 384             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 385             return NULL;
 386         }
 387         if (!is_vthread) {
 388             if (threadControl_isDebugThread(node->thread)) {
 389                 /* Remember if it is a debug thread */
 390                 node->isDebugThread = JNI_TRUE;
 391             } else {
 392                 if (suspendAllCount > 0) {
 393                     /*
 394                      * If there is a pending suspendAll, all new threads should
 395                      * be initialized as if they were suspended by the suspendAll,
 396                      * and the thread will need to be suspended when it starts.
 397                      */
 398                     node->suspendCount = suspendAllCount;
 399                     node->suspendOnStart = JNI_TRUE;
 400                 }
 401             }
 402         } else { /* vthread */
 403             jint vthread_state = 0;
 404             jvmtiError error = threadState(node->thread, &vthread_state);
 405             if (error != JVMTI_ERROR_NONE) {
 406                 EXIT_ERROR(error, "getting thread state");
 407             }
 408             if (suspendAllCount > 0) {
 409                 // Assume the suspendAllCount, just like the regular thread case above.
 410                 node->suspendCount = suspendAllCount;
 411                 if (vthread_state == 0) {
 412                     // If state == 0, then this is a new vthread that has not been started yet.
 413                     // Need to suspendOnStart in that case, just like the regular thread case above.
 414                     node->suspendOnStart = JNI_TRUE;
 415                     list = &otherThreads; // Put on otherThreads list instead of runningVThreads
 416                 }
 417             }
 418             if (vthread_state != 0) {
 419                 // This is an already started vthread that we were not already tracking.
 420                 node->isStarted = JNI_TRUE;
 421             }
 422         }
 423 
 424         node->current_ei = 0;
 425         node->is_vthread = is_vthread;
 426         node->instructionStepMode = JVMTI_DISABLE;
 427         node->eventBag = eventBag;
 428         addNode(list, node);
 429 
 430 #ifdef DEBUG_THREADNAME
 431         {
 432             /* Set the thread name */
 433             jvmtiThreadInfo info;
 434             jvmtiError error;
 435 
 436             memset(&info, 0, sizeof(info));
 437             error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
 438                     (gdata->jvmti, node->thread, &info);
 439             if (info.name != NULL) {
 440                 strncpy(node->name, info.name, sizeof(node->name) - 1);
 441                 jvmtiDeallocate(info.name);
 442             }
 443         }
 444 #endif
 445 
 446         /* Set thread local storage for quick thread -> node access.
 447          *   Threads that are not yet started do not allow setting of TLS. These
 448          *   threads go on the otherThreads list and have their TLS set
 449          *   when moved to the runningThreads list. findThread() knows to look
 450          *   on otherThreads when the TLS lookup fails.
 451          */
 452         if (list != &otherThreads) {
 453             setThreadLocalStorage(node->thread, (void*)node);
 454         }
 455     }
 456 
 457     return node;
 458 }
 459 
 460 static void
 461 clearThread(JNIEnv *env, ThreadNode *node)
 462 {
 463     if (node->pendingStop != NULL) {
 464         tossGlobalRef(env, &(node->pendingStop));
 465     }
 466     stepControl_clearRequest(node->thread, &node->currentStep);
 467     if (node->isDebugThread) {
 468         (void)threadControl_removeDebugThread(node->thread);
 469     }
 470     /* Clear out TLS on this thread (just a cleanup action) */
 471     setThreadLocalStorage(node->thread, NULL);
 472     tossGlobalRef(env, &(node->thread));
 473     bagDestroyBag(node->eventBag);
 474     jvmtiDeallocate(node);
 475 }
 476 
 477 static void
 478 removeThread(JNIEnv *env, ThreadList *list, jthread thread)
 479 {
 480     ThreadNode *node;
 481 
 482     node = findThread(list, thread);
 483     if (node != NULL) {
 484         removeNode(list, node);
 485         clearThread(env, node);
 486     }
 487 }
 488 
 489 static void
 490 removeResumed(JNIEnv *env, ThreadList *list)
 491 {
 492     ThreadNode *node;
 493 
 494     node = list->first;
 495     while (node != NULL) {
 496         ThreadNode *temp = node->next;
 497         if (node->suspendCount == 0) {
 498             removeThread(env, list, node->thread);
 499         }
 500         node = temp;
 501     }
 502 }
 503 
 504 static void
 505 moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node)
 506 {
 507     removeNode(source, node);
 508     // vthread fixme: we should really fix the caller to pass the right list
 509     if (node->is_vthread && dest == &runningThreads) {
 510         dest = &runningVThreads;
 511     }
 512     JDI_ASSERT(findThread(dest, node->thread) == NULL);
 513     addNode(dest, node);
 514 }
 515 
 516 typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);
 517 
 518 static jvmtiError
 519 enumerateOverThreadList(JNIEnv *env, ThreadList *list,
 520                         ThreadEnumerateFunction function, void *arg)
 521 {
 522     ThreadNode *node;
 523     jvmtiError error = JVMTI_ERROR_NONE;
 524 
 525     for (node = list->first; node != NULL; node = node->next) {
 526         error = (*function)(env, node, arg);
 527         if ( error != JVMTI_ERROR_NONE ) {
 528             break;
 529         }
 530     }
 531     return error;
 532 }
 533 
 534 static void
 535 insertEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode)
 536 {
 537     if (list->last != NULL) {
 538         list->last->next = eventMode;
 539     } else {
 540         list->first = eventMode;
 541     }
 542     list->last = eventMode;
 543 }
 544 
 545 static void
 546 removeEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode, DeferredEventMode *prev)
 547 {
 548     if (prev == NULL) {
 549         list->first = eventMode->next;
 550     } else {
 551         prev->next = eventMode->next;
 552     }
 553     if (eventMode->next == NULL) {
 554         list->last = prev;
 555     }
 556 }
 557 
 558 static jvmtiError
 559 addDeferredEventMode(JNIEnv *env, jvmtiEventMode mode, EventIndex ei, jthread thread)
 560 {
 561     DeferredEventMode *eventMode;
 562 
 563     /*LINTED*/
 564     eventMode = jvmtiAllocate((jint)sizeof(DeferredEventMode));
 565     if (eventMode == NULL) {
 566         return AGENT_ERROR_OUT_OF_MEMORY;
 567     }
 568     eventMode->thread = NULL;
 569     saveGlobalRef(env, thread, &(eventMode->thread));
 570     eventMode->mode = mode;
 571     eventMode->ei = ei;
 572     eventMode->next = NULL;
 573     insertEventMode(&deferredEventModes, eventMode);
 574     return JVMTI_ERROR_NONE;
 575 }
 576 
 577 static void
 578 freeDeferredEventModes(JNIEnv *env)
 579 {
 580     DeferredEventMode *eventMode;
 581     eventMode = deferredEventModes.first;
 582     while (eventMode != NULL) {
 583         DeferredEventMode *next;
 584         next = eventMode->next;
 585         tossGlobalRef(env, &(eventMode->thread));
 586         jvmtiDeallocate(eventMode);
 587         eventMode = next;
 588     }
 589     deferredEventModes.first = NULL;
 590     deferredEventModes.last = NULL;
 591 }
 592 
 593 static jvmtiError
 594 threadSetEventNotificationMode(ThreadNode *node,
 595         jvmtiEventMode mode, EventIndex ei, jthread thread)
 596 {
 597     jvmtiError error;
 598 
 599     /* record single step mode */
 600     if (ei == EI_SINGLE_STEP) {
 601         node->instructionStepMode = mode;
 602     }
 603     error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
 604         (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
 605     return error;
 606 }
 607 
 608 static void
 609 processDeferredEventModes(JNIEnv *env, jthread thread, ThreadNode *node)
 610 {
 611     jvmtiError error;
 612     DeferredEventMode *eventMode;
 613     DeferredEventMode *prev;
 614 
 615     prev = NULL;
 616     eventMode = deferredEventModes.first;
 617     while (eventMode != NULL) {
 618         DeferredEventMode *next = eventMode->next;
 619         if (isSameObject(env, thread, eventMode->thread)) {
 620             error = threadSetEventNotificationMode(node,
 621                     eventMode->mode, eventMode->ei, eventMode->thread);
 622             if (error != JVMTI_ERROR_NONE) {
 623                 EXIT_ERROR(error, "cannot process deferred thread event notifications at thread start");
 624             }
 625             removeEventMode(&deferredEventModes, eventMode, prev);
 626             tossGlobalRef(env, &(eventMode->thread));
 627             jvmtiDeallocate(eventMode);
 628         } else {
 629             prev = eventMode;
 630         }
 631         eventMode = next;
 632     }
 633 }
 634 
 635 static void
 636 getLocks(void)
 637 {
 638     /*
 639      * Anything which might be locked as part of the handling of
 640      * a JVMTI event (which means: might be locked by an application
 641      * thread) needs to be grabbed here. This allows thread control
 642      * code to safely suspend and resume the application threads
 643      * while ensuring they don't hold a critical lock.
 644      */
 645 
 646     eventHandler_lock();
 647     invoker_lock();
 648     eventHelper_lock();
 649     stepControl_lock();
 650     commonRef_lock();
 651     debugMonitorEnter(threadLock);
 652 
 653 }
 654 
 655 static void
 656 releaseLocks(void)
 657 {
 658     debugMonitorExit(threadLock);
 659     commonRef_unlock();
 660     stepControl_unlock();
 661     eventHelper_unlock();
 662     invoker_unlock();
 663     eventHandler_unlock();
 664 }
 665 
 666 void
 667 threadControl_initialize(void)
 668 {
 669     jlocation unused;
 670     jvmtiError error;
 671 
 672     suspendAllCount = 0;
 673     runningThreads.first = NULL;
 674     otherThreads.first = NULL;
 675     runningVThreads.first = NULL;
 676     debugThreadCount = 0;
 677     threadLock = debugMonitorCreate("JDWP Thread Lock");
 678     if (gdata->threadClass==NULL) {
 679         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class");
 680     }
 681     if (gdata->threadResume==0) {
 682         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread");
 683     }
 684     /* Get the java.lang.Thread.resume() method beginning location */
 685     error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
 686     if (error != JVMTI_ERROR_NONE) {
 687         EXIT_ERROR(error, "getting method location");
 688     }
 689 }
 690 
 691 static jthread
 692 getResumee(jthread resumingThread)
 693 {
 694     jthread resumee = NULL;
 695     jvmtiError error;
 696     jobject object;
 697     FrameNumber fnum = 0;
 698 
 699     error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
 700                     (gdata->jvmti, resumingThread, fnum, 0, &object);
 701     if (error == JVMTI_ERROR_NONE) {
 702         resumee = object;
 703     }
 704     return resumee;
 705 }
 706 
 707 
 708 static jboolean
 709 pendingAppResume(jboolean includeSuspended)
 710 {
 711     ThreadList *list;
 712     ThreadNode *node;
 713 
 714     list = &runningThreads;
 715     node = list->first;
 716     while (node != NULL) {
 717         if (node->resumeFrameDepth > 0) {
 718             if (includeSuspended) {
 719                 return JNI_TRUE;
 720             } else {
 721                 jvmtiError error;
 722                 jint       state;
 723 
 724                 error = threadState(node->thread, &state);
 725                 if (error != JVMTI_ERROR_NONE) {
 726                     EXIT_ERROR(error, "getting thread state");
 727                 }
 728                 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
 729                     return JNI_TRUE;
 730                 }
 731             }
 732         }
 733         node = node->next;
 734         if (node == NULL && list == &runningThreads) {
 735             // We need to look at runningVThreads after we are done with runningThreads.
 736             list = &runningVThreads;
 737             node = list->first;
 738         }
 739     }
 740     return JNI_FALSE;
 741 }
 742 
 743 static void
 744 notifyAppResumeComplete(void)
 745 {
 746     debugMonitorNotifyAll(threadLock);
 747     if (!pendingAppResume(JNI_TRUE)) {
 748         if (framePopHandlerNode != NULL) {
 749             (void)eventHandler_free(framePopHandlerNode);
 750             framePopHandlerNode = NULL;
 751         }
 752         if (catchHandlerNode != NULL) {
 753             (void)eventHandler_free(catchHandlerNode);
 754             catchHandlerNode = NULL;
 755         }
 756     }
 757 }
 758 
 759 /*
 760  * Event handler for FRAME_POP and EXCEPTION_CATCH when in Thread.resume()
 761  * so we can detect its completion.
 762  */
 763 static void
 764 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
 765                           HandlerNode *handlerNode,
 766                           struct bag *eventBag)
 767 {
 768     ThreadNode *node;
 769     jthread     thread;
 770 
 771     thread = evinfo->thread;
 772 
 773     debugMonitorEnter(threadLock);
 774 
 775     node = findRunningThread(thread);
 776     if (node != NULL) {
 777         if (node->resumeFrameDepth > 0) {
 778             jint compareDepth = getStackDepth(thread);
 779             if (evinfo->ei == EI_FRAME_POP) {
 780                 compareDepth--;
 781             }
 782             if (compareDepth < node->resumeFrameDepth) {
 783                 node->resumeFrameDepth = 0;
 784                 notifyAppResumeComplete();
 785             }
 786         }
 787     }
 788 
 789     debugMonitorExit(threadLock);
 790 }
 791 
 792 static void
 793 blockOnDebuggerSuspend(jthread thread)
 794 {
 795     ThreadNode *node;
 796 
 797     node = findThread(NULL, thread);
 798     if (node != NULL) {
 799         while (node && node->suspendCount > 0) {
 800             debugMonitorWait(threadLock);
 801             node = findThread(NULL, thread);
 802         }
 803     }
 804 }
 805 
 806 static void
 807 trackAppResume(jthread thread)
 808 {
 809     jvmtiError  error;
 810     FrameNumber fnum;
 811     ThreadNode *node;
 812 
 813     fnum = 0;
 814     node = findRunningThread(thread);
 815     if (node != NULL) {
 816         JDI_ASSERT(node->resumeFrameDepth == 0);
 817         error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
 818                         (gdata->jvmti, thread, fnum);
 819         if (error == JVMTI_ERROR_NONE) {
 820             jint frameDepth = getStackDepth(thread);
 821             if ((frameDepth > 0) && (framePopHandlerNode == NULL)) {
 822                 framePopHandlerNode = eventHandler_createInternalThreadOnly(
 823                                            EI_FRAME_POP,
 824                                            handleAppResumeCompletion,
 825                                            thread);
 826                 catchHandlerNode = eventHandler_createInternalThreadOnly(
 827                                            EI_EXCEPTION_CATCH,
 828                                            handleAppResumeCompletion,
 829                                            thread);
 830                 if ((framePopHandlerNode == NULL) ||
 831                     (catchHandlerNode == NULL)) {
 832                     (void)eventHandler_free(framePopHandlerNode);
 833                     framePopHandlerNode = NULL;
 834                     (void)eventHandler_free(catchHandlerNode);
 835                     catchHandlerNode = NULL;
 836                 }
 837             }
 838             if ((framePopHandlerNode != NULL) &&
 839                 (catchHandlerNode != NULL) &&
 840                 (frameDepth > 0)) {
 841                 node->resumeFrameDepth = frameDepth;
 842             }
 843         }
 844     }
 845 }
 846 
 847 /* Global breakpoint handler for Thread.resume() */
 848 static void
 849 handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo,
 850                           HandlerNode *handlerNode,
 851                           struct bag *eventBag)
 852 {
 853     jthread resumer = evinfo->thread;
 854     jthread resumee = getResumee(resumer);
 855 
 856     debugMonitorEnter(threadLock);
 857     if (resumee != NULL) {
 858         /*
 859          * Hold up any attempt to resume as long as the debugger
 860          * has suspended the resumee.
 861          */
 862         blockOnDebuggerSuspend(resumee);
 863     }
 864 
 865     if (resumer != NULL) {
 866         /*
 867          * Track the resuming thread by marking it as being within
 868          * a resume and by setting up for notification on
 869          * a frame pop or exception. We won't allow the debugger
 870          * to suspend threads while any thread is within a
 871          * call to resume. This (along with the block above)
 872          * ensures that when the debugger
 873          * suspends a thread it will remain suspended.
 874          */
 875         trackAppResume(resumer);
 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             }
1692 
1693             /*
1694              * Increment suspendCount of each virtual thread that we are tracking. Note the
1695              * compliment to this that happens during the resumeAll() is handled by
1696              * commonResumeList(), so it's a bit orthogonal to how we handle incrementing
1697              * the suspendCount.
1698              */
1699             error = enumerateOverThreadList(env, &runningVThreads, incrementSuspendCountHelper, NULL);
1700             JDI_ASSERT(error == JVMTI_ERROR_NONE);
1701         }
1702 
1703         threads = allThreads(&count);
1704         if (threads == NULL) {
1705             error = AGENT_ERROR_OUT_OF_MEMORY;
1706             goto err;
1707         }
1708         error = commonSuspendList(env, count, threads);
1709         if (error != JVMTI_ERROR_NONE) {
1710             goto err;
1711         }
1712 
1713         /*
1714          * Update the suspend count of any threads not yet (or no longer)
1715          * in the thread list above.
1716          */
1717         {
1718             SuspendAllArg arg;
1719             arg.list = threads;
1720             arg.count = count;
1721             error = enumerateOverThreadList(env, &otherThreads,
1722                                             suspendAllHelper, &arg);
1723         }
1724 
1725         if (error == JVMTI_ERROR_NONE) {
1726             /*
1727              * Pin all objects to prevent objects from being
1728              * garbage collected while the VM is suspended.
1729              */
1730             commonRef_pinAll();
1731 
1732             suspendAllCount++;
1733         }
1734 
1735     err:
1736         jvmtiDeallocate(threads);
1737 
1738     } END_WITH_LOCAL_REFS(env)
1739 
1740     postSuspend();
1741 
1742     return error;
1743 }
1744 
1745 static jvmtiError
1746 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1747 {
1748     /*
1749      * Since this helper is called with the threadLock held, we
1750      * don't need to recheck to see if the node is still on one
1751      * of the two thread lists.
1752      */
1753     return resumeThreadByNode(node);
1754 }
1755 
1756 static jvmtiError
1757 excludeCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1758 {
1759     JDI_ASSERT(node->is_vthread);
1760     if (node->suspendCount > 0) {
1761         jint *counter = (jint *)arg;
1762         (*counter)++;
1763     }
1764     return JVMTI_ERROR_NONE;
1765 }
1766 
1767 static jvmtiError
1768 excludeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1769 {
1770     JDI_ASSERT(node->is_vthread);
1771     if (node->suspendCount > 0) {
1772         jthread **listPtr = (jthread **)arg;
1773         **listPtr = node->thread;
1774         (*listPtr)++;
1775     }
1776     return JVMTI_ERROR_NONE;
1777 }
1778 
1779 jvmtiError
1780 threadControl_resumeAll(void)
1781 {
1782     jvmtiError error;
1783     JNIEnv    *env;
1784 #if 0
1785     tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount);
1786 #endif
1787 
1788     env = getEnv();
1789 
1790     log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1791 
1792     eventHandler_lock(); /* for proper lock order */
1793     debugMonitorEnter(threadLock);
1794 
1795     if (gdata->vthreadsSupported) {
1796         if (suspendAllCount == 1) {
1797             jint excludeCnt = 0;
1798             jthread *excludeList = NULL;
1799             /*
1800              * Tell JVMTI to resume all virtual threads except for those we
1801              * are tracking separately. The commonResumeList() call below will
1802              * resume any vthread with a suspendCount == 1, and we want to ignore
1803              * vthreads with a suspendCount > 0. Therefor we don't want
1804              * ResumeAllVirtualThreads resuming these vthreads. We must first
1805              * build a list of them to pass to as the exclude list.
1806              */
1807             enumerateOverThreadList(env, &runningVThreads, excludeCountHelper,
1808                                     &excludeCnt);
1809             if (excludeCnt > 0) {
1810                 excludeList = newArray(excludeCnt, sizeof(jthread));
1811                 if (excludeList == NULL) {
1812                     EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"exclude list");
1813                 }
1814                 {
1815                     jthread *excludeListPtr = excludeList;
1816                     enumerateOverThreadList(env, &runningVThreads, excludeCopyHelper,
1817                                             &excludeListPtr);
1818                 }
1819             }
1820             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeAllVirtualThreads)
1821                     (gdata->jvmti, excludeCnt, excludeList);
1822             if (error != JVMTI_ERROR_NONE) {
1823                 EXIT_ERROR(error, "cannot resume all virtual threads");
1824             }
1825         }
1826     }
1827 
1828     /*
1829      * Resume only those threads that the debugger has suspended. All
1830      * such threads must have a node in one of the thread lists, so there's
1831      * no need to get the whole thread list from JVMTI (unlike
1832      * suspendAll).
1833      */
1834     error = commonResumeList(env);
1835     if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1836         error = enumerateOverThreadList(env, &otherThreads,
1837                                         resumeHelper, NULL);
1838         removeResumed(env, &otherThreads);
1839     }
1840 
1841     if (suspendAllCount > 0) {
1842         /*
1843          * Unpin all objects.
1844          */
1845         commonRef_unpinAll();
1846 
1847         suspendAllCount--;
1848     }
1849 
1850     debugMonitorExit(threadLock);
1851     eventHandler_unlock();
1852     /* let eventHelper.c: commandLoop() know we are resuming */
1853     unblockCommandLoop();
1854 
1855     return error;
1856 }
1857 
1858 
1859 StepRequest *
1860 threadControl_getStepRequest(jthread thread)
1861 {
1862     ThreadNode  *node;
1863     StepRequest *step;
1864 
1865     step = NULL;
1866 
1867     debugMonitorEnter(threadLock);
1868 
1869     node = findRunningThread(thread);
1870     if (node != NULL) {
1871         step = &node->currentStep;
1872     }
1873 
1874     debugMonitorExit(threadLock);
1875 
1876     return step;
1877 }
1878 
1879 InvokeRequest *
1880 threadControl_getInvokeRequest(jthread thread)
1881 {
1882     ThreadNode    *node;
1883     InvokeRequest *request;
1884 
1885     request = NULL;
1886 
1887     debugMonitorEnter(threadLock);
1888 
1889     node = findRunningThread(thread);
1890     if (node != NULL) {
1891          request = &node->currentInvoke;
1892     }
1893 
1894     debugMonitorExit(threadLock);
1895 
1896     return request;
1897 }
1898 
1899 jvmtiError
1900 threadControl_addDebugThread(jthread thread)
1901 {
1902     jvmtiError error;
1903 
1904     debugMonitorEnter(threadLock);
1905     if (debugThreadCount >= MAX_DEBUG_THREADS) {
1906         error = AGENT_ERROR_OUT_OF_MEMORY;
1907     } else {
1908         JNIEnv    *env;
1909 
1910         env = getEnv();
1911         debugThreads[debugThreadCount] = NULL;
1912         saveGlobalRef(env, thread, &(debugThreads[debugThreadCount]));
1913         if (debugThreads[debugThreadCount] == NULL) {
1914             error = AGENT_ERROR_OUT_OF_MEMORY;
1915         } else {
1916             debugThreadCount++;
1917             error = JVMTI_ERROR_NONE;
1918         }
1919     }
1920     debugMonitorExit(threadLock);
1921     return error;
1922 }
1923 
1924 static jvmtiError
1925 threadControl_removeDebugThread(jthread thread)
1926 {
1927     jvmtiError error;
1928     JNIEnv    *env;
1929     int        i;
1930 
1931     error = AGENT_ERROR_INVALID_THREAD;
1932     env   = getEnv();
1933 
1934     debugMonitorEnter(threadLock);
1935     for (i = 0; i< debugThreadCount; i++) {
1936         if (isSameObject(env, thread, debugThreads[i])) {
1937             int j;
1938 
1939             tossGlobalRef(env, &(debugThreads[i]));
1940             for (j = i+1; j < debugThreadCount; j++) {
1941                 debugThreads[j-1] = debugThreads[j];
1942             }
1943             debugThreadCount--;
1944             error = JVMTI_ERROR_NONE;
1945             break;
1946         }
1947     }
1948     debugMonitorExit(threadLock);
1949     return error;
1950 }
1951 
1952 jboolean
1953 threadControl_isDebugThread(jthread thread)
1954 {
1955     int      i;
1956     jboolean rc;
1957     JNIEnv  *env;
1958 
1959     rc  = JNI_FALSE;
1960     env = getEnv();
1961 
1962     debugMonitorEnter(threadLock);
1963     for (i = 0; i < debugThreadCount; i++) {
1964         if (isSameObject(env, thread, debugThreads[i])) {
1965             rc = JNI_TRUE;
1966             break;
1967         }
1968     }
1969     debugMonitorExit(threadLock);
1970     return rc;
1971 }
1972 
1973 static void
1974 initLocks(void)
1975 {
1976     if (popFrameEventLock == NULL) {
1977         popFrameEventLock = debugMonitorCreate("JDWP PopFrame Event Lock");
1978         popFrameProceedLock = debugMonitorCreate("JDWP PopFrame Proceed Lock");
1979     }
1980 }
1981 
1982 static jboolean
1983 getPopFrameThread(jthread thread)
1984 {
1985     jboolean popFrameThread;
1986 
1987     debugMonitorEnter(threadLock);
1988     {
1989         ThreadNode *node;
1990 
1991         node = findThread(NULL, thread);
1992         if (node == NULL) {
1993             popFrameThread = JNI_FALSE;
1994         } else {
1995             popFrameThread = node->popFrameThread;
1996         }
1997     }
1998     debugMonitorExit(threadLock);
1999 
2000     return popFrameThread;
2001 }
2002 
2003 static void
2004 setPopFrameThread(jthread thread, jboolean value)
2005 {
2006     debugMonitorEnter(threadLock);
2007     {
2008         ThreadNode *node;
2009 
2010         node = findThread(NULL, thread);
2011         if (node == NULL) {
2012             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2013         } else {
2014             node->popFrameThread = value;
2015         }
2016     }
2017     debugMonitorExit(threadLock);
2018 }
2019 
2020 static jboolean
2021 getPopFrameEvent(jthread thread)
2022 {
2023     jboolean popFrameEvent;
2024 
2025     debugMonitorEnter(threadLock);
2026     {
2027         ThreadNode *node;
2028 
2029         node = findThread(NULL, thread);
2030         if (node == NULL) {
2031             popFrameEvent = JNI_FALSE;
2032             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2033         } else {
2034             popFrameEvent = node->popFrameEvent;
2035         }
2036     }
2037     debugMonitorExit(threadLock);
2038 
2039     return popFrameEvent;
2040 }
2041 
2042 static void
2043 setPopFrameEvent(jthread thread, jboolean value)
2044 {
2045     debugMonitorEnter(threadLock);
2046     {
2047         ThreadNode *node;
2048 
2049         node = findThread(NULL, thread);
2050         if (node == NULL) {
2051             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2052         } else {
2053             node->popFrameEvent = value;
2054             node->frameGeneration++; /* Increment on each resume */
2055         }
2056     }
2057     debugMonitorExit(threadLock);
2058 }
2059 
2060 static jboolean
2061 getPopFrameProceed(jthread thread)
2062 {
2063     jboolean popFrameProceed;
2064 
2065     debugMonitorEnter(threadLock);
2066     {
2067         ThreadNode *node;
2068 
2069         node = findThread(NULL, thread);
2070         if (node == NULL) {
2071             popFrameProceed = JNI_FALSE;
2072             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2073         } else {
2074             popFrameProceed = node->popFrameProceed;
2075         }
2076     }
2077     debugMonitorExit(threadLock);
2078 
2079     return popFrameProceed;
2080 }
2081 
2082 static void
2083 setPopFrameProceed(jthread thread, jboolean value)
2084 {
2085     debugMonitorEnter(threadLock);
2086     {
2087         ThreadNode *node;
2088 
2089         node = findThread(NULL, thread);
2090         if (node == NULL) {
2091             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2092         } else {
2093             node->popFrameProceed = value;
2094         }
2095     }
2096     debugMonitorExit(threadLock);
2097 }
2098 
2099 /**
2100  * Special event handler for events on the popped thread
2101  * that occur during the pop operation.
2102  */
2103 static void
2104 popFrameCompleteEvent(jthread thread)
2105 {
2106       debugMonitorEnter(popFrameProceedLock);
2107       {
2108           /* notify that we got the event */
2109           debugMonitorEnter(popFrameEventLock);
2110           {
2111               setPopFrameEvent(thread, JNI_TRUE);
2112               debugMonitorNotify(popFrameEventLock);
2113           }
2114           debugMonitorExit(popFrameEventLock);
2115 
2116           /* make sure we get suspended again */
2117           setPopFrameProceed(thread, JNI_FALSE);
2118           while (getPopFrameProceed(thread) == JNI_FALSE) {
2119               debugMonitorWait(popFrameProceedLock);
2120           }
2121       }
2122       debugMonitorExit(popFrameProceedLock);
2123 }
2124 
2125 /**
2126  * Pop one frame off the stack of thread.
2127  * popFrameEventLock is already held
2128  */
2129 static jvmtiError
2130 popOneFrame(jthread thread)
2131 {
2132     jvmtiError error;
2133 
2134     error = JVMTI_FUNC_PTR(gdata->jvmti,PopFrame)(gdata->jvmti, thread);
2135     if (error != JVMTI_ERROR_NONE) {
2136         return error;
2137     }
2138 
2139     /* resume the popped thread so that the pop occurs and so we */
2140     /* will get the event (step or method entry) after the pop */
2141     LOG_MISC(("thread=%p resumed in popOneFrame", thread));
2142     error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, thread);
2143     if (error != JVMTI_ERROR_NONE) {
2144         return error;
2145     }
2146 
2147     /* wait for the event to occur */
2148     setPopFrameEvent(thread, JNI_FALSE);
2149     while (getPopFrameEvent(thread) == JNI_FALSE) {
2150         debugMonitorWait(popFrameEventLock);
2151     }
2152 
2153     /* make sure not to suspend until the popped thread is on the wait */
2154     debugMonitorEnter(popFrameProceedLock);
2155     {
2156         /* return popped thread to suspended state */
2157         LOG_MISC(("thread=%p suspended in popOneFrame", thread));
2158         error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)(gdata->jvmti, thread);
2159 
2160         /* notify popped thread so it can proceed when resumed */
2161         setPopFrameProceed(thread, JNI_TRUE);
2162         debugMonitorNotify(popFrameProceedLock);
2163     }
2164     debugMonitorExit(popFrameProceedLock);
2165 
2166     return error;
2167 }
2168 
2169 /**
2170  * pop frames of the stack of 'thread' until 'frame' is popped.
2171  */
2172 jvmtiError
2173 threadControl_popFrames(jthread thread, FrameNumber fnum)
2174 {
2175     jvmtiError error;
2176     jvmtiEventMode prevStepMode;
2177     jint framesPopped = 0;
2178     jint popCount;
2179     jboolean prevInvokeRequestMode;
2180 
2181     log_debugee_location("threadControl_popFrames()", thread, NULL, 0);
2182 
2183     initLocks();
2184 
2185     /* compute the number of frames to pop */
2186     popCount = fnum+1;
2187     if (popCount < 1) {
2188         return AGENT_ERROR_NO_MORE_FRAMES;
2189     }
2190 
2191     /* enable instruction level single step, but first note prev value */
2192     prevStepMode = threadControl_getInstructionStepMode(thread);
2193 
2194     /*
2195      * Fix bug 6517249.  The pop processing will disable invokes,
2196      * so remember if invokes are enabled now and restore
2197      * that state after we finish popping.
2198      */
2199     prevInvokeRequestMode = invoker_isEnabled(thread);
2200 
2201     error = threadControl_setEventMode(JVMTI_ENABLE,
2202                                        EI_SINGLE_STEP, thread);
2203     if (error != JVMTI_ERROR_NONE) {
2204         return error;
2205     }
2206 
2207     /* Inform eventHandler logic we are in a popFrame for this thread */
2208     debugMonitorEnter(popFrameEventLock);
2209     {
2210         setPopFrameThread(thread, JNI_TRUE);
2211         /* pop frames using single step */
2212         while (framesPopped++ < popCount) {
2213             error = popOneFrame(thread);
2214             if (error != JVMTI_ERROR_NONE) {
2215                 break;
2216             }
2217         }
2218         setPopFrameThread(thread, JNI_FALSE);
2219     }
2220     debugMonitorExit(popFrameEventLock);
2221 
2222     /*  Reset StepRequest info (fromLine and stackDepth) after popframes
2223      *  only if stepping is enabled.
2224      */
2225     if (prevStepMode == JVMTI_ENABLE) {
2226         stepControl_resetRequest(thread);
2227     }
2228 
2229     if (prevInvokeRequestMode) {
2230         invoker_enableInvokeRequests(thread);
2231     }
2232 
2233     /* restore state */
2234     (void)threadControl_setEventMode(prevStepMode,
2235                                EI_SINGLE_STEP, thread);
2236 
2237     return error;
2238 }
2239 
2240 /* Check to see if any events are being consumed by a popFrame(). */
2241 static jboolean
2242 checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread)
2243 {
2244     if ( getPopFrameThread(thread) ) {
2245         switch (ei) {
2246             case EI_THREAD_START:
2247                 /* Excuse me? */
2248                 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame");
2249                 break;
2250             case EI_THREAD_END:
2251                 /* Thread wants to end? let it. */
2252                 setPopFrameThread(thread, JNI_FALSE);
2253                 popFrameCompleteEvent(thread);
2254                 break;
2255             case EI_VIRTUAL_THREAD_START:
2256             case EI_VIRTUAL_THREAD_END:
2257                 JDI_ASSERT(JNI_FALSE);
2258                 break;
2259             case EI_SINGLE_STEP:
2260                 /* This is an event we requested to mark the */
2261                 /*        completion of the pop frame */
2262                 popFrameCompleteEvent(thread);
2263                 return JNI_TRUE;
2264             case EI_BREAKPOINT:
2265             case EI_EXCEPTION:
2266             case EI_FIELD_ACCESS:
2267             case EI_FIELD_MODIFICATION:
2268             case EI_METHOD_ENTRY:
2269             case EI_METHOD_EXIT:
2270                 /* Tell event handler to assume event has been consumed. */
2271                 return JNI_TRUE;
2272             default:
2273                 break;
2274         }
2275     }
2276     /* Pretend we were never called */
2277     return JNI_FALSE;
2278 }
2279 
2280 struct bag *
2281 threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject currentException)
2282 {
2283     ThreadNode *node;
2284     JNIEnv     *env;
2285     struct bag *eventBag;
2286     jthread     threadToSuspend;
2287     jboolean    consumed;
2288     EventIndex  ei = evinfo->ei;
2289     jthread     thread = evinfo->thread;
2290 
2291     env             = getEnv();
2292     threadToSuspend = NULL;
2293 
2294     log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL, 0);
2295 
2296     /* Events during pop commands may need to be ignored here. */
2297     consumed = checkForPopFrameEvents(env, ei, thread);
2298     if ( consumed ) {
2299         /* Always restore any exception (see below). */
2300         if (currentException != NULL) {
2301             JNI_FUNC_PTR(env,Throw)(env, currentException);
2302         } else {
2303             JNI_FUNC_PTR(env,ExceptionClear)(env);
2304         }
2305         return NULL;
2306     }
2307 
2308     debugMonitorEnter(threadLock);
2309 
2310     /*
2311      * Check the list of unknown threads maintained by suspend
2312      * and resume. If this thread is currently present in the
2313      * list, it should be
2314      * moved to the runningThreads list, since it is a
2315      * well-known thread now.
2316      */
2317     node = findThread(&otherThreads, thread);
2318     if (node != NULL) {
2319         moveNode(&otherThreads, &runningThreads, node);
2320         /* Now that we know the thread has started, we can set its TLS.*/
2321         setThreadLocalStorage(thread, (void*)node);
2322     } else {
2323         /*
2324          * Get a thread node for the reporting thread. For thread start
2325          * events, or if this event precedes a thread start event,
2326          * the thread node may need to be created.
2327          *
2328          * It is possible for certain events (notably method entry/exit)
2329          * to precede thread start for some VM implementations.
2330          */
2331         if (evinfo->is_vthread) {
2332           /* fiber fixme: don't add the vthread if this is an EI_THREAD_START or
2333              EI_THREAD_EXIT event. Otherwise we end up adding every vthread. This
2334              is an issue when notifyVThreads is true, which is the default.
2335           */
2336             node = insertThread(env, &runningVThreads, thread);
2337         } else {
2338             node = insertThread(env, &runningThreads, thread);
2339         }
2340     }
2341 
2342     if (ei == EI_THREAD_START || ei == EI_VIRTUAL_THREAD_START) {
2343         node->isStarted = JNI_TRUE;
2344         processDeferredEventModes(env, thread, node);
2345     }
2346 
2347     node->current_ei = ei;
2348     eventBag = node->eventBag;
2349     if (node->suspendOnStart) {
2350         threadToSuspend = node->thread;
2351     }
2352     debugMonitorExit(threadLock);
2353 
2354     if (threadToSuspend != NULL) {
2355         /*
2356          * An attempt was made to suspend this thread before it started.
2357          * We must suspend it now, before it starts to run. This must
2358          * be done with no locks held.
2359          */
2360         eventHelper_suspendThread(sessionID, threadToSuspend);
2361     }
2362 
2363     return eventBag;
2364 }
2365 
2366 static void
2367 doPendingTasks(JNIEnv *env, ThreadNode *node)
2368 {
2369     /*
2370      * Take care of any pending interrupts/stops, and clear out
2371      * info on pending interrupts/stops.
2372      */
2373     if (node->pendingInterrupt) {
2374         JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2375                         (gdata->jvmti, node->thread);
2376         /*
2377          * TO DO: Log error
2378          */
2379         node->pendingInterrupt = JNI_FALSE;
2380     }
2381 
2382     if (node->pendingStop != NULL) {
2383         JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2384                         (gdata->jvmti, node->thread, node->pendingStop);
2385         /*
2386          * TO DO: Log error
2387          */
2388         tossGlobalRef(env, &(node->pendingStop));
2389     }
2390 }
2391 
2392 void
2393 threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
2394                                  struct bag *eventBag)
2395 {
2396     ThreadNode *node;
2397 
2398     log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0);
2399 
2400     if (ei == EI_THREAD_END) {
2401         eventHandler_lock(); /* for proper lock order */
2402     }
2403     debugMonitorEnter(threadLock);
2404 
2405     node = findRunningThread(thread);
2406     if (node == NULL) {
2407         EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2408     } else {
2409         JNIEnv *env;
2410 
2411         env = getEnv();
2412         if (ei == EI_THREAD_END) {
2413             jboolean inResume = (node->resumeFrameDepth > 0);
2414             if (isVThread(thread)) {
2415                 removeThread(env, &runningVThreads, thread);
2416             } else {
2417                 removeThread(env, &runningThreads, thread);
2418             }
2419             node = NULL;   /* has been freed */
2420 
2421             /*
2422              * Clean up mechanism used to detect end of
2423              * resume.
2424              */
2425             if (inResume) {
2426                 notifyAppResumeComplete();
2427             }
2428         } else {
2429             /* No point in doing this if the thread is about to die.*/
2430             doPendingTasks(env, node);
2431             node->eventBag = eventBag;
2432             node->current_ei = 0;
2433         }
2434     }
2435 
2436     debugMonitorExit(threadLock);
2437     if (ei == EI_THREAD_END) {
2438         eventHandler_unlock();
2439     }
2440 }
2441 
2442 /* Returns JDWP flavored status and status flags. */
2443 jvmtiError
2444 threadControl_applicationThreadStatus(jthread thread,
2445                         jdwpThreadStatus *pstatus, jint *statusFlags)
2446 {
2447     ThreadNode *node;
2448     jvmtiError  error;
2449     jint        state;
2450 
2451     log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2452 
2453     debugMonitorEnter(threadLock);
2454 
2455     error = threadState(thread, &state);
2456     *pstatus = map2jdwpThreadStatus(state);
2457     *statusFlags = map2jdwpSuspendStatus(state);
2458 
2459     if (error == JVMTI_ERROR_NONE) {
2460         node = findRunningThread(thread);
2461         if ((node != NULL) && HANDLING_EVENT(node)) {
2462             /*
2463              * While processing an event, an application thread is always
2464              * considered to be running even if its handler happens to be
2465              * cond waiting on an internal debugger monitor, etc.
2466              *
2467              * Leave suspend status untouched since it is not possible
2468              * to distinguish debugger suspends from app suspends.
2469              */
2470             *pstatus = JDWP_THREAD_STATUS(RUNNING);
2471         }
2472     }
2473 #if 0
2474     tty_message("status %s: node(%p) suspendCount(%d) %d %d %s",
2475                 isVThread(thread) ? "vthread" : "thread",
2476                 node, node->suspendCount, *pstatus, *statusFlags, node->name);
2477 #endif
2478 
2479     debugMonitorExit(threadLock);
2480 
2481     return error;
2482 }
2483 
2484 jvmtiError
2485 threadControl_interrupt(jthread thread)
2486 {
2487     ThreadNode *node;
2488     jvmtiError  error;
2489 
2490     // vthread fixme: should this work for vthreads?
2491     JDI_ASSERT(!isVThread(thread));
2492 
2493     error = JVMTI_ERROR_NONE;
2494 
2495     log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2496 
2497     debugMonitorEnter(threadLock);
2498 
2499     node = findThread(&runningThreads, thread);
2500     if ((node == NULL) || !HANDLING_EVENT(node)) {
2501         error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2502                         (gdata->jvmti, thread);
2503     } else {
2504         /*
2505          * Hold any interrupts until after the event is processed.
2506          */
2507         node->pendingInterrupt = JNI_TRUE;
2508     }
2509 
2510     debugMonitorExit(threadLock);
2511 
2512     return error;
2513 }
2514 
2515 void
2516 threadControl_clearCLEInfo(JNIEnv *env, jthread thread)
2517 {
2518     ThreadNode *node;
2519 
2520     debugMonitorEnter(threadLock);
2521 
2522     node = findRunningThread(thread);
2523     if (node != NULL) {
2524         node->cleInfo.ei = 0;
2525         if (node->cleInfo.clazz != NULL) {
2526             tossGlobalRef(env, &(node->cleInfo.clazz));
2527         }
2528     }
2529 
2530     debugMonitorExit(threadLock);
2531 }
2532 
2533 jboolean
2534 threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz,
2535                          jmethodID method, jlocation location)
2536 {
2537     ThreadNode *node;
2538     jboolean    result;
2539 
2540     result = JNI_FALSE;
2541 
2542     debugMonitorEnter(threadLock);
2543 
2544     node = findRunningThread(thread);
2545     if (node != NULL && node->cleInfo.ei != 0 &&
2546         node->cleInfo.method == method &&
2547         node->cleInfo.location == location &&
2548         (isSameObject(env, node->cleInfo.clazz, clazz))) {
2549         result = JNI_TRUE; /* we have a match */
2550     }
2551 
2552     debugMonitorExit(threadLock);
2553 
2554     return result;
2555 }
2556 
2557 void
2558 threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
2559                           jclass clazz, jmethodID method, jlocation location)
2560 {
2561     ThreadNode *node;
2562 
2563     debugMonitorEnter(threadLock);
2564 
2565     node = findRunningThread(thread);
2566     if (node != NULL) {
2567         node->cleInfo.ei = ei;
2568         /* Create a class ref that will live beyond */
2569         /* the end of this call */
2570         saveGlobalRef(env, clazz, &(node->cleInfo.clazz));
2571         /* if returned clazz is NULL, we just won't match */
2572         node->cleInfo.method    = method;
2573         node->cleInfo.location  = location;
2574     }
2575 
2576     debugMonitorExit(threadLock);
2577 }
2578 
2579 void
2580 threadControl_setPendingInterrupt(jthread thread)
2581 {
2582     ThreadNode *node;
2583 
2584     // vthread fixme: should this work for vthreads?
2585     JDI_ASSERT(!isVThread(thread));
2586 
2587     debugMonitorEnter(threadLock);
2588 
2589     node = findThread(&runningThreads, thread);
2590     if (node != NULL) {
2591         node->pendingInterrupt = JNI_TRUE;
2592     }
2593 
2594     debugMonitorExit(threadLock);
2595 }
2596 
2597 jvmtiError
2598 threadControl_stop(jthread thread, jobject throwable)
2599 {
2600     ThreadNode *node;
2601     jvmtiError  error;
2602 
2603     // vthread fixme: should this work for vthreads?
2604     JDI_ASSERT(!isVThread(thread));
2605 
2606     error = JVMTI_ERROR_NONE;
2607 
2608     log_debugee_location("threadControl_stop()", thread, NULL, 0);
2609 
2610     debugMonitorEnter(threadLock);
2611 
2612     node = findThread(&runningThreads, thread);
2613     if ((node == NULL) || !HANDLING_EVENT(node)) {
2614         error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2615                         (gdata->jvmti, thread, throwable);
2616     } else {
2617         JNIEnv *env;
2618 
2619         /*
2620          * Hold any stops until after the event is processed.
2621          */
2622         env = getEnv();
2623         saveGlobalRef(env, throwable, &(node->pendingStop));
2624     }
2625 
2626     debugMonitorExit(threadLock);
2627 
2628     return error;
2629 }
2630 
2631 static jvmtiError
2632 detachHelper(JNIEnv *env, ThreadNode *node, void *arg)
2633 {
2634     invoker_detach(&node->currentInvoke);
2635     return JVMTI_ERROR_NONE;
2636 }
2637 
2638 void
2639 threadControl_detachInvokes(void)
2640 {
2641     JNIEnv *env;
2642 
2643     env = getEnv();
2644     invoker_lock(); /* for proper lock order */
2645     debugMonitorEnter(threadLock);
2646     (void)enumerateOverThreadList(env, &runningThreads, detachHelper, NULL);
2647     debugMonitorExit(threadLock);
2648     invoker_unlock();
2649 }
2650 
2651 static jvmtiError
2652 resetHelper(JNIEnv *env, ThreadNode *node, void *arg)
2653 {
2654     if (node->toBeResumed) {
2655         LOG_MISC(("thread=%p resumed", node->thread));
2656         (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, node->thread);
2657         node->frameGeneration++; /* Increment on each resume */
2658     }
2659     stepControl_clearRequest(node->thread, &node->currentStep);
2660     node->toBeResumed = JNI_FALSE;
2661     node->suspendCount = 0;
2662     node->suspendOnStart = JNI_FALSE;
2663 
2664     return JVMTI_ERROR_NONE;
2665 }
2666 
2667 void
2668 threadControl_reset(void)
2669 {
2670     JNIEnv *env;
2671 
2672     env = getEnv();
2673     eventHandler_lock(); /* for proper lock order */
2674     debugMonitorEnter(threadLock);
2675 
2676     if (gdata->vthreadsSupported) {
2677         if (suspendAllCount > 0) {
2678             /* Tell JVMTI to resume all virtual threads. */
2679             jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeAllVirtualThreads)
2680               (gdata->jvmti, 0, NULL);
2681             if (error != JVMTI_ERROR_NONE) {
2682                 EXIT_ERROR(error, "cannot resume all virtual threads");
2683             }
2684         }
2685     }
2686 
2687     (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2688     (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);
2689     (void)enumerateOverThreadList(env, &runningVThreads, resetHelper, NULL);
2690 
2691     removeResumed(env, &otherThreads);
2692 
2693     freeDeferredEventModes(env);
2694 
2695     suspendAllCount = 0;
2696 
2697     /* Everything should have been resumed */
2698     JDI_ASSERT(otherThreads.first == NULL);
2699 
2700     debugMonitorExit(threadLock);
2701     eventHandler_unlock();
2702 }
2703 
2704 jvmtiEventMode
2705 threadControl_getInstructionStepMode(jthread thread)
2706 {
2707     ThreadNode    *node;
2708     jvmtiEventMode mode;
2709 
2710     mode = JVMTI_DISABLE;
2711 
2712     debugMonitorEnter(threadLock);
2713     node = findRunningThread(thread);
2714     if (node != NULL) {
2715         mode = node->instructionStepMode;
2716     }
2717     debugMonitorExit(threadLock);
2718     return mode;
2719 }
2720 
2721 jvmtiError
2722 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2723 {
2724     jvmtiError error;
2725 
2726     /* Global event */
2727     if ( thread == NULL ) {
2728         error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2729                     (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2730     } else {
2731         /* Thread event */
2732         ThreadNode *node;
2733 
2734         debugMonitorEnter(threadLock);
2735         {
2736             node = findRunningThread(thread);
2737             if ((node == NULL) || (!node->isStarted)) {
2738                 JNIEnv *env;
2739 
2740                 env = getEnv();
2741                 error = addDeferredEventMode(env, mode, ei, thread);
2742             } else {
2743                 error = threadSetEventNotificationMode(node,
2744                         mode, ei, thread);
2745             }
2746         }
2747         debugMonitorExit(threadLock);
2748 
2749     }
2750     return error;
2751 }
2752 
2753 /*
2754  * Returns the current thread, if the thread has generated at least
2755  * one event, and has not generated a thread end event.
2756  */
2757 jthread
2758 threadControl_currentThread(void)
2759 {
2760     jthread thread;
2761 
2762     debugMonitorEnter(threadLock);
2763     {
2764         ThreadNode *node;
2765 
2766         node = findThread(&runningThreads, NULL);
2767         thread = (node == NULL) ? NULL : node->thread;
2768     }
2769     debugMonitorExit(threadLock);
2770 
2771     return thread;
2772 }
2773 
2774 jlong
2775 threadControl_getFrameGeneration(jthread thread)
2776 {
2777     jlong frameGeneration = -1;
2778 
2779     debugMonitorEnter(threadLock);
2780     {
2781         ThreadNode *node;
2782 
2783         node = findThread(NULL, thread);
2784 
2785         if (node != NULL) {
2786             frameGeneration = node->frameGeneration;
2787         }
2788     }
2789     debugMonitorExit(threadLock);
2790 
2791     return frameGeneration;
2792 }
2793 
2794 jthread *
2795 threadControl_allVThreads(jint *numVThreads)
2796 {
2797     JNIEnv *env;
2798     ThreadNode *node;
2799     jthread* vthreads;
2800 
2801     env = getEnv();
2802     debugMonitorEnter(threadLock);
2803 
2804     /* Count the number of vthreads */
2805     /* vthread fixme: we should keep a running total so no counting is needed. */
2806     *numVThreads = 0;
2807     for (node = runningVThreads.first; node != NULL; node = node->next) {
2808         (*numVThreads)++;
2809     }
2810 
2811     /* Allocate and fill in the vthreads array. */
2812     vthreads = jvmtiAllocate(*numVThreads * sizeof(jthread*));
2813     if (vthreads != NULL) {
2814         int i = 0;
2815         for (node = runningVThreads.first; node != NULL;  node = node->next) {
2816             vthreads[i++] = node->thread;
2817         }
2818     }
2819 
2820     debugMonitorExit(threadLock);
2821 
2822     return vthreads;
2823 }
2824 
2825 jboolean threadControl_isKnownVThread(jthread vthread) {
2826     ThreadNode *vthreadNode;
2827     debugMonitorEnter(threadLock);
2828     vthreadNode = findThread(&runningVThreads, vthread);
2829     debugMonitorExit(threadLock);
2830     return vthreadNode != NULL;
2831 }
2832 
2833 void
2834 threadControl_addVThread(jthread vthread)
2835 {
2836     ThreadNode *vthreadNode;
2837     debugMonitorEnter(threadLock);
2838     vthreadNode = insertThread(getEnv(), &runningVThreads, vthread);
2839     debugMonitorExit(threadLock);
2840 }
2841 
2842 /***** debugging *****/
2843 
2844 #ifdef DEBUG
2845 
2846 void
2847 threadControl_dumpAllThreads()
2848 {
2849     tty_message("Dumping runningThreads:");
2850     dumpThreadList(&runningThreads);
2851     tty_message("\nDumping runningVThreads:");
2852     dumpThreadList(&runningVThreads);
2853     tty_message("\nDumping otherThreads:");
2854     dumpThreadList(&otherThreads);
2855 }
2856 
2857 void
2858 threadControl_dumpThread(jthread thread)
2859 {
2860     ThreadNode* node = findThread(NULL, thread);
2861     if (node == NULL) {
2862         tty_message("Thread not found");
2863     } else {
2864         dumpThread(node);
2865     }
2866 }
2867 
2868 static void
2869 dumpThreadList(ThreadList *list)
2870 {
2871     ThreadNode *node;
2872     for (node = list->first; node != NULL; node = node->next) {
2873         if (!node->isDebugThread) {
2874             dumpThread(node);
2875         }
2876     }
2877 }
2878 
2879 static void
2880 dumpThread(ThreadNode *node) {
2881     tty_message("  Thread: node = %p, jthread = %p", node, node->thread);
2882 #ifdef DEBUG_THREADNAME
2883     tty_message("\tname: %s", node->name);
2884 #endif
2885     // More fields can be printed here when needed. The amount of output is intentionlly
2886     // kept small so it doesn't generate too much output.
2887     tty_message("\tsuspendCount: %d", node->suspendCount);
2888 }
2889 
2890 #endif /* DEBUG */