1 /*
   2  * Copyright (c) 1998, 2019, 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 FIBER_SCHEDULED event received. */
  73     unsigned int is_fiber : 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     jthread fiberHelperThread;  /* Temporary thread created for mounting fiber on to get stack trace
  87                                  * or to support suspending an unmounted fiber. */
  88     jboolean isTrackedSuspendedFiber; /* true if we are tracking the suspendCount of this fiber. */
  89     struct ThreadNode *nextTrackedSuspendedFiber;
  90     struct ThreadNode *prevTrackedSuspendedFiber;
  91     struct ThreadNode *next;
  92     struct ThreadNode *prev;
  93     jlong frameGeneration;    /* used to generate a unique frameID. Incremented whenever existing frameID
  94                                  needs to be invalidated, such as when the thread is resumed. */
  95     struct ThreadList *list;  /* Tells us what list this thread is in. */
  96 #ifdef DEBUG_THREADNAME
  97     char name[256];
  98 #endif
  99 } ThreadNode;
 100 
 101 static jint suspendAllCount;
 102 
 103 struct ThreadNode *trackedSuspendedFibers = NULL;
 104 
 105 typedef struct ThreadList {
 106     ThreadNode *first;
 107 } ThreadList;
 108 
 109 /*
 110  * popFrameEventLock is used to notify that the event has been received
 111  */
 112 static jrawMonitorID popFrameEventLock = NULL;
 113 
 114 /*
 115  * popFrameProceedLock is used to assure that the event thread is
 116  * re-suspended immediately after the event is acknowledged.
 117  */
 118 static jrawMonitorID popFrameProceedLock = NULL;
 119 
 120 static jrawMonitorID threadLock;
 121 static jlocation resumeLocation;
 122 static HandlerNode *breakpointHandlerNode;
 123 static HandlerNode *framePopHandlerNode;
 124 static HandlerNode *catchHandlerNode;
 125 
 126 static jvmtiError threadControl_removeDebugThread(jthread thread);
 127 
 128 /*
 129  * Threads which have issued thread start events and not yet issued thread
 130  * end events are maintained in the "runningThreads" list. All other threads known
 131  * to this module are kept in the "otherThreads" list.
 132  */
 133 static ThreadList runningThreads;
 134 static ThreadList otherThreads;
 135 static ThreadList runningFibers; /* Fibers we have seen. */
 136 
 137 #define MAX_DEBUG_THREADS 10
 138 static int debugThreadCount;
 139 static jthread debugThreads[MAX_DEBUG_THREADS];
 140 
 141 typedef struct DeferredEventMode {
 142     EventIndex ei;
 143     jvmtiEventMode mode;
 144     jthread thread;
 145     struct DeferredEventMode *next;
 146 } DeferredEventMode;
 147 
 148 typedef struct {
 149     DeferredEventMode *first;
 150     DeferredEventMode *last;
 151 } DeferredEventModeList;
 152 
 153 static DeferredEventModeList deferredEventModes;
 154 
 155 static jint
 156 getStackDepth(jthread thread)
 157 {
 158     jint count = 0;
 159     jvmtiError error;
 160 
 161     error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
 162                         (gdata->jvmti, thread, &count);
 163     if (error != JVMTI_ERROR_NONE) {
 164         EXIT_ERROR(error, "getting frame count");
 165     }
 166     return count;
 167 }
 168 
 169 /* Get the state of the thread direct from JVMTI */
 170 static jvmtiError
 171 threadState(jthread thread, jint *pstate)
 172 {
 173     *pstate = 0;
 174     return JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState)
 175                         (gdata->jvmti, thread, pstate);
 176 }
 177 
 178 /* Set TLS on a specific jthread to the ThreadNode* */
 179 static void
 180 setThreadLocalStorage(jthread thread, ThreadNode *node)
 181 {
 182     jvmtiError  error;
 183 
 184     error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage)
 185             (gdata->jvmti, thread, (void*)node);
 186     if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
 187         /* Just return, thread hasn't started yet */
 188         return;
 189     } else if ( error != JVMTI_ERROR_NONE ) {
 190         /* The jthread object must be valid, so this must be a fatal error */
 191         EXIT_ERROR(error, "cannot set thread local storage");
 192     }
 193 }
 194 
 195 /* Get TLS on a specific jthread, which is the ThreadNode* */
 196 static ThreadNode *
 197 getThreadLocalStorage(jthread thread)
 198 {
 199     jvmtiError  error;
 200     ThreadNode *node;
 201 
 202     node = NULL;
 203     error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadLocalStorage)
 204             (gdata->jvmti, thread, (void**)&node);
 205     if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
 206         /* Just return NULL, thread hasn't started yet */
 207         return NULL;
 208     } else if ( error != JVMTI_ERROR_NONE ) {
 209         /* The jthread object must be valid, so this must be a fatal error */
 210         EXIT_ERROR(error, "cannot get thread local storage");
 211     }
 212     return node;
 213 }
 214 
 215 /* Search list for nodes that don't have TLS set and match this thread.
 216  *   It assumed that this logic is never dealing with terminated threads,
 217  *   since the ThreadEnd events always delete the ThreadNode while the
 218  *   jthread is still alive.  So we can only look at the ThreadNode's that
 219  *   have never had their TLS set, making the search much faster.
 220  *   But keep in mind, this kind of search should rarely be needed.
 221  */
 222 static ThreadNode *
 223 nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
 224 {
 225     ThreadNode *node;
 226 
 227     for (node = list->first; node != NULL; node = node->next) {
 228         if (isSameObject(env, node->thread, thread)) {
 229             break;
 230         }
 231     }
 232     return node;
 233 }
 234 
 235 /*
 236  * These functions maintain the linked list of currently running threads and fibers.
 237  * All assume that the threadLock is held before calling.
 238  */
 239 
 240 
 241 /*
 242  * Search for a thread on the list. If list==NULL, search all lists.
 243  */
 244 static ThreadNode *
 245 findThread(ThreadList *list, jthread thread)
 246 {
 247     ThreadNode *node;
 248     JNIEnv *env = getEnv();
 249 
 250     if (list == NULL || list == &runningFibers) {
 251         /*
 252          * Search for a fiber.
 253          * fiber fixme: this needs to be done a lot faster. Maybe some sort of TLS for fibers is needed.
 254          * Otherwise we'll need something like a hashlist front end to the runningFibers list so
 255          * we can do quick lookups.
 256          */
 257         ThreadNode *node = nonTlsSearch(env, &runningFibers, thread);
 258         if (node != NULL || list == &runningFibers) {
 259             return node;
 260         }
 261     }    
 262 
 263     /* Get thread local storage for quick thread -> node access */
 264     node = getThreadLocalStorage(thread);
 265 
 266     /* In some rare cases we might get NULL, so we check the list manually for
 267      *   any threads that we could match.
 268      */
 269     if ( node == NULL ) {
 270         if ( list != NULL ) {
 271             node = nonTlsSearch(env, list, thread);
 272         } else {
 273             node = nonTlsSearch(env, &runningThreads, thread);
 274             if ( node == NULL ) {
 275                 node = nonTlsSearch(env, &otherThreads, thread);
 276             }
 277         }
 278         if ( node != NULL ) {
 279             /* Here we make another attempt to set TLS, it's ok if this fails */
 280             setThreadLocalStorage(thread, (void*)node);
 281         }
 282     }
 283 
 284     /* If a list is supplied, only return ones in this list */
 285     if ( node != NULL && list != NULL && node->list != list ) {
 286         return NULL;
 287     }
 288     return node;
 289 }
 290 
 291 /* Remove a ThreadNode from a ThreadList */
 292 static void
 293 removeNode(ThreadList *list, ThreadNode *node)
 294 {
 295     ThreadNode *prev;
 296     ThreadNode *next;
 297 
 298     prev = node->prev;
 299     next = node->next;
 300     if ( prev != NULL ) {
 301         prev->next = next;
 302     }
 303     if ( next != NULL ) {
 304         next->prev = prev;
 305     }
 306     if ( prev == NULL ) {
 307         list->first = next;
 308     }
 309     node->next = NULL;
 310     node->prev = NULL;
 311     node->list = NULL;
 312 }
 313 
 314 /* Add a ThreadNode to a ThreadList */
 315 static void
 316 addNode(ThreadList *list, ThreadNode *node)
 317 {
 318     node->next = NULL;
 319     node->prev = NULL;
 320     node->list = NULL;
 321     if ( list->first == NULL ) {
 322         list->first = node;
 323     } else {
 324         list->first->prev = node;
 325         node->next = list->first;
 326         list->first = node;
 327     }
 328     node->list = list;
 329 }
 330 
 331 static ThreadNode *
 332 insertThread(JNIEnv *env, ThreadList *list, jthread thread)
 333 {
 334     ThreadNode *node;
 335     struct bag *eventBag;
 336     jboolean is_fiber = (list == &runningFibers);
 337 
 338     node = findThread(list, thread);
 339     if (node == NULL) {
 340         node = jvmtiAllocate(sizeof(*node));
 341         if (node == NULL) {
 342             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 343             return NULL;
 344         }
 345         (void)memset(node, 0, sizeof(*node));
 346         eventBag = eventHelper_createEventBag();
 347         if (eventBag == NULL) {
 348             jvmtiDeallocate(node);
 349             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 350             return NULL;
 351         }
 352 
 353         /*
 354          * Init all flags false, all refs NULL, all counts 0
 355          */
 356 
 357         saveGlobalRef(env, thread, &(node->thread));
 358         if (node->thread == NULL) {
 359             jvmtiDeallocate(node);
 360             bagDestroyBag(eventBag);
 361             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 362             return NULL;
 363         }
 364         /*
 365          * Remember if it is a debug thread
 366          */
 367         if (!is_fiber && threadControl_isDebugThread(node->thread)) {
 368             node->isDebugThread = JNI_TRUE;
 369         } else if (suspendAllCount > 0){
 370             /*
 371              * If there is a pending suspendAll, all new threads should
 372              * be initialized as if they were suspended by the suspendAll,
 373              * and the thread will need to be suspended when it starts.
 374              */
 375             node->suspendCount = suspendAllCount;
 376             node->suspendOnStart = JNI_TRUE;
 377         }
 378         node->current_ei = 0;
 379         node->is_fiber = is_fiber;
 380         node->instructionStepMode = JVMTI_DISABLE;
 381         node->eventBag = eventBag;
 382         addNode(list, node);
 383 
 384         /* Set thread local storage for quick thread -> node access.
 385          *   Some threads may not be in a state that allows setting of TLS,
 386          *   which is ok, see findThread, it deals with threads without TLS set.
 387          */
 388         if (!is_fiber) {
 389             setThreadLocalStorage(node->thread, (void*)node);
 390         }
 391 
 392         if (is_fiber) {
 393             node->isStarted = JNI_TRUE; /* Fibers are considered started by default. */
 394         }
 395     }
 396 
 397     return node;
 398 }
 399 
 400 static void
 401 clearThread(JNIEnv *env, ThreadNode *node)
 402 {
 403     if (node->pendingStop != NULL) {
 404         tossGlobalRef(env, &(node->pendingStop));
 405     }
 406     stepControl_clearRequest(node->thread, &node->currentStep);
 407     if (node->isDebugThread) {
 408         (void)threadControl_removeDebugThread(node->thread);
 409     }
 410     /* Clear out TLS on this thread (just a cleanup action) */
 411     if (!node->is_fiber) {
 412         setThreadLocalStorage(node->thread, NULL);
 413     }
 414     tossGlobalRef(env, &(node->thread));
 415     bagDestroyBag(node->eventBag);
 416     jvmtiDeallocate(node);
 417 }
 418 
 419 static void
 420 removeThread(JNIEnv *env, ThreadList *list, jthread thread)
 421 {
 422     ThreadNode *node;
 423 
 424     node = findThread(list, thread);
 425     if (node != NULL) {
 426         removeNode(list, node);
 427         clearThread(env, node);
 428     }
 429 }
 430 
 431 static void
 432 removeResumed(JNIEnv *env, ThreadList *list)
 433 {
 434     ThreadNode *node;
 435 
 436     node = list->first;
 437     while (node != NULL) {
 438         ThreadNode *temp = node->next;
 439         if (node->suspendCount == 0) {
 440             removeThread(env, list, node->thread);
 441         }
 442         node = temp;
 443     }
 444 }
 445 
 446 static void
 447 moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node)
 448 {
 449     removeNode(source, node);
 450     JDI_ASSERT(findThread(dest, node->thread) == NULL);
 451     addNode(dest, node);
 452 }
 453 
 454 typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);
 455 
 456 static jvmtiError
 457 enumerateOverThreadList(JNIEnv *env, ThreadList *list,
 458                         ThreadEnumerateFunction function, void *arg)
 459 {
 460     ThreadNode *node;
 461     jvmtiError error = JVMTI_ERROR_NONE;
 462 
 463     for (node = list->first; node != NULL; node = node->next) {
 464         error = (*function)(env, node, arg);
 465         if ( error != JVMTI_ERROR_NONE ) {
 466             break;
 467         }
 468     }
 469     return error;
 470 }
 471 
 472 static void
 473 insertEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode)
 474 {
 475     if (list->last != NULL) {
 476         list->last->next = eventMode;
 477     } else {
 478         list->first = eventMode;
 479     }
 480     list->last = eventMode;
 481 }
 482 
 483 static void
 484 removeEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode, DeferredEventMode *prev)
 485 {
 486     if (prev == NULL) {
 487         list->first = eventMode->next;
 488     } else {
 489         prev->next = eventMode->next;
 490     }
 491     if (eventMode->next == NULL) {
 492         list->last = prev;
 493     }
 494 }
 495 
 496 static jvmtiError
 497 addDeferredEventMode(JNIEnv *env, jvmtiEventMode mode, EventIndex ei, jthread thread)
 498 {
 499     DeferredEventMode *eventMode;
 500 
 501     /*LINTED*/
 502     eventMode = jvmtiAllocate((jint)sizeof(DeferredEventMode));
 503     if (eventMode == NULL) {
 504         return AGENT_ERROR_OUT_OF_MEMORY;
 505     }
 506     eventMode->thread = NULL;
 507     saveGlobalRef(env, thread, &(eventMode->thread));
 508     eventMode->mode = mode;
 509     eventMode->ei = ei;
 510     eventMode->next = NULL;
 511     insertEventMode(&deferredEventModes, eventMode);
 512     return JVMTI_ERROR_NONE;
 513 }
 514 
 515 static void
 516 freeDeferredEventModes(JNIEnv *env)
 517 {
 518     DeferredEventMode *eventMode;
 519     eventMode = deferredEventModes.first;
 520     while (eventMode != NULL) {
 521         DeferredEventMode *next;
 522         next = eventMode->next;
 523         tossGlobalRef(env, &(eventMode->thread));
 524         jvmtiDeallocate(eventMode);
 525         eventMode = next;
 526     }
 527     deferredEventModes.first = NULL;
 528     deferredEventModes.last = NULL;
 529 }
 530 
 531 static jvmtiError
 532 threadSetEventNotificationMode(ThreadNode *node,
 533         jvmtiEventMode mode, EventIndex ei, jthread thread)
 534 {
 535     jvmtiError error;
 536 
 537     /* record single step mode */
 538     if (ei == EI_SINGLE_STEP) {
 539         node->instructionStepMode = mode;
 540     }
 541     error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
 542         (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
 543     return error;
 544 }
 545 
 546 static void
 547 processDeferredEventModes(JNIEnv *env, jthread thread, ThreadNode *node)
 548 {
 549     jvmtiError error;
 550     DeferredEventMode *eventMode;
 551     DeferredEventMode *prev;
 552 
 553     prev = NULL;
 554     eventMode = deferredEventModes.first;
 555     while (eventMode != NULL) {
 556         DeferredEventMode *next = eventMode->next;
 557         if (isSameObject(env, thread, eventMode->thread)) {
 558             error = threadSetEventNotificationMode(node,
 559                     eventMode->mode, eventMode->ei, eventMode->thread);
 560             if (error != JVMTI_ERROR_NONE) {
 561                 EXIT_ERROR(error, "cannot process deferred thread event notifications at thread start");
 562             }
 563             removeEventMode(&deferredEventModes, eventMode, prev);
 564             tossGlobalRef(env, &(eventMode->thread));
 565             jvmtiDeallocate(eventMode);
 566         } else {
 567             prev = eventMode;
 568         }
 569         eventMode = next;
 570     }
 571 }
 572 
 573 static void
 574 getLocks(void)
 575 {
 576     /*
 577      * Anything which might be locked as part of the handling of
 578      * a JVMTI event (which means: might be locked by an application
 579      * thread) needs to be grabbed here. This allows thread control
 580      * code to safely suspend and resume the application threads
 581      * while ensuring they don't hold a critical lock.
 582      */
 583 
 584     eventHandler_lock();
 585     invoker_lock();
 586     eventHelper_lock();
 587     stepControl_lock();
 588     commonRef_lock();
 589     debugMonitorEnter(threadLock);
 590 
 591 }
 592 
 593 static void
 594 releaseLocks(void)
 595 {
 596     debugMonitorExit(threadLock);
 597     commonRef_unlock();
 598     stepControl_unlock();
 599     eventHelper_unlock();
 600     invoker_unlock();
 601     eventHandler_unlock();
 602 }
 603 
 604 void
 605 threadControl_initialize(void)
 606 {
 607     jlocation unused;
 608     jvmtiError error;
 609 
 610     suspendAllCount = 0;
 611     runningThreads.first = NULL;
 612     otherThreads.first = NULL;
 613     runningFibers.first = NULL;
 614     debugThreadCount = 0;
 615     threadLock = debugMonitorCreate("JDWP Thread Lock");
 616     if (gdata->threadClass==NULL) {
 617         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class");
 618     }
 619     if (gdata->threadResume==0) {
 620         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread");
 621     }
 622     /* Get the java.lang.Thread.resume() method beginning location */
 623     error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
 624     if (error != JVMTI_ERROR_NONE) {
 625         EXIT_ERROR(error, "getting method location");
 626     }
 627 }
 628 
 629 static jthread
 630 getResumee(jthread resumingThread)
 631 {
 632     jthread resumee = NULL;
 633     jvmtiError error;
 634     jobject object;
 635     FrameNumber fnum = 0;
 636 
 637     error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
 638                     (gdata->jvmti, resumingThread, fnum, 0, &object);
 639     if (error == JVMTI_ERROR_NONE) {
 640         resumee = object;
 641     }
 642     return resumee;
 643 }
 644 
 645 
 646 static jboolean
 647 pendingAppResume(jboolean includeSuspended)
 648 {
 649     ThreadList *list;
 650     ThreadNode *node;
 651 
 652     list = &runningThreads;
 653     node = list->first;
 654     while (node != NULL) {
 655         if (node->resumeFrameDepth > 0) {
 656             if (includeSuspended) {
 657                 return JNI_TRUE;
 658             } else {
 659                 jvmtiError error;
 660                 jint       state;
 661 
 662                 error = threadState(node->thread, &state);
 663                 if (error != JVMTI_ERROR_NONE) {
 664                     EXIT_ERROR(error, "getting thread state");
 665                 }
 666                 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
 667                     return JNI_TRUE;
 668                 }
 669             }
 670         }
 671         node = node->next;
 672     }
 673     return JNI_FALSE;
 674 }
 675 
 676 static void
 677 notifyAppResumeComplete(void)
 678 {
 679     debugMonitorNotifyAll(threadLock);
 680     if (!pendingAppResume(JNI_TRUE)) {
 681         if (framePopHandlerNode != NULL) {
 682             (void)eventHandler_free(framePopHandlerNode);
 683             framePopHandlerNode = NULL;
 684         }
 685         if (catchHandlerNode != NULL) {
 686             (void)eventHandler_free(catchHandlerNode);
 687             catchHandlerNode = NULL;
 688         }
 689     }
 690 }
 691 
 692 static void
 693 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
 694                           HandlerNode *handlerNode,
 695                           struct bag *eventBag)
 696 {
 697     ThreadNode *node;
 698     jthread     thread;
 699 
 700     /* fiber fixme: it's unclear how this is used and if anything special needs to be done for fibers. */
 701     JDI_ASSERT(!evinfo->matchesFiber);
 702 
 703     thread = evinfo->thread;
 704 
 705     debugMonitorEnter(threadLock);
 706 
 707     node = findThread(&runningThreads, thread);
 708     if (node != NULL) {
 709         if (node->resumeFrameDepth > 0) {
 710             jint compareDepth = getStackDepth(thread);
 711             if (evinfo->ei == EI_FRAME_POP) {
 712                 compareDepth--;
 713             }
 714             if (compareDepth < node->resumeFrameDepth) {
 715                 node->resumeFrameDepth = 0;
 716                 notifyAppResumeComplete();
 717             }
 718         }
 719     }
 720 
 721     debugMonitorExit(threadLock);
 722 }
 723 
 724 static void
 725 blockOnDebuggerSuspend(jthread thread)
 726 {
 727     ThreadNode *node;
 728 
 729     node = findThread(NULL, thread);
 730     if (node != NULL) {
 731         while (node && node->suspendCount > 0) {
 732             debugMonitorWait(threadLock);
 733             node = findThread(NULL, thread);
 734         }
 735     }
 736 }
 737 
 738 static void
 739 trackAppResume(jthread thread)
 740 {
 741     jvmtiError  error;
 742     FrameNumber fnum;
 743     ThreadNode *node;
 744 
 745     fnum = 0;
 746     node = findThread(&runningThreads, thread);
 747     if (node != NULL) {
 748         JDI_ASSERT(node->resumeFrameDepth == 0);
 749         error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
 750                         (gdata->jvmti, thread, fnum);
 751         if (error == JVMTI_ERROR_NONE) {
 752             jint frameDepth = getStackDepth(thread);
 753             if ((frameDepth > 0) && (framePopHandlerNode == NULL)) {
 754                 framePopHandlerNode = eventHandler_createInternalThreadOnly(
 755                                            EI_FRAME_POP,
 756                                            handleAppResumeCompletion,
 757                                            thread);
 758                 catchHandlerNode = eventHandler_createInternalThreadOnly(
 759                                            EI_EXCEPTION_CATCH,
 760                                            handleAppResumeCompletion,
 761                                            thread);
 762                 if ((framePopHandlerNode == NULL) ||
 763                     (catchHandlerNode == NULL)) {
 764                     (void)eventHandler_free(framePopHandlerNode);
 765                     framePopHandlerNode = NULL;
 766                     (void)eventHandler_free(catchHandlerNode);
 767                     catchHandlerNode = NULL;
 768                 }
 769             }
 770             if ((framePopHandlerNode != NULL) &&
 771                 (catchHandlerNode != NULL) &&
 772                 (frameDepth > 0)) {
 773                 node->resumeFrameDepth = frameDepth;
 774             }
 775         }
 776     }
 777 }
 778 
 779 static void
 780 handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo,
 781                           HandlerNode *handlerNode,
 782                           struct bag *eventBag)
 783 {
 784     /* fiber fixme: it's unclear how this is used and if anything special needs to be done for fibers. */
 785     JDI_ASSERT(!evinfo->matchesFiber);
 786 
 787     jthread resumer = evinfo->thread;
 788     jthread resumee = getResumee(resumer);
 789 
 790     debugMonitorEnter(threadLock);
 791     if (resumee != NULL) {
 792         /*
 793          * Hold up any attempt to resume as long as the debugger
 794          * has suspended the resumee.
 795          */
 796         blockOnDebuggerSuspend(resumee);
 797     }
 798 
 799     if (resumer != NULL) {
 800         /*
 801          * Track the resuming thread by marking it as being within
 802          * a resume and by setting up for notification on
 803          * a frame pop or exception. We won't allow the debugger
 804          * to suspend threads while any thread is within a
 805          * call to resume. This (along with the block above)
 806          * ensures that when the debugger
 807          * suspends a thread it will remain suspended.
 808          */
 809         trackAppResume(resumer);
 810     }
 811 
 812     debugMonitorExit(threadLock);
 813 }
 814 
 815 void
 816 threadControl_onConnect(void)
 817 {
 818     breakpointHandlerNode = eventHandler_createInternalBreakpoint(
 819                  handleAppResumeBreakpoint, NULL,
 820                  gdata->threadClass, gdata->threadResume, resumeLocation);
 821 }
 822 
 823 void
 824 threadControl_onDisconnect(void)
 825 {
 826     if (breakpointHandlerNode != NULL) {
 827         (void)eventHandler_free(breakpointHandlerNode);
 828         breakpointHandlerNode = NULL;
 829     }
 830     if (framePopHandlerNode != NULL) {
 831         (void)eventHandler_free(framePopHandlerNode);
 832         framePopHandlerNode = NULL;
 833     }
 834     if (catchHandlerNode != NULL) {
 835         (void)eventHandler_free(catchHandlerNode);
 836         catchHandlerNode = NULL;
 837     }
 838 }
 839 
 840 void
 841 threadControl_onHook(void)
 842 {
 843     /*
 844      * As soon as the event hook is in place, we need to initialize
 845      * the thread list with already-existing threads. The threadLock
 846      * has been held since initialize, so we don't need to worry about
 847      * insertions or deletions from the event handlers while we do this
 848      */
 849     JNIEnv *env;
 850 
 851     env = getEnv();
 852 
 853     /*
 854      * Prevent any event processing until OnHook has been called
 855      */
 856     debugMonitorEnter(threadLock);
 857 
 858     WITH_LOCAL_REFS(env, 1) {
 859 
 860         jint threadCount;
 861         jthread *threads;
 862 
 863         threads = allThreads(&threadCount);
 864         if (threads == NULL) {
 865             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table");
 866         } else {
 867 
 868             int i;
 869 
 870             for (i = 0; i < threadCount; i++) {
 871                 ThreadNode *node;
 872                 jthread thread = threads[i];
 873                 node = insertThread(env, &runningThreads, thread);
 874 
 875                 /*
 876                  * This is a tiny bit risky. We have to assume that the
 877                  * pre-existing threads have been started because we
 878                  * can't rely on a thread start event for them. The chances
 879                  * of a problem related to this are pretty slim though, and
 880                  * there's really no choice because without setting this flag
 881                  * there is no way to enable stepping and other events on
 882                  * the threads that already exist (e.g. the finalizer thread).
 883                  */
 884                 node->isStarted = JNI_TRUE;
 885             }
 886         }
 887 
 888     } END_WITH_LOCAL_REFS(env)
 889 
 890     debugMonitorExit(threadLock);
 891 }
 892 
 893 
 894 static jvmtiError
 895 resumeFiberHelperThread(JNIEnv *env, ThreadNode *node, void *ignored)
 896 {
 897     jvmtiError error = JVMTI_ERROR_NONE;
 898     if (node->fiberHelperThread != NULL) {
 899         error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
 900             (gdata->jvmti, node->fiberHelperThread);
 901         tossGlobalRef(env, &node->fiberHelperThread);
 902     }
 903     return error;
 904 }
 905 
 906 static void
 907 startTrackingSuspendedFiber(ThreadNode *fiberNode)
 908 {
 909     /* Add fiberNode to the start of the list. */
 910     fiberNode->prevTrackedSuspendedFiber = NULL;
 911     fiberNode->nextTrackedSuspendedFiber = trackedSuspendedFibers;
 912     trackedSuspendedFibers = fiberNode;
 913 
 914     /* Since we didn't previously increment suspendCount for each suspendAll(), do that now. */
 915     fiberNode->suspendCount = suspendAllCount;
 916 
 917     fiberNode->isTrackedSuspendedFiber = JNI_TRUE;
 918 }
 919 
 920 
 921 static void
 922 stopTrackingSuspendedFiber(ThreadNode *fiberNode)
 923 {
 924     /* Remove fiberNode from the list. */
 925     if (fiberNode->prevTrackedSuspendedFiber == NULL) {
 926         /* Node is at the start of the list. */
 927         trackedSuspendedFibers = fiberNode->nextTrackedSuspendedFiber;
 928     } else {
 929         fiberNode->prevTrackedSuspendedFiber->nextTrackedSuspendedFiber =
 930             fiberNode->nextTrackedSuspendedFiber;
 931     }
 932     if (fiberNode->nextTrackedSuspendedFiber != NULL) {
 933         fiberNode->nextTrackedSuspendedFiber->prevTrackedSuspendedFiber =
 934             fiberNode->prevTrackedSuspendedFiber;
 935     }
 936 
 937     /* If this fiber has a helper thread, we no longer need or want it. */
 938     if (fiberNode->fiberHelperThread != NULL) {
 939         resumeFiberHelperThread(getEnv(), fiberNode, NULL);
 940     }
 941 
 942     fiberNode->isTrackedSuspendedFiber = JNI_FALSE;
 943 }
 944 
 945 static jthread
 946 getFiberHelperThread(jthread fiber)
 947 {
 948     JNIEnv *env;
 949     ThreadNode *fiberNode;
 950     jthread helperThread;
 951 
 952     fiberNode = findThread(&runningFibers, fiber);
 953     if (fiberNode->fiberHelperThread != NULL) {
 954         return fiberNode->fiberHelperThread;
 955     }
 956 
 957     env = getEnv();
 958 
 959     /*
 960      * We need to mount the fiber on a helper thread. This is done by calling
 961      * Fiber.tryMountAndSuspend(), which will create a helper thread for us,
 962      * mount the fiber on the thread, suspend the thread, and then return the thread.
 963      *
 964      * This helper thread is disposed of by resumeFiberHelperThread() when it is 
 965      * determined that the helper thread is no longer need (the fiber was resumed,
 966      * and we are no longer tracking it).
 967      *
 968      * Disable all event handling while doing this, since we don't want to deal
 969      * with any incoming THREAD_START event.
 970      *
 971      * Also release the threadLock, or a deadlock will occur when the 
 972      * CONTINUATION_RUN event arrives on the helper thread.
 973      * fiber fixme: this might not be safe to do.
 974      */
 975     debugMonitorExit(threadLock);    
 976     gdata->ignoreEvents = JNI_TRUE;
 977     helperThread = JNI_FUNC_PTR(env,CallObjectMethod)
 978         (env, fiber, gdata->fiberTryMountAndSuspend);
 979     gdata->ignoreEvents = JNI_FALSE;
 980     debugMonitorEnter(threadLock);
 981 
 982 
 983     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
 984         JNI_FUNC_PTR(env,ExceptionClear)(env);
 985         helperThread = NULL;
 986     }
 987 
 988     if (helperThread != NULL) {
 989         saveGlobalRef(env, helperThread, &(fiberNode->fiberHelperThread));
 990         /* Start tracking this fiber as a suspended one. */
 991         startTrackingSuspendedFiber(fiberNode);
 992     }
 993 
 994     return fiberNode->fiberHelperThread;
 995 }
 996 
 997 static jvmtiError
 998 commonSuspendByNode(ThreadNode *node)
 999 {
1000     jvmtiError error;
1001 
1002     LOG_MISC(("thread=%p suspended", node->thread));
1003     error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)
1004                 (gdata->jvmti, node->thread);
1005 
1006     /*
1007      * Mark for resume only if suspend succeeded
1008      */
1009     if (error == JVMTI_ERROR_NONE) {
1010         node->toBeResumed = JNI_TRUE;
1011     }
1012 
1013     /*
1014      * If the thread was suspended by another app thread,
1015      * do nothing and report no error (we won't resume it later).
1016      */
1017      if (error == JVMTI_ERROR_THREAD_SUSPENDED) {
1018         error = JVMTI_ERROR_NONE;
1019      }
1020 
1021      return error;
1022 }
1023 
1024 /*
1025  * Deferred suspends happen when the suspend is attempted on a thread
1026  * that is not started. Bookkeeping (suspendCount,etc.)
1027  * is handled by the original request, and once the thread actually
1028  * starts, an actual suspend is attempted. This function does the
1029  * deferred suspend without changing the bookkeeping that is already
1030  * in place.
1031  */
1032 static jint
1033 deferredSuspendThreadByNode(ThreadNode *node)
1034 {
1035     jvmtiError error;
1036 
1037     error = JVMTI_ERROR_NONE;
1038     if (node->isDebugThread) {
1039         /* Ignore requests for suspending debugger threads */
1040         return JVMTI_ERROR_NONE;
1041     }
1042 
1043     /*
1044      * Do the actual suspend only if a subsequent resume hasn't
1045      * made it irrelevant.
1046      */
1047     if (node->suspendCount > 0) {
1048         error = commonSuspendByNode(node);
1049 
1050         /*
1051          * Attempt to clean up from any error by decrementing the
1052          * suspend count. This compensates for the increment that
1053          * happens when suspendOnStart is set to true.
1054          */
1055         if (error != JVMTI_ERROR_NONE) {
1056           node->suspendCount--;
1057         }
1058     }
1059 
1060     node->suspendOnStart = JNI_FALSE;
1061 
1062     debugMonitorNotifyAll(threadLock);
1063 
1064     return error;
1065 }
1066 
1067 static jvmtiError
1068 suspendThreadByNode(ThreadNode *node)
1069 {
1070     jvmtiError error = JVMTI_ERROR_NONE;
1071     if (node->isDebugThread) {
1072         /* Ignore requests for suspending debugger threads */
1073         return JVMTI_ERROR_NONE;
1074     }
1075 
1076     /*
1077      * Just increment the suspend count if we are waiting
1078      * for a deferred suspend.
1079      */
1080     if (node->suspendOnStart) {
1081         node->suspendCount++;
1082         return JVMTI_ERROR_NONE;
1083     }
1084 
1085     if (node->suspendCount == 0) {
1086         error = commonSuspendByNode(node);
1087 
1088         if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1089             /*
1090              * This error means that the thread is either a zombie or not yet
1091              * started. In either case, we ignore the error. If the thread
1092              * is a zombie, suspend/resume are no-ops. If the thread is not
1093              * started, it will be suspended for real during the processing
1094              * of its thread start event.
1095              */
1096             node->suspendOnStart = JNI_TRUE;
1097             error = JVMTI_ERROR_NONE;
1098         }
1099     }
1100 
1101     if (error == JVMTI_ERROR_NONE) {
1102         node->suspendCount++;
1103         if (gdata->fibersSupported) {
1104             /*
1105              * If this is a carrier thread with a mounted fiber, and the fiber
1106              * is being tracked, bump the fiber's suspendCount also.
1107              */
1108             jthread fiber = getThreadFiber(node->thread);
1109             if (fiber != NULL) {
1110                 ThreadNode *fiberNode = findThread(&runningFibers, fiber);
1111                 if (fiberNode != NULL && fiberNode->isTrackedSuspendedFiber) {
1112                     /* If tracking, bump the fiber suspendCount also. */
1113                     fiberNode->suspendCount++;
1114                 }
1115             }
1116         }
1117     }
1118 
1119     debugMonitorNotifyAll(threadLock);
1120 
1121     return error;
1122 }
1123 
1124 static jvmtiError
1125 resumeThreadByNode(ThreadNode *node)
1126 {
1127     jvmtiError error = JVMTI_ERROR_NONE;
1128 
1129     if (node->isDebugThread) {
1130         /* never suspended by debugger => don't ever try to resume */
1131         return JVMTI_ERROR_NONE;
1132     }
1133     if (node->suspendCount > 0) {
1134         if (gdata->fibersSupported) {
1135             /*
1136              * If this is a carrier thread with a mounted fiber, and the fiber
1137              * is being tracked, decrement the fiber's suspendCount also.
1138              */
1139             jthread fiber = getThreadFiber(node->thread);
1140             if (fiber != NULL) {
1141                 ThreadNode *fiberNode = findThread(&runningFibers, fiber);
1142                 if (fiberNode != NULL && fiberNode->isTrackedSuspendedFiber) {
1143                     /* If tracking, decrement the fiber suspendCount also. */
1144                     if (fiberNode->suspendCount > 0) {
1145                         fiberNode->suspendCount--;
1146                     }
1147                 }
1148             }
1149         }
1150         node->suspendCount--;
1151         debugMonitorNotifyAll(threadLock);
1152         if ((node->suspendCount == 0) && node->toBeResumed &&
1153             !node->suspendOnStart) {
1154             LOG_MISC(("thread=%p resumed", node->thread));
1155             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
1156                         (gdata->jvmti, node->thread);
1157             node->frameGeneration++; /* Increment on each resume */
1158             node->toBeResumed = JNI_FALSE;
1159             if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
1160                 /*
1161                  * We successfully "suspended" this thread, but
1162                  * we never received a THREAD_START event for it.
1163                  * Since the thread never ran, we can ignore our
1164                  * failure to resume the thread.
1165                  */
1166                 error = JVMTI_ERROR_NONE;
1167             }
1168         }
1169     }
1170 
1171     return error;
1172 }
1173 
1174 /*
1175  * Functions which respond to user requests to suspend/resume
1176  * threads.
1177  * Suspends and resumes add and subtract from a count respectively.
1178  * The thread is only suspended when the count goes from 0 to 1 and
1179  * resumed only when the count goes from 1 to 0.
1180  *
1181  * These functions suspend and resume application threads
1182  * without changing the
1183  * state of threads that were already suspended beforehand.
1184  * They must not be called from an application thread because
1185  * that thread may be suspended somewhere in the  middle of things.
1186  */
1187 static void
1188 preSuspend(void)
1189 {
1190     getLocks();                     /* Avoid debugger deadlocks */
1191 
1192     /*
1193      * Delay any suspend while a call to java.lang.Thread.resume is in
1194      * progress (not including those in suspended threads). The wait is
1195      * timed because the threads suspended through
1196      * java.lang.Thread.suspend won't result in a notify even though
1197      * it may change the result of pendingAppResume()
1198      */
1199     while (pendingAppResume(JNI_FALSE)) {
1200         /*
1201          * This is ugly but we need to release the locks from getLocks
1202          * or else the notify will never happen. The locks must be
1203          * released and reacquired in the right order. else deadlocks
1204          * can happen. It is possible that, during this dance, the
1205          * notify will be missed, but since the wait needs to be timed
1206          * anyway, it won't be a disaster. Note that this code will
1207          * execute only on very rare occasions anyway.
1208          */
1209         releaseLocks();
1210 
1211         debugMonitorEnter(threadLock);
1212         debugMonitorTimedWait(threadLock, 1000);
1213         debugMonitorExit(threadLock);
1214 
1215         getLocks();
1216     }
1217 }
1218 
1219 static void
1220 postSuspend(void)
1221 {
1222     releaseLocks();
1223 }
1224 
1225 /*
1226  * This function must be called after preSuspend and before postSuspend.
1227  */
1228 static jvmtiError
1229 commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1230 {
1231     ThreadNode *node;
1232 
1233     if (isFiber(thread)) {
1234         jvmtiError error = JVMTI_ERROR_NONE;
1235         while (JNI_TRUE) {
1236             jthread carrier_thread = getFiberThread(thread);
1237             if (carrier_thread != NULL) {
1238                 /* Fiber is mounted. Suspend the carrier thread. */
1239                 node = findThread(&runningThreads, carrier_thread);
1240                 error = suspendThreadByNode(node);
1241                 if (error != JVMTI_ERROR_NONE) {
1242                     LOG_MISC(("commonSuspend: failed to suspend carrier thread(%p)", carrier_thread));
1243                     return error;
1244                 }
1245                 if (isSameObject(env, carrier_thread, getFiberThread(thread))) {
1246                     /* Successfully suspended and still mounted on same carrier thread. */
1247                     break;
1248                 }
1249                 /* Fiber moved to new carrier thread before it was suspended. Undo and retry. */
1250                 resumeThreadByNode(node);
1251                 LOG_MISC(("commonSuspend: fiber mounted on different carrier thread(%p)", carrier_thread));
1252             } else {
1253                 /* Fiber is not mounted. Get a suspended helper thread for it. */
1254                 ThreadNode *fiberNode = findThread(&runningFibers, thread);
1255                 if (getFiberHelperThread(thread) == NULL) {
1256                     /* fiber fixme: Sometimes the fiber is in a bad state and we can't create a
1257                      * helper thread for it. For now we just fail. */
1258                     LOG_MISC(("commonSuspend: failed to get fiber helper thread."));
1259                     return JVMTI_ERROR_INTERNAL;
1260                 }
1261                 fiberNode->suspendCount++;
1262                 break;
1263             }
1264         }
1265         return error;
1266     }
1267 
1268     /*
1269      * If the thread is not between its start and end events, we should
1270      * still suspend it. To keep track of things, add the thread
1271      * to a separate list of threads so that we'll resume it later.
1272      */
1273     node = findThread(&runningThreads, thread);
1274 #if 0
1275     tty_message("commonSuspend: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1276 #endif
1277     if (node == NULL) {
1278         node = insertThread(env, &otherThreads, thread);
1279     }
1280 
1281     if ( deferred ) {
1282         return deferredSuspendThreadByNode(node);
1283     } else {
1284         return suspendThreadByNode(node);
1285     }
1286 }
1287 
1288 
1289 static jvmtiError
1290 resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1291 {
1292     if (node->isDebugThread) {
1293         /* never suspended by debugger => don't ever try to resume */
1294         return JVMTI_ERROR_NONE;
1295     }
1296 
1297     if (node->suspendCount > 1) {
1298         node->suspendCount--;
1299         /* nested suspend so just undo one level */
1300         return JVMTI_ERROR_NONE;
1301     }
1302 
1303     /*
1304      * This thread was marked for suspension since its THREAD_START
1305      * event came in during a suspendAll, but the helper hasn't
1306      * completed the job yet. We decrement the count so the helper
1307      * won't suspend this thread after we are done with the resumeAll.
1308      * Another case to be handled here is when the debugger suspends
1309      * the thread while the app has it suspended. In this case,
1310      * the toBeResumed flag has been cleared indicating that
1311      * the thread should not be resumed when the debugger does a resume.
1312      * In this case, we also have to decrement the suspend count.
1313      * If we don't then when the app resumes the thread and our Thread.resume
1314      * bkpt handler is called, blockOnDebuggerSuspend will not resume
1315      * the thread because suspendCount will be 1 meaning that the
1316      * debugger has the thread suspended.  See bug 6224859.
1317      */
1318     if (node->suspendCount == 1 && (!node->toBeResumed || node->suspendOnStart)) {
1319         node->suspendCount--;
1320         return JVMTI_ERROR_NONE;
1321     }
1322 
1323     if (arg == NULL) {
1324         /* nothing to hard resume so we're done */
1325         return JVMTI_ERROR_NONE;
1326     }
1327 
1328     /*
1329      * This is tricky. A suspendCount of 1 and toBeResumed means that
1330      * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1331      * on this thread. The check for !suspendOnStart is paranoia that
1332      * we inherited from resumeThreadByNode().
1333      */
1334     if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1335         jthread **listPtr = (jthread **)arg;
1336 
1337         **listPtr = node->thread;
1338         (*listPtr)++;
1339     }
1340     return JVMTI_ERROR_NONE;
1341 }
1342 
1343 
1344 static jvmtiError
1345 resumeCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1346 {
1347     if (node->isDebugThread) {
1348         /* never suspended by debugger => don't ever try to resume */
1349         return JVMTI_ERROR_NONE;
1350     }
1351 
1352     /*
1353      * This is tricky. A suspendCount of 1 and toBeResumed means that
1354      * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1355      * on this thread. The check for !suspendOnStart is paranoia that
1356      * we inherited from resumeThreadByNode().
1357      */
1358     if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1359         jint *counter = (jint *)arg;
1360 
1361         (*counter)++;
1362     }
1363     return JVMTI_ERROR_NONE;
1364 }
1365 
1366 static void *
1367 newArray(jint length, size_t nbytes)
1368 {
1369     void *ptr;
1370     ptr = jvmtiAllocate(length*(jint)nbytes);
1371     if ( ptr != NULL ) {
1372         (void)memset(ptr, 0, length*nbytes);
1373     }
1374     return ptr;
1375 }
1376 
1377 static void
1378 deleteArray(void *ptr)
1379 {
1380     jvmtiDeallocate(ptr);
1381 }
1382 
1383 /*
1384  * This function must be called with the threadLock held.
1385  *
1386  * Two facts conspire to make this routine complicated:
1387  *
1388  * 1) the VM doesn't support nested external suspend
1389  * 2) the original resumeAll code structure doesn't retrieve the
1390  *    entire thread list from JVMTI so we use the runningThreads
1391  *    list and two helpers to get the job done.
1392  *
1393  * Because we hold the threadLock, state seen by resumeCountHelper()
1394  * is the same state seen in resumeCopyHelper(). resumeCountHelper()
1395  * just counts up the number of threads to be hard resumed.
1396  * resumeCopyHelper() does the accounting for nested suspends and
1397  * special cases and, finally, populates the list of hard resume
1398  * threads to be passed to ResumeThreadList().
1399  *
1400  * At first glance, you might think that the accounting could be done
1401  * in resumeCountHelper(), but then resumeCopyHelper() would see
1402  * "post-resume" state in the accounting values (suspendCount and
1403  * toBeResumed) and would not be able to distinguish between a thread
1404  * that needs a hard resume versus a thread that is already running.
1405  */
1406 static jvmtiError
1407 commonResumeList(JNIEnv *env)
1408 {
1409     jvmtiError   error;
1410     jint         i;
1411     jint         reqCnt;
1412     jthread     *reqList;
1413     jthread     *reqPtr;
1414     jvmtiError  *results;
1415 
1416     reqCnt = 0;
1417 
1418     /* count number of threads to hard resume */
1419     (void) enumerateOverThreadList(env, &runningThreads, resumeCountHelper,
1420                                    &reqCnt);
1421     if (reqCnt == 0) {
1422         /* nothing to hard resume so do just the accounting part */
1423         (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1424                                        NULL);
1425         return JVMTI_ERROR_NONE;
1426     }
1427 
1428     /*LINTED*/
1429     reqList = newArray(reqCnt, sizeof(jthread));
1430     if (reqList == NULL) {
1431         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume request list");
1432     }
1433     /*LINTED*/
1434     results = newArray(reqCnt, sizeof(jvmtiError));
1435     if (results == NULL) {
1436         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume list");
1437     }
1438 
1439     /* copy the jthread values for threads to hard resume */
1440     reqPtr = reqList;
1441     (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1442                                    &reqPtr);
1443 
1444     error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThreadList)
1445                 (gdata->jvmti, reqCnt, reqList, results);
1446     for (i = 0; i < reqCnt; i++) {
1447         ThreadNode *node;
1448 
1449         node = findThread(&runningThreads, reqList[i]);
1450         if (node == NULL) {
1451             EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in running thread table");
1452         }
1453         LOG_MISC(("thread=%p resumed as part of list", node->thread));
1454 
1455         /*
1456          * resumeThreadByNode() assumes that JVM/DI ResumeThread()
1457          * always works and does all the accounting updates. We do
1458          * the same here. We also don't clear the error.
1459          */
1460         node->suspendCount--;
1461         node->toBeResumed = JNI_FALSE;
1462         node->frameGeneration++; /* Increment on each resume */
1463     }
1464     deleteArray(results);
1465     deleteArray(reqList);
1466 
1467     debugMonitorNotifyAll(threadLock);
1468 
1469     return error;
1470 }
1471 
1472 
1473 /*
1474  * This function must be called after preSuspend and before postSuspend.
1475  */
1476 static jvmtiError
1477 commonSuspendList(JNIEnv *env, jint initCount, jthread *initList)
1478 {
1479     jvmtiError  error;
1480     jint        i;
1481     jint        reqCnt;
1482     jthread    *reqList;
1483 
1484     error   = JVMTI_ERROR_NONE;
1485     reqCnt  = 0;
1486     reqList = newArray(initCount, sizeof(jthread));
1487     if (reqList == NULL) {
1488         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"request list");
1489     }
1490 
1491     /*
1492      * Go through the initial list and see if we have anything to suspend.
1493      */
1494     for (i = 0; i < initCount; i++) {
1495         ThreadNode *node;
1496 
1497         /*
1498          * If the thread is not between its start and end events, we should
1499          * still suspend it. To keep track of things, add the thread
1500          * to a separate list of threads so that we'll resume it later.
1501          */
1502         node = findThread(&runningThreads, initList[i]);
1503         if (node == NULL) {
1504             node = insertThread(env, &otherThreads, initList[i]);
1505         }
1506 
1507         if (node->isDebugThread) {
1508             /* Ignore requests for suspending debugger threads */
1509             continue;
1510         }
1511 
1512         /*
1513          * Just increment the suspend count if we are waiting
1514          * for a deferred suspend or if this is a nested suspend.
1515          */
1516         if (node->suspendOnStart || node->suspendCount > 0) {
1517             node->suspendCount++;
1518             continue;
1519         }
1520 
1521         if (node->suspendCount == 0) {
1522             /* thread is not suspended yet so put it on the request list */
1523             reqList[reqCnt++] = initList[i];
1524         }
1525     }
1526 
1527     if (reqCnt > 0) {
1528         jvmtiError *results = newArray(reqCnt, sizeof(jvmtiError));
1529 
1530         if (results == NULL) {
1531             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"suspend list results");
1532         }
1533 
1534         /*
1535          * We have something to suspend so try to do it.
1536          */
1537         error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThreadList)
1538                         (gdata->jvmti, reqCnt, reqList, results);
1539         for (i = 0; i < reqCnt; i++) {
1540             ThreadNode *node;
1541 
1542             node = findThread(NULL, reqList[i]);
1543             if (node == NULL) {
1544                 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in thread tables");
1545             }
1546             LOG_MISC(("thread=%p suspended as part of list", node->thread));
1547 
1548             if (results[i] == JVMTI_ERROR_NONE) {
1549                 /* thread was suspended as requested */
1550                 node->toBeResumed = JNI_TRUE;
1551             } else if (results[i] == JVMTI_ERROR_THREAD_SUSPENDED) {
1552                 /*
1553                  * If the thread was suspended by another app thread,
1554                  * do nothing and report no error (we won't resume it later).
1555                  */
1556                 results[i] = JVMTI_ERROR_NONE;
1557             } else if (results[i] == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1558                 /*
1559                  * This error means that the suspend request failed
1560                  * because the thread is either a zombie or not yet
1561                  * started. In either case, we ignore the error. If the
1562                  * thread is a zombie, suspend/resume are no-ops. If the
1563                  * thread is not started, it will be suspended for real
1564                  * during the processing of its thread start event.
1565                  */
1566                 node->suspendOnStart = JNI_TRUE;
1567                 results[i] = JVMTI_ERROR_NONE;
1568             }
1569 
1570             /* count real, app and deferred (suspendOnStart) suspensions */
1571             if (results[i] == JVMTI_ERROR_NONE) {
1572                 node->suspendCount++;
1573             }
1574         }
1575         deleteArray(results);
1576     }
1577     deleteArray(reqList);
1578 
1579     debugMonitorNotifyAll(threadLock);
1580 
1581     return error;
1582 }
1583 
1584 static jvmtiError
1585 commonResume(jthread thread)
1586 {
1587     jvmtiError  error;
1588     ThreadNode *node;
1589 
1590     if (isFiber(thread)) {
1591         jthread carrier_thread = getFiberThread(thread);
1592         ThreadNode *fiberNode = findThread(&runningFibers, thread);
1593         if (carrier_thread == NULL) {
1594             /*
1595              * Fiber is not mounted on a carrier thread. We may already be tracking this fiber as a
1596              * suspended fiber at this point. We would not be if a suspendAll was done, and there was
1597              * no suspend of just this fiber. If we are not tracking it, then we need to.
1598              */
1599             if (fiberNode->isTrackedSuspendedFiber) {
1600                 if (fiberNode->suspendCount > 0) {
1601                     fiberNode->suspendCount--;
1602                     /*
1603                      * Note, if suspendCount == 0 but suspendAllCount does not, eventually
1604                      * threadControl_resumeAll() will be responsible for calling
1605                      * stopTrackingSuspendedFiber()
1606                      */
1607                     if (fiberNode->suspendCount == 0 && suspendAllCount == 0) {
1608                         stopTrackingSuspendedFiber(fiberNode);
1609                     }
1610                 }
1611             } else {
1612                 if (suspendAllCount > 0) {
1613                     startTrackingSuspendedFiber(fiberNode);
1614                     fiberNode->suspendCount--;
1615                 }
1616             }
1617             return JVMTI_ERROR_NONE;
1618         } else {
1619             /*
1620              * This is a mounted fiber. If the fiber is being tracked, and the suspendCount
1621              * of the carrier thread is 0, then decrement the fiber's suspendCount here
1622              * since it cannot be done by resumeThreadByNode because we'll have no way to
1623              * get the fiber if the carrier thread is not suspended (getThreadFiber() will
1624              * produce a fatal error).
1625              */
1626             if (fiberNode->isTrackedSuspendedFiber) {
1627                 if (fiberNode->suspendCount > 0) {
1628                     ThreadNode *threadNode = findThread(NULL, thread);
1629                     if (threadNode->suspendCount == 0) {
1630                         fiberNode->suspendCount--;
1631                     }
1632                 }
1633             }
1634             /* Fiber is mounted on a carrier thread. Fall through to code below to resume
1635              * the carrier thread. */
1636             thread = carrier_thread;
1637         }
1638     }
1639 
1640     /*
1641      * The thread is normally between its start and end events, but if
1642      * not, check the auxiliary list used by threadControl_suspendThread.
1643      */
1644     node = findThread(NULL, thread);
1645 #if 0
1646     tty_message("commonResume: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1647 #endif
1648 
1649     /*
1650      * If the node is in neither list, the debugger never suspended
1651      * this thread, so do nothing.
1652      */
1653     error = JVMTI_ERROR_NONE;
1654     if (node != NULL) {
1655         error = resumeThreadByNode(node);
1656     }
1657 
1658     return error;
1659 }
1660 
1661 
1662 jvmtiError
1663 threadControl_suspendThread(jthread thread, jboolean deferred)
1664 {
1665     jvmtiError error;
1666     JNIEnv    *env;
1667 
1668     env = getEnv();
1669 
1670     log_debugee_location("threadControl_suspendThread()", thread, NULL, 0);
1671 
1672     preSuspend();
1673     error = commonSuspend(env, thread, deferred);
1674     postSuspend();
1675 
1676     return error;
1677 }
1678 
1679 jvmtiError
1680 threadControl_resumeThread(jthread thread, jboolean do_unblock)
1681 {
1682     jvmtiError error;
1683     JNIEnv    *env;
1684 
1685     env = getEnv();
1686 
1687     log_debugee_location("threadControl_resumeThread()", thread, NULL, 0);
1688 
1689     eventHandler_lock(); /* for proper lock order */
1690     debugMonitorEnter(threadLock);
1691     error = commonResume(thread);
1692     removeResumed(env, &otherThreads);
1693     debugMonitorExit(threadLock);
1694     eventHandler_unlock();
1695 
1696     if (do_unblock) {
1697         /* let eventHelper.c: commandLoop() know we resumed one thread */
1698         unblockCommandLoop();
1699     }
1700 
1701     return error;
1702 }
1703 
1704 jvmtiError
1705 threadControl_suspendCount(jthread thread, jint *count)
1706 {
1707     jvmtiError  error;
1708     ThreadNode *node;
1709     jboolean is_fiber = isFiber(thread);
1710 
1711     debugMonitorEnter(threadLock);
1712 
1713     if (is_fiber) {
1714         node = findThread(&runningFibers, thread);
1715     } else {
1716         node = findThread(&runningThreads, thread);
1717         if (node == NULL) {
1718             node = findThread(&otherThreads, thread);
1719         }
1720     }
1721 
1722     error = JVMTI_ERROR_NONE;
1723     if (node != NULL) {
1724         if (!is_fiber) {
1725             *count = node->suspendCount;
1726         } else {
1727             jthread carrier_thread = getFiberThread(thread);
1728             if (carrier_thread == NULL) {
1729                 if (node->isTrackedSuspendedFiber) {
1730                     /* Already tracking this fiber, so fiber node owns its suspendCount. */
1731                     *count = node->suspendCount;
1732                 } else {
1733                     /* Not tacking this fiber yet, so use suspendAllCount. */
1734                     *count = suspendAllCount;
1735                 }
1736             } else {
1737                 /* It's a mounted fiber, so the carrier thread tracks the suspend count. */
1738                 node = findThread(&runningThreads, carrier_thread);
1739                 JDI_ASSERT(node != NULL);
1740                 *count = node->suspendCount;
1741             }
1742         }
1743     } else {
1744         /*
1745          * If the node is in neither list, the debugger never suspended
1746          * this thread, so the suspend count is 0.
1747          */
1748         *count = 0;
1749     }
1750 
1751     debugMonitorExit(threadLock);
1752 
1753     return error;
1754 }
1755 
1756 static jboolean
1757 contains(JNIEnv *env, jthread *list, jint count, jthread item)
1758 {
1759     int i;
1760 
1761     for (i = 0; i < count; i++) {
1762         if (isSameObject(env, list[i], item)) {
1763             return JNI_TRUE;
1764         }
1765     }
1766     return JNI_FALSE;
1767 }
1768 
1769 
1770 typedef struct {
1771     jthread *list;
1772     jint count;
1773 } SuspendAllArg;
1774 
1775 static jvmtiError
1776 suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1777 {
1778     SuspendAllArg *saArg = (SuspendAllArg *)arg;
1779     jvmtiError error = JVMTI_ERROR_NONE;
1780     jthread *list = saArg->list;
1781     jint count = saArg->count;
1782     if (!contains(env, list, count, node->thread)) {
1783         error = commonSuspend(env, node->thread, JNI_FALSE);
1784     }
1785     return error;
1786 }
1787 
1788 jvmtiError
1789 threadControl_suspendAll(void)
1790 {
1791     jvmtiError error;
1792     JNIEnv    *env;
1793 #if 0
1794     tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount);
1795 #endif
1796 
1797     env = getEnv();
1798 
1799     log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0);
1800 
1801     preSuspend();
1802 
1803     /*
1804      * Get a list of all threads and suspend them.
1805      */
1806     WITH_LOCAL_REFS(env, 1) {
1807 
1808         jthread *threads;
1809         jint count;
1810 
1811         threads = allThreads(&count);
1812         if (threads == NULL) {
1813             error = AGENT_ERROR_OUT_OF_MEMORY;
1814             goto err;
1815         }
1816         if (canSuspendResumeThreadLists()) {
1817             error = commonSuspendList(env, count, threads);
1818             if (error != JVMTI_ERROR_NONE) {
1819                 goto err;
1820             }
1821         } else {
1822             int i;
1823             for (i = 0; i < count; i++) {
1824                 error = commonSuspend(env, threads[i], JNI_FALSE);
1825 
1826                 if (error != JVMTI_ERROR_NONE) {
1827                     goto err;
1828                 }
1829             }
1830         }
1831 
1832         /*
1833          * Update the suspend count of any threads not yet (or no longer)
1834          * in the thread list above.
1835          */
1836         {
1837             SuspendAllArg arg;
1838             arg.list = threads;
1839             arg.count = count;
1840             error = enumerateOverThreadList(env, &otherThreads,
1841                                             suspendAllHelper, &arg);
1842         }
1843 
1844         /*
1845          * Update the suspend count of any fiber that was explicitly suspended
1846          * and had a helper thread created for that purpose. These are known
1847          * as "tracked" suspended fibers.
1848          */
1849         debugMonitorEnter(threadLock);
1850         {
1851             ThreadNode *trackedSuspendedFiber = trackedSuspendedFibers;
1852             while (trackedSuspendedFiber != NULL) {
1853                 trackedSuspendedFiber->suspendCount++;
1854                 trackedSuspendedFiber = trackedSuspendedFiber->nextTrackedSuspendedFiber;
1855             }
1856         }
1857         debugMonitorExit(threadLock);
1858 
1859         if (error == JVMTI_ERROR_NONE) {
1860             suspendAllCount++;
1861         }
1862 
1863     err: ;
1864 
1865     } END_WITH_LOCAL_REFS(env)
1866 
1867     postSuspend();
1868 
1869     return error;
1870 }
1871 
1872 static jvmtiError
1873 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1874 {
1875     /*
1876      * Since this helper is called with the threadLock held, we
1877      * don't need to recheck to see if the node is still on one
1878      * of the two thread lists.
1879      */
1880     return resumeThreadByNode(node);
1881 }
1882 
1883 jvmtiError
1884 threadControl_resumeAll(void)
1885 {
1886     jvmtiError error;
1887     JNIEnv    *env;
1888 #if 0
1889     tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount);
1890 #endif
1891 
1892     env = getEnv();
1893 
1894     log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1895 
1896     eventHandler_lock(); /* for proper lock order */
1897     debugMonitorEnter(threadLock);
1898 
1899     /*
1900      * Resume only those threads that the debugger has suspended. All
1901      * such threads must have a node in one of the thread lists, so there's
1902      * no need to get the whole thread list from JVMTI (unlike
1903      * suspendAll).
1904      */
1905     if (canSuspendResumeThreadLists()) {
1906         error = commonResumeList(env);
1907     } else {
1908         error = enumerateOverThreadList(env, &runningThreads,
1909                                         resumeHelper, NULL);
1910     }
1911     if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1912         error = enumerateOverThreadList(env, &otherThreads,
1913                                         resumeHelper, NULL);
1914         removeResumed(env, &otherThreads);
1915     }
1916 
1917     if (suspendAllCount > 0) {
1918         suspendAllCount--;
1919     }
1920 
1921     /*
1922      * Update the suspend count of any fiber that is being tracked. If it is being
1923      * tracked, that means that either it was explicitly suspended and had a helper
1924      * thread created for helping to suspend it, or it had helper thread created for
1925      * the purpose of getting its stack. If the count reaches zero, then stop tracking the fiber.
1926      */
1927     {
1928         ThreadNode *trackedSuspendedFiber = trackedSuspendedFibers;
1929         while (trackedSuspendedFiber != NULL) {
1930             ThreadNode *fiberNode = trackedSuspendedFiber;
1931             trackedSuspendedFiber = trackedSuspendedFiber->nextTrackedSuspendedFiber;
1932             if (fiberNode->suspendCount > 0) {
1933                 fiberNode->suspendCount--;
1934             }
1935             if (fiberNode->suspendCount == 0 && suspendAllCount == 0) {
1936                 stopTrackingSuspendedFiber(fiberNode);
1937             }
1938         }
1939     }
1940 
1941     debugMonitorExit(threadLock);
1942     eventHandler_unlock();
1943     /* let eventHelper.c: commandLoop() know we are resuming */
1944     unblockCommandLoop();
1945 
1946     return error;
1947 }
1948 
1949 
1950 StepRequest *
1951 threadControl_getStepRequest(jthread thread)
1952 {
1953     ThreadNode  *node;
1954     StepRequest *step;
1955 
1956     step = NULL;
1957 
1958     debugMonitorEnter(threadLock);
1959 
1960     node = findThread(&runningThreads, thread);
1961     if (node != NULL) {
1962         step = &node->currentStep;
1963     }
1964 
1965     debugMonitorExit(threadLock);
1966 
1967     return step;
1968 }
1969 
1970 InvokeRequest *
1971 threadControl_getInvokeRequest(jthread thread)
1972 {
1973     ThreadNode    *node;
1974     InvokeRequest *request;
1975 
1976     request = NULL;
1977 
1978     debugMonitorEnter(threadLock);
1979 
1980     node = findThread(&runningThreads, thread);
1981     if (node != NULL) {
1982          request = &node->currentInvoke;
1983     }
1984 
1985     debugMonitorExit(threadLock);
1986 
1987     return request;
1988 }
1989 
1990 jvmtiError
1991 threadControl_addDebugThread(jthread thread)
1992 {
1993     jvmtiError error;
1994 
1995     debugMonitorEnter(threadLock);
1996     if (debugThreadCount >= MAX_DEBUG_THREADS) {
1997         error = AGENT_ERROR_OUT_OF_MEMORY;
1998     } else {
1999         JNIEnv    *env;
2000 
2001         env = getEnv();
2002         debugThreads[debugThreadCount] = NULL;
2003         saveGlobalRef(env, thread, &(debugThreads[debugThreadCount]));
2004         if (debugThreads[debugThreadCount] == NULL) {
2005             error = AGENT_ERROR_OUT_OF_MEMORY;
2006         } else {
2007             debugThreadCount++;
2008             error = JVMTI_ERROR_NONE;
2009         }
2010     }
2011     debugMonitorExit(threadLock);
2012     return error;
2013 }
2014 
2015 static jvmtiError
2016 threadControl_removeDebugThread(jthread thread)
2017 {
2018     jvmtiError error;
2019     JNIEnv    *env;
2020     int        i;
2021 
2022     error = AGENT_ERROR_INVALID_THREAD;
2023     env   = getEnv();
2024 
2025     debugMonitorEnter(threadLock);
2026     for (i = 0; i< debugThreadCount; i++) {
2027         if (isSameObject(env, thread, debugThreads[i])) {
2028             int j;
2029 
2030             tossGlobalRef(env, &(debugThreads[i]));
2031             for (j = i+1; j < debugThreadCount; j++) {
2032                 debugThreads[j-1] = debugThreads[j];
2033             }
2034             debugThreadCount--;
2035             error = JVMTI_ERROR_NONE;
2036             break;
2037         }
2038     }
2039     debugMonitorExit(threadLock);
2040     return error;
2041 }
2042 
2043 jboolean
2044 threadControl_isDebugThread(jthread thread)
2045 {
2046     int      i;
2047     jboolean rc;
2048     JNIEnv  *env;
2049 
2050     rc  = JNI_FALSE;
2051     env = getEnv();
2052 
2053     debugMonitorEnter(threadLock);
2054     for (i = 0; i < debugThreadCount; i++) {
2055         if (isSameObject(env, thread, debugThreads[i])) {
2056             rc = JNI_TRUE;
2057             break;
2058         }
2059     }
2060     debugMonitorExit(threadLock);
2061     return rc;
2062 }
2063 
2064 static void
2065 initLocks(void)
2066 {
2067     if (popFrameEventLock == NULL) {
2068         popFrameEventLock = debugMonitorCreate("JDWP PopFrame Event Lock");
2069         popFrameProceedLock = debugMonitorCreate("JDWP PopFrame Proceed Lock");
2070     }
2071 }
2072 
2073 static jboolean
2074 getPopFrameThread(jthread thread)
2075 {
2076     jboolean popFrameThread;
2077 
2078     debugMonitorEnter(threadLock);
2079     {
2080         ThreadNode *node;
2081 
2082         node = findThread(NULL, thread);
2083         if (node == NULL) {
2084             popFrameThread = JNI_FALSE;
2085         } else {
2086             popFrameThread = node->popFrameThread;
2087         }
2088     }
2089     debugMonitorExit(threadLock);
2090 
2091     return popFrameThread;
2092 }
2093 
2094 static void
2095 setPopFrameThread(jthread thread, jboolean value)
2096 {
2097     debugMonitorEnter(threadLock);
2098     {
2099         ThreadNode *node;
2100 
2101         node = findThread(NULL, thread);
2102         if (node == NULL) {
2103             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2104         } else {
2105             node->popFrameThread = value;
2106         }
2107     }
2108     debugMonitorExit(threadLock);
2109 }
2110 
2111 static jboolean
2112 getPopFrameEvent(jthread thread)
2113 {
2114     jboolean popFrameEvent;
2115 
2116     debugMonitorEnter(threadLock);
2117     {
2118         ThreadNode *node;
2119 
2120         node = findThread(NULL, thread);
2121         if (node == NULL) {
2122             popFrameEvent = JNI_FALSE;
2123             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2124         } else {
2125             popFrameEvent = node->popFrameEvent;
2126         }
2127     }
2128     debugMonitorExit(threadLock);
2129 
2130     return popFrameEvent;
2131 }
2132 
2133 static void
2134 setPopFrameEvent(jthread thread, jboolean value)
2135 {
2136     debugMonitorEnter(threadLock);
2137     {
2138         ThreadNode *node;
2139 
2140         node = findThread(NULL, thread);
2141         if (node == NULL) {
2142             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2143         } else {
2144             node->popFrameEvent = value;
2145             node->frameGeneration++; /* Increment on each resume */
2146         }
2147     }
2148     debugMonitorExit(threadLock);
2149 }
2150 
2151 static jboolean
2152 getPopFrameProceed(jthread thread)
2153 {
2154     jboolean popFrameProceed;
2155 
2156     debugMonitorEnter(threadLock);
2157     {
2158         ThreadNode *node;
2159 
2160         node = findThread(NULL, thread);
2161         if (node == NULL) {
2162             popFrameProceed = JNI_FALSE;
2163             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2164         } else {
2165             popFrameProceed = node->popFrameProceed;
2166         }
2167     }
2168     debugMonitorExit(threadLock);
2169 
2170     return popFrameProceed;
2171 }
2172 
2173 static void
2174 setPopFrameProceed(jthread thread, jboolean value)
2175 {
2176     debugMonitorEnter(threadLock);
2177     {
2178         ThreadNode *node;
2179 
2180         node = findThread(NULL, thread);
2181         if (node == NULL) {
2182             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table");
2183         } else {
2184             node->popFrameProceed = value;
2185         }
2186     }
2187     debugMonitorExit(threadLock);
2188 }
2189 
2190 /**
2191  * Special event handler for events on the popped thread
2192  * that occur during the pop operation.
2193  */
2194 static void
2195 popFrameCompleteEvent(jthread thread)
2196 {
2197       debugMonitorEnter(popFrameProceedLock);
2198       {
2199           /* notify that we got the event */
2200           debugMonitorEnter(popFrameEventLock);
2201           {
2202               setPopFrameEvent(thread, JNI_TRUE);
2203               debugMonitorNotify(popFrameEventLock);
2204           }
2205           debugMonitorExit(popFrameEventLock);
2206 
2207           /* make sure we get suspended again */
2208           setPopFrameProceed(thread, JNI_FALSE);
2209           while (getPopFrameProceed(thread) == JNI_FALSE) {
2210               debugMonitorWait(popFrameProceedLock);
2211           }
2212       }
2213       debugMonitorExit(popFrameProceedLock);
2214 }
2215 
2216 /**
2217  * Pop one frame off the stack of thread.
2218  * popFrameEventLock is already held
2219  */
2220 static jvmtiError
2221 popOneFrame(jthread thread)
2222 {
2223     jvmtiError error;
2224 
2225     error = JVMTI_FUNC_PTR(gdata->jvmti,PopFrame)(gdata->jvmti, thread);
2226     if (error != JVMTI_ERROR_NONE) {
2227         return error;
2228     }
2229 
2230     /* resume the popped thread so that the pop occurs and so we */
2231     /* will get the event (step or method entry) after the pop */
2232     LOG_MISC(("thread=%p resumed in popOneFrame", thread));
2233     error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, thread);
2234     if (error != JVMTI_ERROR_NONE) {
2235         return error;
2236     }
2237 
2238     /* wait for the event to occur */
2239     setPopFrameEvent(thread, JNI_FALSE);
2240     while (getPopFrameEvent(thread) == JNI_FALSE) {
2241         debugMonitorWait(popFrameEventLock);
2242     }
2243 
2244     /* make sure not to suspend until the popped thread is on the wait */
2245     debugMonitorEnter(popFrameProceedLock);
2246     {
2247         /* return popped thread to suspended state */
2248         LOG_MISC(("thread=%p suspended in popOneFrame", thread));
2249         error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)(gdata->jvmti, thread);
2250 
2251         /* notify popped thread so it can proceed when resumed */
2252         setPopFrameProceed(thread, JNI_TRUE);
2253         debugMonitorNotify(popFrameProceedLock);
2254     }
2255     debugMonitorExit(popFrameProceedLock);
2256 
2257     return error;
2258 }
2259 
2260 /**
2261  * pop frames of the stack of 'thread' until 'frame' is popped.
2262  */
2263 jvmtiError
2264 threadControl_popFrames(jthread thread, FrameNumber fnum)
2265 {
2266     jvmtiError error;
2267     jvmtiEventMode prevStepMode;
2268     jint framesPopped = 0;
2269     jint popCount;
2270     jboolean prevInvokeRequestMode;
2271 
2272     log_debugee_location("threadControl_popFrames()", thread, NULL, 0);
2273 
2274     initLocks();
2275 
2276     /* compute the number of frames to pop */
2277     popCount = fnum+1;
2278     if (popCount < 1) {
2279         return AGENT_ERROR_NO_MORE_FRAMES;
2280     }
2281 
2282     /* enable instruction level single step, but first note prev value */
2283     prevStepMode = threadControl_getInstructionStepMode(thread);
2284 
2285     /*
2286      * Fix bug 6517249.  The pop processing will disable invokes,
2287      * so remember if invokes are enabled now and restore
2288      * that state after we finish popping.
2289      */
2290     prevInvokeRequestMode = invoker_isEnabled(thread);
2291 
2292     error = threadControl_setEventMode(JVMTI_ENABLE,
2293                                        EI_SINGLE_STEP, thread);
2294     if (error != JVMTI_ERROR_NONE) {
2295         return error;
2296     }
2297 
2298     /* Inform eventHandler logic we are in a popFrame for this thread */
2299     debugMonitorEnter(popFrameEventLock);
2300     {
2301         setPopFrameThread(thread, JNI_TRUE);
2302         /* pop frames using single step */
2303         while (framesPopped++ < popCount) {
2304             error = popOneFrame(thread);
2305             if (error != JVMTI_ERROR_NONE) {
2306                 break;
2307             }
2308         }
2309         setPopFrameThread(thread, JNI_FALSE);
2310     }
2311     debugMonitorExit(popFrameEventLock);
2312 
2313     /*  Reset StepRequest info (fromLine and stackDepth) after popframes
2314      *  only if stepping is enabled.
2315      */
2316     if (prevStepMode == JVMTI_ENABLE) {
2317         stepControl_resetRequest(thread);
2318     }
2319 
2320     if (prevInvokeRequestMode) {
2321         invoker_enableInvokeRequests(thread);
2322     }
2323 
2324     /* restore state */
2325     (void)threadControl_setEventMode(prevStepMode,
2326                                EI_SINGLE_STEP, thread);
2327 
2328     return error;
2329 }
2330 
2331 /* Check to see if any events are being consumed by a popFrame(). */
2332 static jboolean
2333 checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread)
2334 {
2335     if ( getPopFrameThread(thread) ) {
2336         switch (ei) {
2337             case EI_THREAD_START:
2338                 /* Excuse me? */
2339                 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame");
2340                 break;
2341             case EI_THREAD_END:
2342                 /* Thread wants to end? let it. */
2343                 setPopFrameThread(thread, JNI_FALSE);
2344                 popFrameCompleteEvent(thread);
2345                 break;
2346             case EI_SINGLE_STEP:
2347                 /* This is an event we requested to mark the */
2348                 /*        completion of the pop frame */
2349                 popFrameCompleteEvent(thread);
2350                 return JNI_TRUE;
2351             case EI_BREAKPOINT:
2352             case EI_EXCEPTION:
2353             case EI_FIELD_ACCESS:
2354             case EI_FIELD_MODIFICATION:
2355             case EI_METHOD_ENTRY:
2356             case EI_METHOD_EXIT:
2357                 /* Tell event handler to assume event has been consumed. */
2358                 return JNI_TRUE;
2359             default:
2360                 break;
2361         }
2362     }
2363     /* Pretend we were never called */
2364     return JNI_FALSE;
2365 }
2366 
2367 struct bag *
2368 threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject currentException)
2369 {
2370     ThreadNode *node;
2371     JNIEnv     *env;
2372     struct bag *eventBag;
2373     jthread     threadToSuspend;
2374     jboolean    consumed;
2375     EventIndex  ei = evinfo->ei;
2376     jthread     thread = evinfo->thread;
2377 
2378     env             = getEnv();
2379     threadToSuspend = NULL;
2380 
2381     log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL, 0);
2382 
2383     /* Events during pop commands may need to be ignored here. */
2384     consumed = checkForPopFrameEvents(env, ei, thread);
2385     if ( consumed ) {
2386         /* Always restore any exception (see below). */
2387         if (currentException != NULL) {
2388             JNI_FUNC_PTR(env,Throw)(env, currentException);
2389         } else {
2390             JNI_FUNC_PTR(env,ExceptionClear)(env);
2391         }
2392         return NULL;
2393     }
2394 
2395     debugMonitorEnter(threadLock);
2396 
2397     /*
2398      * Check the list of unknown threads maintained by suspend
2399      * and resume. If this thread is currently present in the
2400      * list, it should be
2401      * moved to the runningThreads list, since it is a
2402      * well-known thread now.
2403      */
2404     node = findThread(&otherThreads, thread);
2405     if (node != NULL) {
2406         moveNode(&otherThreads, &runningThreads, node);
2407     } else {
2408         /*
2409          * Get a thread node for the reporting thread. For thread start
2410          * events, or if this event precedes a thread start event,
2411          * the thread node may need to be created.
2412          *
2413          * It is possible for certain events (notably method entry/exit)
2414          * to precede thread start for some VM implementations.
2415          */
2416         node = insertThread(env, &runningThreads, thread);
2417     }
2418 
2419     if (ei == EI_THREAD_START) {
2420         node->isStarted = JNI_TRUE;
2421         processDeferredEventModes(env, thread, node);
2422     }
2423 
2424     node->current_ei = ei;
2425     eventBag = node->eventBag;
2426     if (node->suspendOnStart) {
2427         threadToSuspend = node->thread;
2428     }
2429     debugMonitorExit(threadLock);
2430 
2431     if (threadToSuspend != NULL) {
2432         /*
2433          * An attempt was made to suspend this thread before it started.
2434          * We must suspend it now, before it starts to run. This must
2435          * be done with no locks held.
2436          */
2437         eventHelper_suspendThread(sessionID, threadToSuspend);
2438     }
2439 
2440     return eventBag;
2441 }
2442 
2443 static void
2444 doPendingTasks(JNIEnv *env, ThreadNode *node)
2445 {
2446     /*
2447      * Take care of any pending interrupts/stops, and clear out
2448      * info on pending interrupts/stops.
2449      */
2450     if (node->pendingInterrupt) {
2451         JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2452                         (gdata->jvmti, node->thread);
2453         /*
2454          * TO DO: Log error
2455          */
2456         node->pendingInterrupt = JNI_FALSE;
2457     }
2458 
2459     if (node->pendingStop != NULL) {
2460         JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2461                         (gdata->jvmti, node->thread, node->pendingStop);
2462         /*
2463          * TO DO: Log error
2464          */
2465         tossGlobalRef(env, &(node->pendingStop));
2466     }
2467 }
2468 
2469 void
2470 threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
2471                                  struct bag *eventBag)
2472 {
2473     ThreadNode *node;
2474 
2475     log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0);
2476 
2477     if (ei == EI_THREAD_END) {
2478         eventHandler_lock(); /* for proper lock order */
2479     }
2480     debugMonitorEnter(threadLock);
2481 
2482     node = findThread(&runningThreads, thread);
2483     if (node == NULL) {
2484         EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2485     } else {
2486         JNIEnv *env;
2487 
2488         env = getEnv();
2489         if (ei == EI_THREAD_END) {
2490             jboolean inResume = (node->resumeFrameDepth > 0);
2491             removeThread(env, &runningThreads, thread);
2492             node = NULL;   /* has been freed */
2493 
2494             /*
2495              * Clean up mechanism used to detect end of
2496              * resume.
2497              */
2498             if (inResume) {
2499                 notifyAppResumeComplete();
2500             }
2501         } else {
2502             /* No point in doing this if the thread is about to die.*/
2503             doPendingTasks(env, node);
2504             node->eventBag = eventBag;
2505             node->current_ei = 0;
2506         }
2507     }
2508 
2509     debugMonitorExit(threadLock);
2510     if (ei == EI_THREAD_END) {
2511         eventHandler_unlock();
2512     }
2513 }
2514 
2515 void
2516 threadControl_setName(jthread thread, const char *name)
2517 {
2518 #ifdef DEBUG_THREADNAME
2519     ThreadNode *node = findThread(NULL, thread);
2520     if (node != NULL) {
2521         strncpy(node->name, name, sizeof(node->name) - 1);
2522     }
2523 #endif
2524 }
2525 
2526 /* Returns JDWP flavored status and status flags. */
2527 jvmtiError
2528 threadControl_applicationThreadStatus(jthread thread,
2529                         jdwpThreadStatus *pstatus, jint *statusFlags)
2530 {
2531     ThreadNode *node = NULL;
2532     jvmtiError  error;
2533     jint        state;
2534     jboolean    is_fiber = isFiber(thread);
2535 
2536     log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2537 
2538     debugMonitorEnter(threadLock);
2539 
2540     if (!is_fiber) {
2541         error = threadState(thread, &state);
2542         *pstatus = map2jdwpThreadStatus(state);
2543         *statusFlags = map2jdwpSuspendStatus(state);
2544         node = findThread(&runningThreads, thread);
2545 
2546         if (error == JVMTI_ERROR_NONE) {
2547             if ((node != NULL) && HANDLING_EVENT(node)) {
2548                 /*
2549                  * While processing an event, an application thread is always
2550                  * considered to be running even if its handler happens to be
2551                  * cond waiting on an internal debugger monitor, etc.
2552                  *
2553                  * Leave suspend status untouched since it is not possible
2554                  * to distinguish debugger suspends from app suspends.
2555                  */
2556                 *pstatus = JDWP_THREAD_STATUS(RUNNING);
2557             }
2558         }
2559 #if 0
2560         tty_message("status thread: node(%p) suspendCount(%d) %d %d %s",
2561                     node, node->suspendCount, *pstatus, *statusFlags, node->name);
2562 #endif
2563     } else { /* It's a fiber */
2564         int suspendCount;
2565         error = JVMTI_ERROR_NONE;
2566         *pstatus = JDWP_THREAD_STATUS(RUNNING);
2567         *statusFlags = 0;
2568         node = findThread(&runningFibers, thread);
2569         if (node->isTrackedSuspendedFiber) {
2570             /* Already tracking this fiber, so fiber node owns its suspendCount. */
2571             suspendCount = node->suspendCount;
2572         } else {
2573             /* Not tacking this fiber yet, so use suspendAllCount. */
2574             suspendCount = suspendAllCount;
2575         }
2576         if (suspendCount > 0) {
2577             *statusFlags = JDWP_SUSPEND_STATUS(SUSPENDED);
2578         } else {
2579             /* If the fiber was not suspended, maybe it's carrier thread was. */
2580             thread = getFiberThread(thread);
2581             if (thread != NULL) {
2582                 node = findThread(&runningThreads, thread);
2583                 if (node->suspendCount > 0) {
2584                     *statusFlags = JDWP_SUSPEND_STATUS(SUSPENDED);
2585                 }
2586             }
2587         }
2588 #if 0
2589         tty_message("status thread: fiber(%p) suspendCount(%d) %d %d %s",
2590                     node, node->suspendCount, *pstatus, *statusFlags, node->name);
2591 #endif
2592     }
2593 
2594     debugMonitorExit(threadLock);
2595 
2596     return error;
2597 }
2598 
2599 jvmtiError
2600 threadControl_interrupt(jthread thread)
2601 {
2602     ThreadNode *node;
2603     jvmtiError  error;
2604 
2605     error = JVMTI_ERROR_NONE;
2606 
2607     log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2608 
2609     debugMonitorEnter(threadLock);
2610 
2611     node = findThread(&runningThreads, thread);
2612     if ((node == NULL) || !HANDLING_EVENT(node)) {
2613         error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2614                         (gdata->jvmti, thread);
2615     } else {
2616         /*
2617          * Hold any interrupts until after the event is processed.
2618          */
2619         node->pendingInterrupt = JNI_TRUE;
2620     }
2621 
2622     debugMonitorExit(threadLock);
2623 
2624     return error;
2625 }
2626 
2627 void
2628 threadControl_clearCLEInfo(JNIEnv *env, jthread thread)
2629 {
2630     ThreadNode *node;
2631 
2632     debugMonitorEnter(threadLock);
2633 
2634     node = findThread(&runningThreads, thread);
2635     if (node != NULL) {
2636         node->cleInfo.ei = 0;
2637         if (node->cleInfo.clazz != NULL) {
2638             tossGlobalRef(env, &(node->cleInfo.clazz));
2639         }
2640     }
2641 
2642     debugMonitorExit(threadLock);
2643 }
2644 
2645 jboolean
2646 threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz,
2647                          jmethodID method, jlocation location)
2648 {
2649     ThreadNode *node;
2650     jboolean    result;
2651 
2652     result = JNI_FALSE;
2653 
2654     debugMonitorEnter(threadLock);
2655 
2656     node = findThread(&runningThreads, thread);
2657     if (node != NULL && node->cleInfo.ei != 0 &&
2658         node->cleInfo.method == method &&
2659         node->cleInfo.location == location &&
2660         (isSameObject(env, node->cleInfo.clazz, clazz))) {
2661         result = JNI_TRUE; /* we have a match */
2662     }
2663 
2664     debugMonitorExit(threadLock);
2665 
2666     return result;
2667 }
2668 
2669 void
2670 threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
2671                           jclass clazz, jmethodID method, jlocation location)
2672 {
2673     ThreadNode *node;
2674 
2675     debugMonitorEnter(threadLock);
2676 
2677     node = findThread(&runningThreads, thread);
2678     if (node != NULL) {
2679         node->cleInfo.ei = ei;
2680         /* Create a class ref that will live beyond */
2681         /* the end of this call */
2682         saveGlobalRef(env, clazz, &(node->cleInfo.clazz));
2683         /* if returned clazz is NULL, we just won't match */
2684         node->cleInfo.method    = method;
2685         node->cleInfo.location  = location;
2686     }
2687 
2688     debugMonitorExit(threadLock);
2689 }
2690 
2691 void
2692 threadControl_setPendingInterrupt(jthread thread)
2693 {
2694     ThreadNode *node;
2695 
2696     debugMonitorEnter(threadLock);
2697 
2698     node = findThread(&runningThreads, thread);
2699     if (node != NULL) {
2700         node->pendingInterrupt = JNI_TRUE;
2701     }
2702 
2703     debugMonitorExit(threadLock);
2704 }
2705 
2706 jvmtiError
2707 threadControl_stop(jthread thread, jobject throwable)
2708 {
2709     ThreadNode *node;
2710     jvmtiError  error;
2711 
2712     error = JVMTI_ERROR_NONE;
2713 
2714     log_debugee_location("threadControl_stop()", thread, NULL, 0);
2715 
2716     debugMonitorEnter(threadLock);
2717 
2718     node = findThread(&runningThreads, thread);
2719     if ((node == NULL) || !HANDLING_EVENT(node)) {
2720         error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2721                         (gdata->jvmti, thread, throwable);
2722     } else {
2723         JNIEnv *env;
2724 
2725         /*
2726          * Hold any stops until after the event is processed.
2727          */
2728         env = getEnv();
2729         saveGlobalRef(env, throwable, &(node->pendingStop));
2730     }
2731 
2732     debugMonitorExit(threadLock);
2733 
2734     return error;
2735 }
2736 
2737 static jvmtiError
2738 detachHelper(JNIEnv *env, ThreadNode *node, void *arg)
2739 {
2740     invoker_detach(&node->currentInvoke);
2741     return JVMTI_ERROR_NONE;
2742 }
2743 
2744 void
2745 threadControl_detachInvokes(void)
2746 {
2747     JNIEnv *env;
2748 
2749     env = getEnv();
2750     invoker_lock(); /* for proper lock order */
2751     debugMonitorEnter(threadLock);
2752     (void)enumerateOverThreadList(env, &runningThreads, detachHelper, NULL);
2753     debugMonitorExit(threadLock);
2754     invoker_unlock();
2755 }
2756 
2757 static jvmtiError
2758 resetHelper(JNIEnv *env, ThreadNode *node, void *arg)
2759 {
2760     if (node->toBeResumed) {
2761         LOG_MISC(("thread=%p resumed", node->thread));
2762         (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, node->thread);
2763         node->frameGeneration++; /* Increment on each resume */
2764     }
2765     stepControl_clearRequest(node->thread, &node->currentStep);
2766     node->toBeResumed = JNI_FALSE;
2767     node->suspendCount = 0;
2768     node->suspendOnStart = JNI_FALSE;
2769 
2770     return JVMTI_ERROR_NONE;
2771 }
2772 
2773 void
2774 threadControl_reset(void)
2775 {
2776     JNIEnv *env;
2777 
2778     env = getEnv();
2779     eventHandler_lock(); /* for proper lock order */
2780     debugMonitorEnter(threadLock);
2781     (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2782     (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);
2783     (void)enumerateOverThreadList(env, &runningFibers, resetHelper, NULL);
2784 
2785     removeResumed(env, &otherThreads);
2786 
2787     freeDeferredEventModes(env);
2788 
2789     suspendAllCount = 0;
2790 
2791     /* Everything should have been resumed */
2792     JDI_ASSERT(otherThreads.first == NULL);
2793 
2794     debugMonitorExit(threadLock);
2795     eventHandler_unlock();
2796 }
2797 
2798 jvmtiEventMode
2799 threadControl_getInstructionStepMode(jthread thread)
2800 {
2801     ThreadNode    *node;
2802     jvmtiEventMode mode;
2803 
2804     mode = JVMTI_DISABLE;
2805 
2806     debugMonitorEnter(threadLock);
2807     node = findThread(&runningThreads, thread);
2808     if (node != NULL) {
2809         mode = node->instructionStepMode;
2810     }
2811     debugMonitorExit(threadLock);
2812     return mode;
2813 }
2814 
2815 jvmtiError
2816 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2817 {
2818     jvmtiError error;
2819 
2820     /* Global event */
2821     if ( thread == NULL ) {
2822         error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2823                     (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2824     } else {
2825         /* Thread event */
2826         ThreadNode *node;
2827 
2828         debugMonitorEnter(threadLock);
2829         {
2830             if (isFiber(thread)) {
2831                 /* fiber fixme: Getting the carrier thread here is just a hack. It does not work if
2832                  * the fiber is not mounted, and even if mounted, does not result in the correct
2833                  * behaviour if the fiber changes carrier threads. If the carrier thread is
2834                  * NULL we need to defer all the code below, most notably
2835                  * threadSetEventNotificationMode(), until after the fiber is mounted. We also need
2836                  * to call threadSetEventNotificationMode() each time there is an unmount or mount
2837                  * since the thread that needs notifications will change as the fiber moves
2838                  * between carrier threads. The best way to manage this might be to move
2839                  * HandlerNodes for unmounted fibers onto a linked list hanging off the fiber's
2840                  * ThreadNode. But that also complicates finding HandlerNodes. For example,
2841                  * when a breakpoint is cleared, we call eventHandler_freeByID(), which would
2842                  * need to also search every fiber for the handler. The other choice is to
2843                  * keep handlers where they are now (off the array of handler chains), but
2844                  * for every mount/unmount, search all the handlers in all the chains for
2845                  * ones that are for the mounting/unmounting fiber. This could be slow,
2846                  * although generally speaking we don't have many HandlerNodes because
2847                  * they are generated indirectly by the debugger as users do things
2848                  * like set breakpoints.
2849                  * A hybrid approach might be best. Keep the handler chains as they are now,
2850                  * but also have each fiber maintain a list of its handler nodes for faster
2851                  * handling during mount/unmount.
2852                  *
2853                  * And it should also be noted here that if the carrier thread is null, the
2854                  * findThread() call ends up returning the current thread, and then 
2855                  * threadSetEventNotificationMode() is called with a NULL thread, resulting
2856                  * in the event being enabled on all threads. This bug actually has the 
2857                  * desireable affect of making breakpoints that are filtered on an unmounted
2858                  * fiber work as expected, because all the carrier threads get the breakpoint
2859                  * event enabled. However, for some odd reason it also works as expected if
2860                  * the fiber is already mounted. I expected that the breakpoint event would only
2861                  * be enabled on the carrier thread in that case, and therefore if the fiber
2862                  * was moved to a different carrier thread, you would stop getting breakpoints
2863                  * until it moved back to the original carrier thread. That's not the case for some
2864                  * reason, and I'm see the breakpoints no matter what carrier thread the fiber
2865                  * runs on. It turns out that the agent installs a global breakpoint for
2866                  * Thread.resume(), so global breakpoints are always enabled.
2867                  * See handleAppResumeBreakpoint.
2868                  *
2869                  * It also should be noted that this does not cause a problem for single stepping
2870                  * because:
2871                  *  - There is at most one single step HandlerNode per thread.
2872                  *  - Fiber mount/unmount events result explicitly dooing the proper
2873                  *    enabling/disabling of the JVMTI single step event on the carrier thread.
2874                  * There is a potential issue with initiating a StepRequest on and unmounted
2875                  * fiber. See the fixme comment in stepControl_beginStep.
2876                  */ 
2877                 thread = getFiberThread(thread);
2878             }
2879             node = findThread(&runningThreads, thread);
2880             if ((node == NULL) || (!node->isStarted)) {
2881                 JNIEnv *env;
2882 
2883                 env = getEnv();
2884                 error = addDeferredEventMode(env, mode, ei, thread);
2885             } else {
2886                 error = threadSetEventNotificationMode(node,
2887                         mode, ei, thread);
2888             }
2889         }
2890         debugMonitorExit(threadLock);
2891 
2892     }
2893     return error;
2894 }
2895 
2896 /*
2897  * Returns the current thread, if the thread has generated at least
2898  * one event, and has not generated a thread end event.
2899  */
2900 jthread
2901 threadControl_currentThread(void)
2902 {
2903     jthread thread;
2904 
2905     debugMonitorEnter(threadLock);
2906     {
2907         ThreadNode *node;
2908 
2909         node = findThread(&runningThreads, NULL);
2910         thread = (node == NULL) ? NULL : node->thread;
2911     }
2912     debugMonitorExit(threadLock);
2913 
2914     return thread;
2915 }
2916 
2917 jlong
2918 threadControl_getFrameGeneration(jthread thread)
2919 {
2920     jlong frameGeneration = -1;
2921 
2922     debugMonitorEnter(threadLock);
2923     {
2924         ThreadNode *node;
2925 
2926         node = findThread(NULL, thread);
2927 
2928         if (node != NULL) {
2929             frameGeneration = node->frameGeneration;
2930         }
2931     }
2932     debugMonitorExit(threadLock);
2933 
2934     return frameGeneration;
2935 }
2936 
2937 jthread
2938 threadControl_getFiberCarrierOrHelperThread(jthread fiber)
2939 {
2940     /* Get the carrier thread that the fiber is running on */
2941     jthread carrier_thread = getFiberThread(fiber);
2942     if (carrier_thread != NULL) {
2943         return carrier_thread;
2944     } else {
2945         jthread helperThread;
2946         debugMonitorEnter(threadLock);
2947         helperThread = getFiberHelperThread(fiber);
2948         debugMonitorExit(threadLock);
2949         if (helperThread == NULL) {
2950             /* fiber fixme: we failed to get the helper thread, probably because the fiber
2951              * is currently in the PARKING state. Still need a solution for this. Fix
2952              * all callers too.
2953              */
2954             LOG_MISC(("threadControl_getFiberCarrierOrHelperThread: getFiberHelperThread() failed"));
2955         }
2956         return helperThread;
2957     }
2958 }
2959 
2960 jthread *
2961 threadControl_allFibers(jint *numFibers)
2962 {
2963     JNIEnv *env;
2964     ThreadNode *node;
2965     jthread* fibers;
2966 
2967     env = getEnv();
2968     debugMonitorEnter(threadLock);
2969 
2970     /* Count the number of fibers */
2971     /* fiber fixme: we should keep a running total so no counting is needed. */
2972     *numFibers = 0;
2973     for (node = runningFibers.first; node != NULL; node = node->next) {
2974         (*numFibers)++;
2975     }
2976 
2977     /* Allocate and fill in the fibers array. */
2978     fibers = jvmtiAllocate(*numFibers * sizeof(jthread*));
2979     if (fibers != NULL) {
2980         int i = 0;
2981         for (node = runningFibers.first; node != NULL;  node = node->next) {
2982             fibers[i++] = node->thread;
2983         }
2984     }
2985 
2986     debugMonitorExit(threadLock);
2987 
2988     return fibers;
2989 }
2990 
2991 jboolean threadControl_isKnownFiber(jthread fiber) {
2992     ThreadNode *fiberNode;
2993     debugMonitorEnter(threadLock);
2994     fiberNode = findThread(&runningFibers, fiber);
2995     debugMonitorExit(threadLock);
2996     return fiberNode != NULL;
2997 }
2998 
2999 void
3000 threadControl_addFiber(jthread fiber)
3001 {
3002     ThreadNode *fiberNode;
3003     debugMonitorEnter(threadLock);
3004     fiberNode = insertThread(getEnv(), &runningFibers, fiber);
3005     debugMonitorExit(threadLock);
3006 }
3007 
3008 void
3009 threadControl_mountFiber(jthread fiber, jthread thread, jbyte sessionID) {
3010     /* fiber fixme: this funciton no longer serves any purpose now that we rely on
3011      * continuation events instead. remove.
3012      */
3013 }
3014 
3015 
3016 void
3017 threadControl_unmountFiber(jthread fiber, jthread thread)
3018 {
3019     /* fiber fixme: this funciton no longer serves any purpose now that we rely on
3020      * continuation events instead. remove.
3021      */
3022 }
3023 
3024 void
3025 threadControl_continuationRun(jthread thread, jint continuation_frame_count)
3026 {
3027     debugMonitorEnter(threadLock);
3028     {
3029         JNIEnv *env = getEnv();
3030         ThreadNode *threadNode;
3031         ThreadNode *fiberNode;
3032         jthread fiber;
3033 
3034         threadNode = findThread(&runningThreads, thread);
3035 
3036         /*
3037          * fiber fixme: For now, NULL implies that this is a helper thread created by
3038          * getFiberHelperThread(). We should actually verify that, but for now just
3039          * assume it is the case and ignore the event. The need for helper threads will
3040          * hopefully go away, in which case the assert can be re-added.
3041          */
3042         //JDI_ASSERT(threadNode != NULL);
3043         if (threadNode == NULL) {
3044             debugMonitorExit(threadLock);
3045             return;
3046         }
3047 
3048         JDI_ASSERT(threadNode->isStarted);
3049         JDI_ASSERT(bagSize(threadNode->eventBag) == 0);
3050 
3051         if (threadNode->currentStep.pending) {
3052             /*
3053              * If we are doing a STEP_INTO and are doing class filtering (usually library
3054              * classes), we are relying on METHOD_ENTRY events to tell us if we've stepped
3055              * back into user code. We won't get this event if when we resume the
3056              * continuation, so we need to let the stepControl now that we got a
3057              * CONTINUATION_RUN event so it can do the right thing in absense of
3058              * the METHOD_ENTRY event. There's also a FramePop setup situation that
3059              * stepControl needs to deal with, which is another reason it needs to
3060              * know about CONTINUATION_RUN events.
3061              */
3062             stepControl_handleContinuationRun(env, thread, &threadNode->currentStep);
3063         }
3064 
3065         fiber = getThreadFiber(threadNode->thread);
3066         if (fiber == NULL) {
3067             debugMonitorExit(threadLock);
3068             return; /* Nothing more to do if thread is not executing a fiber. */
3069         }
3070 
3071         fiberNode = findThread(&runningFibers, fiber);
3072         if (!gdata->notifyDebuggerOfAllFibers && fiberNode == NULL) {
3073             /* This is not a fiber we are tracking, so nothing to do. */
3074             debugMonitorExit(threadLock);
3075             return;
3076         }
3077 
3078         JDI_ASSERT(fiberNode != NULL);
3079         JDI_ASSERT(fiberNode->isStarted);
3080         JDI_ASSERT(bagSize(fiberNode->eventBag) == 0);
3081 
3082         /* If we are not single stepping in this fiber then there is nothing to do. */
3083         if (!fiberNode->currentStep.pending) {
3084             debugMonitorExit(threadLock);
3085             return;
3086         }
3087         JDI_ASSERT(fiberNode->currentStep.is_fiber);
3088 
3089         /*
3090          * Move the single step state from the fiberNode to threadNode, but only if we aren't
3091          * already single stepping on the carrier thread.
3092          */
3093         if (!threadNode->currentStep.pending) {
3094             /* Copy fiber currentStep struct to carrier thread. */
3095             memcpy(&threadNode->currentStep, &fiberNode->currentStep, sizeof(fiberNode->currentStep));
3096 
3097             /* Enable JVMTI single step on the carrier thread if necessary. */
3098             if (fiberNode->instructionStepMode == JVMTI_ENABLE) {
3099                 stepControl_enableStepping(thread);
3100                 threadNode->instructionStepMode = JVMTI_ENABLE;
3101             }
3102 
3103             /* Restore the NotifyFramePop that was in place when this Fiber yielded. */
3104             {
3105                 jvmtiError error;
3106                 jint depth;
3107                 /* NotifyFramePop was originally called with a depth of 0 to indicate the current
3108                  * frame. However, frames have been pushed since then, so we need to adjust the
3109                  * depth to get to the right frame.
3110                  *
3111                  * fromStackDepth represents the number of frames on the stack when the STEP_OVER
3112                  * was started. NotifyFramePop was called on the method that was entered, which is
3113                  * one frame below (fromStackDepth + 1). To account for new frames pushed since
3114                  * then, we subtract fromStackDepth from the current number of frames. This
3115                  * represents the frame where the STEP_OVER was done, but since we want one
3116                  * frame below this point, we also subtract one.
3117                  */
3118                 depth = getThreadFrameCount(thread) - fiberNode->currentStep.fromStackDepth;
3119                 depth--; /* We actually want the frame one below the adjusted fromStackDepth. */
3120                 if (depth >= 0) {
3121                     error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)(gdata->jvmti, thread, depth);
3122                     if (error == JVMTI_ERROR_DUPLICATE) {
3123                       error = JVMTI_ERROR_NONE;
3124                       /* Already being notified, continue without error */
3125                     } else if (error != JVMTI_ERROR_NONE) {
3126                       EXIT_ERROR(error, "NotifyFramePop failed during mountFiber");
3127                     }
3128                 } else {
3129                     /*
3130                      * If the less than 0, then that means we were single stepping over
3131                      * the Continuation.doYield() call. In this case NotifyFramePop is not going to work
3132                      * since there was never one setup (doYield() was never actually entered). So
3133                      * all that needs to be done is to restore single stepping, and we'll stop
3134                      * on the next bytecode after the doYield() call.
3135                      */
3136                     JDI_ASSERT(depth == -1);
3137                     if (fiberNode->instructionStepMode == JVMTI_DISABLE) {
3138                       stepControl_enableStepping(thread);
3139                       threadNode->instructionStepMode = JVMTI_ENABLE;
3140                     }
3141                 }
3142             }
3143    
3144             /* Enable events */
3145             threadControl_setEventMode(JVMTI_ENABLE, EI_EXCEPTION_CATCH, thread);
3146             threadControl_setEventMode(JVMTI_ENABLE, EI_FRAME_POP, thread);
3147             if (threadNode->currentStep.methodEnterHandlerNode != NULL) {
3148                 threadControl_setEventMode(JVMTI_ENABLE, EI_METHOD_ENTRY, thread);
3149             }
3150         }
3151 
3152         /* Always clear the fiber single step state, regardless of what we've done above. */
3153         fiberNode->instructionStepMode = JVMTI_DISABLE;
3154         memset(&fiberNode->currentStep, 0, sizeof(fiberNode->currentStep));
3155 
3156         /*
3157          * If for any reason we are tracking this fiber, then that must mean during a 
3158          * suspendAll there was a resume done on this fiber. So we started tracking it
3159          * and decremented its suspendCount (which normally would put it at 0).
3160          */
3161         if (fiberNode->isTrackedSuspendedFiber) {
3162             JDI_ASSERT(suspendAllCount > 0 && fiberNode->suspendCount == 0);
3163         }
3164         if (suspendAllCount > 0) {
3165             /*
3166              * If there is an outstanding suspendAll, then we suspend the carrier thread. The
3167              * way this typically ends up happening is if initially all threads were suspended
3168              * (perhaps when a breakpoing was hit), and then the debugger user decides to resume
3169              * the fiber or carrier thread. This could allow a new fiber to be mounted on the
3170              * carrier thread, but the fiber is implied to be suspended because suspendAllCount
3171              * is >0. In order to keep the fiber from running we must suspened the carrier thread.
3172              */
3173             /* fiber fixme XXX: disable this feature for now. */
3174             //eventHelper_suspendThread(sessionID, thread);
3175         }
3176     }
3177     debugMonitorExit(threadLock);
3178 }
3179 
3180 void
3181 threadControl_continuationYield(jthread thread, jint continuation_frame_count)
3182 {
3183     /* fiber fixme: need to figure out what to do with these 4 ThreadNode fields:
3184        unsigned int popFrameEvent : 1;
3185        unsigned int popFrameProceed : 1;
3186        unsigned int popFrameThread : 1;
3187        InvokeRequest currentInvoke;
3188     */
3189     debugMonitorEnter(threadLock);
3190     {
3191         JNIEnv *env = getEnv();
3192         ThreadNode *threadNode;
3193         jint total_frame_count;
3194         jint fromDepth;
3195 
3196         threadNode = findThread(&runningThreads, thread);
3197 
3198         /*
3199          * fiber fixme: For now, NULL implies that this is a helper thread created by
3200          * getFiberHelperThread(). We should actually verify that, but for now just
3201          * assume it is the case and ignore the event. The need for helper threads will
3202          * hopefully go away, in which case the assert can be re-added.
3203          */
3204         //JDI_ASSERT(threadNode != NULL);
3205         if (threadNode == NULL) {
3206             debugMonitorExit(threadLock);
3207             return; /* Nothing to do if thread is not known */
3208         }
3209 
3210         JDI_ASSERT(threadNode->isStarted);
3211         JDI_ASSERT(bagSize(threadNode->eventBag) == 0);
3212 
3213         /*
3214          * If we are not single stepping in this thread, then there is nothing to do.
3215          */
3216         if (!threadNode->currentStep.pending) {
3217             debugMonitorExit(threadLock);
3218             return; /* Nothing to do. */
3219         }
3220 
3221         /* At what depth were we single stepping. */
3222         fromDepth = threadNode->currentStep.fromStackDepth;
3223 
3224         /*
3225          * Note the continuation has already been unmounted, so total_frame_count will not
3226          * include the continuation frames.
3227          */
3228         total_frame_count = getThreadFrameCount(thread);
3229 
3230         if (threadNode->currentStep.depth == JDWP_STEP_DEPTH(OVER) &&
3231             total_frame_count == fromDepth) {
3232             /*
3233              * We were stepping over Continuation.doContinue() in Continuation.run(). This
3234              * is a special case. Before the continuation was unmounted do to the yield, the
3235              * stack looked like:
3236              *    java.lang.Continuation.yield0
3237              *    java.lang.Continuation.yield
3238              *    <fiber frames>  <-- if Fiber, otherwise just additional continuation frames
3239              *    java.lang.Continuation.enter  <-- bottommost continuation frame
3240              *    java.lang.Continuation.run    <-- doContinue() call jumps into continuation
3241              *    java.lang.Fiber.runContinuation  <-- if Fiber, otherwise will be different
3242              *    <scheduler frames>
3243              * All frames above run(), starting with enter(), are continuation frames. The
3244              * correct thing to do here is just enable single stepping. This will resume single
3245              * stepping in Continuation.run() right after the Continuation.doContinue() call.
3246              */
3247             JDI_ASSERT(threadNode->instructionStepMode == JVMTI_DISABLE);
3248             {
3249                 stepControl_enableStepping(thread);
3250                 threadNode->instructionStepMode = JVMTI_ENABLE;
3251             }
3252         } else if (!threadNode->currentStep.is_fiber) {
3253             /* We were single stepping, but not in a fiber. */
3254             if (total_frame_count < fromDepth) { /* Check if fromDepth is in the continuation. */
3255                 /*
3256                  * This means the frame we were single stepping in was part of the set of
3257                  * frames that will were frozen when this continuation yielded. Because of that
3258                  * we need to re-enable single stepping because we won't ever be getting
3259                  * the FRAME_POP event for returning to that frame. This will resume single
3260                  * stepping in Continuation.run() right after the Continuation.enter() call.
3261                  */
3262                 if (threadNode->instructionStepMode == JVMTI_DISABLE) {
3263                     stepControl_enableStepping(thread);
3264                     threadNode->instructionStepMode = JVMTI_ENABLE;
3265                 }
3266             } else {
3267                 /*
3268                  * We are not single stepping in the continuation, and from the earlier check we
3269                  * know we are not single stepping in Continuation.run(), because that would imply
3270                  * we were single stepping over the doContinue() call, and we already checked
3271                  * for that. There is nothing to do in this case. A NotifyFramePop is already setup
3272                  * for a frame further up the stack.
3273                  */
3274             }
3275         } else {
3276             /*
3277              * We are single stepping the fiber, not the carrier thread. Move the single step
3278              * state to the fiberNode.
3279              */
3280             jthread fiber = getThreadFiber(thread);
3281             ThreadNode *fiberNode;
3282             JDI_ASSERT(fiber != NULL);
3283 
3284             fiberNode = findThread(&runningFibers, fiber);
3285             if (!gdata->notifyDebuggerOfAllFibers && fiberNode == NULL) {
3286                 /* This is not a fiber we are tracking. */
3287                 debugMonitorExit(threadLock);
3288                 return;
3289             }
3290 
3291             JDI_ASSERT(fiberNode != NULL);
3292             JDI_ASSERT(fiberNode->isStarted);
3293             JDI_ASSERT(bagSize(fiberNode->eventBag) == 0);
3294 
3295             if (threadNode->currentStep.depth == JDWP_STEP_DEPTH(INTO) &&
3296                 (total_frame_count + continuation_frame_count == fromDepth)) {
3297                 /* We are stepping into Continuation.doYield(), so leave single stepping enabled.
3298                  * This will resume single stepping in Continuation.run() right after the
3299                  * Continuation.enter() call.
3300                  */
3301             } else if (total_frame_count >= fromDepth) { /* Check if fromDepth is NOT in the continuation. */
3302                 /*
3303                  * This means the single stepping was initiated stepping in a fiber, but in that small
3304                  * window after Thread.setFiber(this) has been called, and before the fiber's
3305                  * continuation was actually mounted. An example of this is stepping over the cont.run()
3306                  * call in Fiber.runContinuation(). In this case we just leave the carrier thread's
3307                  * single step state in place. We should eventually get a FramePop event to 
3308                  * enable single stepping again.
3309                  */
3310                 JDI_ASSERT(threadNode->currentStep.depth == JDWP_STEP_DEPTH(OVER));
3311             } else {
3312                 /*
3313                  * We were single stepping in the fiber, and now we need to stop doing that since
3314                  * we are leaving the fiber. We will copy our single step state from the carrier
3315                  * thread to the fiber so we can later restore it when the fiber is mounted again
3316                  * and we get a CONTINUATION_RUN event.
3317                  */
3318 
3319                 /* Clean up JVMTI SINGLE_STEP state. */
3320                 if (threadNode->instructionStepMode == JVMTI_ENABLE) {
3321                     stepControl_disableStepping(thread);
3322                     threadNode->instructionStepMode = JVMTI_DISABLE;
3323                     fiberNode->instructionStepMode = JVMTI_ENABLE;
3324                 }
3325    
3326                 /* Disable events */
3327                 threadControl_setEventMode(JVMTI_DISABLE, EI_EXCEPTION_CATCH, thread);
3328                 threadControl_setEventMode(JVMTI_DISABLE, EI_FRAME_POP, thread);
3329                 if (threadNode->currentStep.methodEnterHandlerNode != NULL) {
3330                     threadControl_setEventMode(JVMTI_DISABLE, EI_METHOD_ENTRY, thread);
3331                 }
3332 
3333                 /* Copy currentStep struct from the threadNode to the fiberNode and then zero out the threadNode. */
3334                 memcpy(&fiberNode->currentStep, &threadNode->currentStep, sizeof(threadNode->currentStep));
3335                 memset(&threadNode->currentStep, 0, sizeof(threadNode->currentStep));
3336             }
3337         }
3338     }
3339     debugMonitorExit(threadLock);
3340 }