< prev index next >

src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c

Print this page

  52 /**
  53  * The main data structure in threadControl is the ThreadNode.
  54  * This is a per-thread structure that is allocated on the
  55  * first event that occurs in a thread. It is freed after the
  56  * thread's thread end event has completed processing. The
  57  * structure contains state information on its thread including
  58  * suspend counts. It also acts as a repository for other
  59  * per-thread state such as the current method invocation or
  60  * current step.
  61  *
  62  * suspendCount is the number of outstanding suspends
  63  * from the debugger. suspends from the app itself are
  64  * not included in this count.
  65  */
  66 typedef struct ThreadNode {
  67     jthread thread;
  68     unsigned int toBeResumed : 1;      /* true if this thread was successfully suspended. */
  69     unsigned int pendingInterrupt : 1; /* true if thread is interrupted while handling an event. */
  70     unsigned int isDebugThread : 1;    /* true if this is one of our debug agent threads. */
  71     unsigned int suspendOnStart : 1;   /* true for new threads if we are currently in a VM.suspend(). */
  72     unsigned int isStarted : 1;        /* THREAD_START or VIRTUAL_THREAD_SCHEDULED event received. */

  73     unsigned int popFrameEvent : 1;
  74     unsigned int popFrameProceed : 1;
  75     unsigned int popFrameThread : 1;
  76     EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */
  77     jobject pendingStop;   /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */
  78     jint suspendCount;
  79     jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */
  80     jvmtiEventMode instructionStepMode;
  81     StepRequest currentStep;
  82     InvokeRequest currentInvoke;
  83     struct bag *eventBag;       /* Accumulation of JDWP events to be sent as a reply. */
  84     CoLocatedEventInfo cleInfo; /* See comment above deferEventReport() for an explanation. */
  85     struct ThreadNode *next;
  86     struct ThreadNode *prev;
  87     jlong frameGeneration;    /* used to generate a unique frameID. Incremented whenever existing frameID
  88                                  needs to be invalidated, such as when the thread is resumed. */
  89     struct ThreadList *list;  /* Tells us what list this thread is in. */
  90 #ifdef DEBUG_THREADNAME
  91     char name[256];
  92 #endif

 107  * popFrameProceedLock is used to assure that the event thread is
 108  * re-suspended immediately after the event is acknowledged.
 109  */
 110 static jrawMonitorID popFrameProceedLock = NULL;
 111 
 112 static jrawMonitorID threadLock;
 113 static jlocation resumeLocation;
 114 static HandlerNode *breakpointHandlerNode;
 115 static HandlerNode *framePopHandlerNode;
 116 static HandlerNode *catchHandlerNode;
 117 
 118 static jvmtiError threadControl_removeDebugThread(jthread thread);
 119 
 120 /*
 121  * Threads which have issued thread start events and not yet issued thread
 122  * end events are maintained in the "runningThreads" list. All other threads known
 123  * to this module are kept in the "otherThreads" list.
 124  */
 125 static ThreadList runningThreads;
 126 static ThreadList otherThreads;

 127 
 128 #define MAX_DEBUG_THREADS 10
 129 static int debugThreadCount;
 130 static jthread debugThreads[MAX_DEBUG_THREADS];
 131 
 132 typedef struct DeferredEventMode {
 133     EventIndex ei;
 134     jvmtiEventMode mode;
 135     jthread thread;
 136     struct DeferredEventMode *next;
 137 } DeferredEventMode;
 138 
 139 typedef struct {
 140     DeferredEventMode *first;
 141     DeferredEventMode *last;
 142 } DeferredEventModeList;
 143 
 144 static DeferredEventModeList deferredEventModes;
 145 
 146 #ifdef DEBUG

 212  *   It assumed that this logic is never dealing with terminated threads,
 213  *   since the ThreadEnd events always delete the ThreadNode while the
 214  *   jthread is still alive.  So we can only look at the ThreadNode's that
 215  *   have never had their TLS set, making the search much faster.
 216  *   But keep in mind, this kind of search should rarely be needed.
 217  */
 218 static ThreadNode *
 219 nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
 220 {
 221     ThreadNode *node;
 222 
 223     for (node = list->first; node != NULL; node = node->next) {
 224         if (isSameObject(env, node->thread, thread)) {
 225             break;
 226         }
 227     }
 228     return node;
 229 }
 230 
 231 /*
 232  * These functions maintain the linked list of currently running threads.
 233  * All assume that the threadLock is held before calling.
 234  */
 235 
 236 /*
 237  * Search for a thread on the list. If list==NULL, search all lists.
 238  */
 239 static ThreadNode *
 240 findThread(ThreadList *list, jthread thread)
 241 {
 242     ThreadNode *node;

 243 
 244     /* Get thread local storage for quick thread -> node access */
 245     node = getThreadLocalStorage(thread);
 246 
 247     if ( node == NULL ) {
 248         /*
 249          * If the thread was not yet started when the ThreadNode was created, then it
 250          * got added to the otherThreads list and its thread local storage was not set.
 251          * Search for it in the otherThreads list.
 252          */
 253         if ( list == NULL || list == &otherThreads ) {
 254             node = nonTlsSearch(getEnv(), &otherThreads, thread);
 255         }
 256         /*
 257          * Normally we can assume that a thread with no TLS will never be in the runningThreads
 258          * list. This is because we always set the TLS when adding to runningThreads.
 259          * However, when a thread exits, its TLS is automatically cleared. Normally this
 260          * is not a problem because the debug agent will first get a THREAD_END event,
 261          * and that will cause the thread to be removed from runningThreads, thus we
 262          * avoid this situation of having a thread in runningThreads, but with no TLS.

 278         } else {
 279             /*
 280              * Search the runningThreads list. The TLS lookup may have failed because the
 281              * thread has terminated, but we never got the THREAD_END event.
 282              */
 283             if ( node == NULL ) {
 284                 if ( list == NULL || list == &runningThreads ) {
 285                     node = nonTlsSearch(getEnv(), &runningThreads, thread);
 286                 }
 287             }
 288         }
 289     }
 290 
 291     /* If a list is supplied, only return ones in this list */
 292     if ( node != NULL && list != NULL && node->list != list ) {
 293         return NULL;
 294     }
 295     return node;
 296 }
 297 













 298 /* Remove a ThreadNode from a ThreadList */
 299 static void
 300 removeNode(ThreadList *list, ThreadNode *node)
 301 {
 302     ThreadNode *prev;
 303     ThreadNode *next;
 304 
 305     prev = node->prev;
 306     next = node->next;
 307     if ( prev != NULL ) {
 308         prev->next = next;
 309     }
 310     if ( next != NULL ) {
 311         next->prev = prev;
 312     }
 313     if ( prev == NULL ) {
 314         list->first = next;
 315     }
 316     node->next = NULL;
 317     node->prev = NULL;

 323 addNode(ThreadList *list, ThreadNode *node)
 324 {
 325     node->next = NULL;
 326     node->prev = NULL;
 327     node->list = NULL;
 328     if ( list->first == NULL ) {
 329         list->first = node;
 330     } else {
 331         list->first->prev = node;
 332         node->next = list->first;
 333         list->first = node;
 334     }
 335     node->list = list;
 336 }
 337 
 338 static ThreadNode *
 339 insertThread(JNIEnv *env, ThreadList *list, jthread thread)
 340 {
 341     ThreadNode *node;
 342     struct bag *eventBag;

 343 
 344     node = findThread(list, thread);
 345     if (node == NULL) {
 346         node = jvmtiAllocate(sizeof(*node));
 347         if (node == NULL) {
 348             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 349             return NULL;
 350         }
 351         (void)memset(node, 0, sizeof(*node));
 352         eventBag = eventHelper_createEventBag();
 353         if (eventBag == NULL) {
 354             jvmtiDeallocate(node);
 355             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 356             return NULL;
 357         }
 358 
 359         /*
 360          * Init all flags false, all refs NULL, all counts 0
 361          */
 362 
 363         saveGlobalRef(env, thread, &(node->thread));
 364         if (node->thread == NULL) {
 365             jvmtiDeallocate(node);
 366             bagDestroyBag(eventBag);
 367             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 368             return NULL;
 369         }
 370         /*
 371          * Remember if it is a debug thread
 372          */
 373         if (threadControl_isDebugThread(node->thread)) {
 374             node->isDebugThread = JNI_TRUE;
 375         } else if (suspendAllCount > 0){
 376             /*
 377              * If there is a pending suspendAll, all new threads should
 378              * be initialized as if they were suspended by the suspendAll,
 379              * and the thread will need to be suspended when it starts.
 380              */
 381             node->suspendCount = suspendAllCount;
 382             node->suspendOnStart = JNI_TRUE;






















 383         }

 384         node->current_ei = 0;

 385         node->instructionStepMode = JVMTI_DISABLE;
 386         node->eventBag = eventBag;
 387         addNode(list, node);
 388 
 389 #ifdef DEBUG_THREADNAME
 390         {
 391             /* Set the thread name */
 392             jvmtiThreadInfo info;
 393             jvmtiError error;
 394 
 395             memset(&info, 0, sizeof(info));
 396             error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
 397                     (gdata->jvmti, node->thread, &info);
 398             if (info.name != NULL) {
 399                 strncpy(node->name, info.name, sizeof(node->name) - 1);
 400                 jvmtiDeallocate(info.name);
 401             }
 402         }
 403 #endif
 404 

 447 
 448 static void
 449 removeResumed(JNIEnv *env, ThreadList *list)
 450 {
 451     ThreadNode *node;
 452 
 453     node = list->first;
 454     while (node != NULL) {
 455         ThreadNode *temp = node->next;
 456         if (node->suspendCount == 0) {
 457             removeThread(env, list, node->thread);
 458         }
 459         node = temp;
 460     }
 461 }
 462 
 463 static void
 464 moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node)
 465 {
 466     removeNode(source, node);




 467     JDI_ASSERT(findThread(dest, node->thread) == NULL);
 468     addNode(dest, node);
 469 }
 470 
 471 typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);
 472 
 473 static jvmtiError
 474 enumerateOverThreadList(JNIEnv *env, ThreadList *list,
 475                         ThreadEnumerateFunction function, void *arg)
 476 {
 477     ThreadNode *node;
 478     jvmtiError error = JVMTI_ERROR_NONE;
 479 
 480     for (node = list->first; node != NULL; node = node->next) {
 481         error = (*function)(env, node, arg);
 482         if ( error != JVMTI_ERROR_NONE ) {
 483             break;
 484         }
 485     }
 486     return error;

 610 static void
 611 releaseLocks(void)
 612 {
 613     debugMonitorExit(threadLock);
 614     commonRef_unlock();
 615     stepControl_unlock();
 616     eventHelper_unlock();
 617     invoker_unlock();
 618     eventHandler_unlock();
 619 }
 620 
 621 void
 622 threadControl_initialize(void)
 623 {
 624     jlocation unused;
 625     jvmtiError error;
 626 
 627     suspendAllCount = 0;
 628     runningThreads.first = NULL;
 629     otherThreads.first = NULL;

 630     debugThreadCount = 0;
 631     threadLock = debugMonitorCreate("JDWP Thread Lock");
 632     if (gdata->threadClass==NULL) {
 633         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class");
 634     }
 635     if (gdata->threadResume==0) {
 636         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread");
 637     }
 638     /* Get the java.lang.Thread.resume() method beginning location */
 639     error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
 640     if (error != JVMTI_ERROR_NONE) {
 641         EXIT_ERROR(error, "getting method location");
 642     }
 643 }
 644 
 645 static jthread
 646 getResumee(jthread resumingThread)
 647 {
 648     jthread resumee = NULL;
 649     jvmtiError error;

 668     list = &runningThreads;
 669     node = list->first;
 670     while (node != NULL) {
 671         if (node->resumeFrameDepth > 0) {
 672             if (includeSuspended) {
 673                 return JNI_TRUE;
 674             } else {
 675                 jvmtiError error;
 676                 jint       state;
 677 
 678                 error = threadState(node->thread, &state);
 679                 if (error != JVMTI_ERROR_NONE) {
 680                     EXIT_ERROR(error, "getting thread state");
 681                 }
 682                 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
 683                     return JNI_TRUE;
 684                 }
 685             }
 686         }
 687         node = node->next;





 688     }
 689     return JNI_FALSE;
 690 }
 691 
 692 static void
 693 notifyAppResumeComplete(void)
 694 {
 695     debugMonitorNotifyAll(threadLock);
 696     if (!pendingAppResume(JNI_TRUE)) {
 697         if (framePopHandlerNode != NULL) {
 698             (void)eventHandler_free(framePopHandlerNode);
 699             framePopHandlerNode = NULL;
 700         }
 701         if (catchHandlerNode != NULL) {
 702             (void)eventHandler_free(catchHandlerNode);
 703             catchHandlerNode = NULL;
 704         }
 705     }
 706 }
 707 
 708 /*
 709  * Event handler for FRAME_POP and EXCEPTION_CATCH when in Thread.resume()
 710  * so we can detect its completion.
 711  */
 712 static void
 713 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
 714                           HandlerNode *handlerNode,
 715                           struct bag *eventBag)
 716 {
 717     ThreadNode *node;
 718     jthread     thread;
 719 
 720     thread = evinfo->thread;
 721 
 722     debugMonitorEnter(threadLock);
 723 
 724     node = findThread(&runningThreads, thread);
 725     if (node != NULL) {
 726         if (node->resumeFrameDepth > 0) {
 727             jint compareDepth = getStackDepth(thread);
 728             if (evinfo->ei == EI_FRAME_POP) {
 729                 compareDepth--;
 730             }
 731             if (compareDepth < node->resumeFrameDepth) {
 732                 node->resumeFrameDepth = 0;
 733                 notifyAppResumeComplete();
 734             }
 735         }
 736     }
 737 
 738     debugMonitorExit(threadLock);
 739 }
 740 
 741 static void
 742 blockOnDebuggerSuspend(jthread thread)
 743 {
 744     ThreadNode *node;
 745 
 746     node = findThread(NULL, thread);
 747     if (node != NULL) {
 748         while (node && node->suspendCount > 0) {
 749             debugMonitorWait(threadLock);
 750             node = findThread(NULL, thread);
 751         }
 752     }
 753 }
 754 
 755 static void
 756 trackAppResume(jthread thread)
 757 {
 758     jvmtiError  error;
 759     FrameNumber fnum;
 760     ThreadNode *node;
 761 
 762     fnum = 0;
 763     node = findThread(&runningThreads, thread);
 764     if (node != NULL) {
 765         JDI_ASSERT(node->resumeFrameDepth == 0);
 766         error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
 767                         (gdata->jvmti, thread, fnum);
 768         if (error == JVMTI_ERROR_NONE) {
 769             jint frameDepth = getStackDepth(thread);
 770             if ((frameDepth > 0) && (framePopHandlerNode == NULL)) {
 771                 framePopHandlerNode = eventHandler_createInternalThreadOnly(
 772                                            EI_FRAME_POP,
 773                                            handleAppResumeCompletion,
 774                                            thread);
 775                 catchHandlerNode = eventHandler_createInternalThreadOnly(
 776                                            EI_EXCEPTION_CATCH,
 777                                            handleAppResumeCompletion,
 778                                            thread);
 779                 if ((framePopHandlerNode == NULL) ||
 780                     (catchHandlerNode == NULL)) {
 781                     (void)eventHandler_free(framePopHandlerNode);
 782                     framePopHandlerNode = NULL;
 783                     (void)eventHandler_free(catchHandlerNode);

1031     if (node->suspendCount > 0) {
1032         node->suspendCount--;
1033         debugMonitorNotifyAll(threadLock);
1034         if ((node->suspendCount == 0) && node->toBeResumed &&
1035             !node->suspendOnStart) {
1036             LOG_MISC(("thread=%p resumed", node->thread));
1037             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
1038                         (gdata->jvmti, node->thread);
1039             node->frameGeneration++; /* Increment on each resume */
1040             node->toBeResumed = JNI_FALSE;
1041             if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
1042                 /*
1043                  * We successfully "suspended" this thread, but
1044                  * we never received a THREAD_START event for it.
1045                  * Since the thread never ran, we can ignore our
1046                  * failure to resume the thread.
1047                  */
1048                 error = JVMTI_ERROR_NONE;
1049             }
1050         }

1051     }
1052 
1053     return error;
1054 }
1055 
1056 /*
1057  * Functions which respond to user requests to suspend/resume
1058  * threads.
1059  * Suspends and resumes add and subtract from a count respectively.
1060  * The thread is only suspended when the count goes from 0 to 1 and
1061  * resumed only when the count goes from 1 to 0.
1062  *
1063  * These functions suspend and resume application threads
1064  * without changing the
1065  * state of threads that were already suspended beforehand.
1066  * They must not be called from an application thread because
1067  * that thread may be suspended somewhere in the  middle of things.
1068  */
1069 static void
1070 preSuspend(void)

1095         debugMonitorExit(threadLock);
1096 
1097         getLocks();
1098     }
1099 }
1100 
1101 static void
1102 postSuspend(void)
1103 {
1104     releaseLocks();
1105 }
1106 
1107 /*
1108  * This function must be called after preSuspend and before postSuspend.
1109  */
1110 static jvmtiError
1111 commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1112 {
1113     ThreadNode *node;
1114 
1115     /*
1116      * If the thread is not between its start and end events, we should
1117      * still suspend it. To keep track of things, add the thread
1118      * to a separate list of threads so that we'll resume it later.
1119      */
1120     node = findThread(&runningThreads, thread);













1121 #if 0
1122     tty_message("commonSuspend: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1123 #endif
1124     if (node == NULL) {
1125         node = insertThread(env, &otherThreads, thread);
1126     }
1127 
1128     if ( deferred ) {
1129         return deferredSuspendThreadByNode(node);
1130     } else {
1131         return suspendThreadByNode(node);
1132     }
1133 }
1134 
1135 
1136 static jvmtiError
1137 resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1138 {
1139     if (node->isDebugThread) {
1140         /* never suspended by debugger => don't ever try to resume */
1141         return JVMTI_ERROR_NONE;
1142     }
1143 
1144     if (node->suspendCount > 1) {
1145         node->suspendCount--;
1146         /* nested suspend so just undo one level */
1147         return JVMTI_ERROR_NONE;
1148     }
1149 
1150     /*
1151      * This thread was marked for suspension since its THREAD_START
1152      * event came in during a suspendAll, but the helper hasn't
1153      * completed the job yet. We decrement the count so the helper
1154      * won't suspend this thread after we are done with the resumeAll.
1155      * Another case to be handled here is when the debugger suspends
1156      * the thread while the app has it suspended. In this case,
1157      * the toBeResumed flag has been cleared indicating that
1158      * the thread should not be resumed when the debugger does a resume.
1159      * In this case, we also have to decrement the suspend count.
1160      * If we don't then when the app resumes the thread and our Thread.resume
1161      * bkpt handler is called, blockOnDebuggerSuspend will not resume
1162      * the thread because suspendCount will be 1 meaning that the
1163      * debugger has the thread suspended.  See bug 6224859.
1164      */
1165     if (node->suspendCount == 1 && (!node->toBeResumed || node->suspendOnStart)) {
1166         node->suspendCount--;

1167         return JVMTI_ERROR_NONE;
1168     }
1169 
1170     if (arg == NULL) {
1171         /* nothing to hard resume so we're done */
1172         return JVMTI_ERROR_NONE;
1173     }
1174 
1175     /*
1176      * This is tricky. A suspendCount of 1 and toBeResumed means that
1177      * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1178      * on this thread. The check for !suspendOnStart is paranoia that
1179      * we inherited from resumeThreadByNode().
1180      */
1181     if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1182         jthread **listPtr = (jthread **)arg;
1183 
1184         **listPtr = node->thread;
1185         (*listPtr)++;
1186     }

1248  * in resumeCountHelper(), but then resumeCopyHelper() would see
1249  * "post-resume" state in the accounting values (suspendCount and
1250  * toBeResumed) and would not be able to distinguish between a thread
1251  * that needs a hard resume versus a thread that is already running.
1252  */
1253 static jvmtiError
1254 commonResumeList(JNIEnv *env)
1255 {
1256     jvmtiError   error;
1257     jint         i;
1258     jint         reqCnt;
1259     jthread     *reqList;
1260     jthread     *reqPtr;
1261     jvmtiError  *results;
1262 
1263     reqCnt = 0;
1264 
1265     /* count number of threads to hard resume */
1266     (void) enumerateOverThreadList(env, &runningThreads, resumeCountHelper,
1267                                    &reqCnt);


1268     if (reqCnt == 0) {
1269         /* nothing to hard resume so do just the accounting part */
1270         (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1271                                        NULL);


1272         return JVMTI_ERROR_NONE;
1273     }
1274 
1275     /*LINTED*/
1276     reqList = newArray(reqCnt, sizeof(jthread));
1277     if (reqList == NULL) {
1278         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume request list");
1279     }
1280     /*LINTED*/
1281     results = newArray(reqCnt, sizeof(jvmtiError));
1282     if (results == NULL) {
1283         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume list");
1284     }
1285 
1286     /* copy the jthread values for threads to hard resume */
1287     reqPtr = reqList;
1288     (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1289                                    &reqPtr);


1290 
1291     error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThreadList)
1292                 (gdata->jvmti, reqCnt, reqList, results);
1293     for (i = 0; i < reqCnt; i++) {
1294         ThreadNode *node;
1295 
1296         node = findThread(&runningThreads, reqList[i]);
1297         if (node == NULL) {
1298             EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in running thread table");
1299         }
1300         LOG_MISC(("thread=%p resumed as part of list", node->thread));
1301 
1302         /*
1303          * resumeThreadByNode() assumes that JVM/DI ResumeThread()
1304          * always works and does all the accounting updates. We do
1305          * the same here. We also don't clear the error.
1306          */
1307         node->suspendCount--;
1308         node->toBeResumed = JNI_FALSE;
1309         node->frameGeneration++; /* Increment on each resume */


1310     }
1311     deleteArray(results);
1312     deleteArray(reqList);
1313 
1314     debugMonitorNotifyAll(threadLock);
1315 
1316     return error;
1317 }
1318 
1319 
1320 /*
1321  * This function must be called after preSuspend and before postSuspend.
1322  */
1323 static jvmtiError
1324 commonSuspendList(JNIEnv *env, jint initCount, jthread *initList)
1325 {
1326     jvmtiError  error;
1327     jint        i;
1328     jint        reqCnt;
1329     jthread    *reqList;

1485     eventHandler_lock(); /* for proper lock order */
1486     debugMonitorEnter(threadLock);
1487     error = commonResume(thread);
1488     removeResumed(env, &otherThreads);
1489     debugMonitorExit(threadLock);
1490     eventHandler_unlock();
1491 
1492     if (do_unblock) {
1493         /* let eventHelper.c: commandLoop() know we resumed one thread */
1494         unblockCommandLoop();
1495     }
1496 
1497     return error;
1498 }
1499 
1500 jvmtiError
1501 threadControl_suspendCount(jthread thread, jint *count)
1502 {
1503     jvmtiError  error;
1504     ThreadNode *node;

1505 
1506     debugMonitorEnter(threadLock);
1507 
1508     node = findThread(&runningThreads, thread);




1509     if (node == NULL) {
1510         node = findThread(&otherThreads, thread);
1511     }
1512 
1513     error = JVMTI_ERROR_NONE;
1514     if (node != NULL) {
1515         *count = node->suspendCount;
1516     } else {
1517         /*
1518          * If the node is in neither list, the debugger never suspended
1519          * this thread, so the suspend count is 0.
1520          */














1521         *count = 0;

1522     }
1523 
1524     debugMonitorExit(threadLock);
1525 
1526     return error;
1527 }
1528 
1529 static jboolean
1530 contains(JNIEnv *env, jthread *list, jint count, jthread item)
1531 {
1532     int i;
1533 
1534     for (i = 0; i < count; i++) {
1535         if (isSameObject(env, list[i], item)) {
1536             return JNI_TRUE;
1537         }
1538     }
1539     return JNI_FALSE;
1540 }
1541 
1542 








1543 typedef struct {
1544     jthread *list;
1545     jint count;
1546 } SuspendAllArg;
1547 
1548 static jvmtiError
1549 suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1550 {
1551     SuspendAllArg *saArg = (SuspendAllArg *)arg;
1552     jvmtiError error = JVMTI_ERROR_NONE;
1553     jthread *list = saArg->list;
1554     jint count = saArg->count;
1555     if (!contains(env, list, count, node->thread)) {
1556         error = commonSuspend(env, node->thread, JNI_FALSE);
1557     }
1558     return error;
1559 }
1560 
1561 jvmtiError
1562 threadControl_suspendAll(void)

1564     jvmtiError error;
1565     JNIEnv    *env;
1566 #if 0
1567     tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount);
1568 #endif
1569 
1570     env = getEnv();
1571 
1572     log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0);
1573 
1574     preSuspend();
1575 
1576     /*
1577      * Get a list of all threads and suspend them.
1578      */
1579     WITH_LOCAL_REFS(env, 1) {
1580 
1581         jthread *threads;
1582         jint count;
1583 




















1584         threads = allThreads(&count);
1585         if (threads == NULL) {
1586             error = AGENT_ERROR_OUT_OF_MEMORY;
1587             goto err;
1588         }
1589         error = commonSuspendList(env, count, threads);
1590         if (error != JVMTI_ERROR_NONE) {
1591             goto err;
1592         }
1593 
1594         /*
1595          * Update the suspend count of any threads not yet (or no longer)
1596          * in the thread list above.
1597          */
1598         {
1599             SuspendAllArg arg;
1600             arg.list = threads;
1601             arg.count = count;
1602             error = enumerateOverThreadList(env, &otherThreads,
1603                                             suspendAllHelper, &arg);

1617         jvmtiDeallocate(threads);
1618 
1619     } END_WITH_LOCAL_REFS(env)
1620 
1621     postSuspend();
1622 
1623     return error;
1624 }
1625 
1626 static jvmtiError
1627 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1628 {
1629     /*
1630      * Since this helper is called with the threadLock held, we
1631      * don't need to recheck to see if the node is still on one
1632      * of the two thread lists.
1633      */
1634     return resumeThreadByNode(node);
1635 }
1636 























1637 jvmtiError
1638 threadControl_resumeAll(void)
1639 {
1640     jvmtiError error;
1641     JNIEnv    *env;
1642 #if 0
1643     tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount);
1644 #endif
1645 
1646     env = getEnv();
1647 
1648     log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1649 
1650     eventHandler_lock(); /* for proper lock order */
1651     debugMonitorEnter(threadLock);
1652 

































1653     /*
1654      * Resume only those threads that the debugger has suspended. All
1655      * such threads must have a node in one of the thread lists, so there's
1656      * no need to get the whole thread list from JVMTI (unlike
1657      * suspendAll).
1658      */
1659     error = commonResumeList(env);
1660     if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1661         error = enumerateOverThreadList(env, &otherThreads,
1662                                         resumeHelper, NULL);
1663         removeResumed(env, &otherThreads);
1664     }
1665 
1666     if (suspendAllCount > 0) {
1667         /*
1668          * Unpin all objects.
1669          */
1670         commonRef_unpinAll();
1671 
1672         suspendAllCount--;

1674 
1675     debugMonitorExit(threadLock);
1676     eventHandler_unlock();
1677     /* let eventHelper.c: commandLoop() know we are resuming */
1678     unblockCommandLoop();
1679 
1680     return error;
1681 }
1682 
1683 
1684 StepRequest *
1685 threadControl_getStepRequest(jthread thread)
1686 {
1687     ThreadNode  *node;
1688     StepRequest *step;
1689 
1690     step = NULL;
1691 
1692     debugMonitorEnter(threadLock);
1693 
1694     node = findThread(&runningThreads, thread);
1695     if (node != NULL) {
1696         step = &node->currentStep;
1697     }
1698 
1699     debugMonitorExit(threadLock);
1700 
1701     return step;
1702 }
1703 
1704 InvokeRequest *
1705 threadControl_getInvokeRequest(jthread thread)
1706 {
1707     ThreadNode    *node;
1708     InvokeRequest *request;
1709 
1710     request = NULL;
1711 
1712     debugMonitorEnter(threadLock);
1713 
1714     node = findThread(&runningThreads, thread);
1715     if (node != NULL) {
1716          request = &node->currentInvoke;
1717     }
1718 
1719     debugMonitorExit(threadLock);
1720 
1721     return request;
1722 }
1723 
1724 jvmtiError
1725 threadControl_addDebugThread(jthread thread)
1726 {
1727     jvmtiError error;
1728 
1729     debugMonitorEnter(threadLock);
1730     if (debugThreadCount >= MAX_DEBUG_THREADS) {
1731         error = AGENT_ERROR_OUT_OF_MEMORY;
1732     } else {
1733         JNIEnv    *env;
1734 

2060                                EI_SINGLE_STEP, thread);
2061 
2062     return error;
2063 }
2064 
2065 /* Check to see if any events are being consumed by a popFrame(). */
2066 static jboolean
2067 checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread)
2068 {
2069     if ( getPopFrameThread(thread) ) {
2070         switch (ei) {
2071             case EI_THREAD_START:
2072                 /* Excuse me? */
2073                 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame");
2074                 break;
2075             case EI_THREAD_END:
2076                 /* Thread wants to end? let it. */
2077                 setPopFrameThread(thread, JNI_FALSE);
2078                 popFrameCompleteEvent(thread);
2079                 break;




2080             case EI_SINGLE_STEP:
2081                 /* This is an event we requested to mark the */
2082                 /*        completion of the pop frame */
2083                 popFrameCompleteEvent(thread);
2084                 return JNI_TRUE;
2085             case EI_BREAKPOINT:
2086             case EI_EXCEPTION:
2087             case EI_FIELD_ACCESS:
2088             case EI_FIELD_MODIFICATION:
2089             case EI_METHOD_ENTRY:
2090             case EI_METHOD_EXIT:
2091                 /* Tell event handler to assume event has been consumed. */
2092                 return JNI_TRUE;
2093             default:
2094                 break;
2095         }
2096     }
2097     /* Pretend we were never called */
2098     return JNI_FALSE;
2099 }

2132      * Check the list of unknown threads maintained by suspend
2133      * and resume. If this thread is currently present in the
2134      * list, it should be
2135      * moved to the runningThreads list, since it is a
2136      * well-known thread now.
2137      */
2138     node = findThread(&otherThreads, thread);
2139     if (node != NULL) {
2140         moveNode(&otherThreads, &runningThreads, node);
2141         /* Now that we know the thread has started, we can set its TLS.*/
2142         setThreadLocalStorage(thread, (void*)node);
2143     } else {
2144         /*
2145          * Get a thread node for the reporting thread. For thread start
2146          * events, or if this event precedes a thread start event,
2147          * the thread node may need to be created.
2148          *
2149          * It is possible for certain events (notably method entry/exit)
2150          * to precede thread start for some VM implementations.
2151          */
2152         node = insertThread(env, &runningThreads, thread);








2153     }
2154 
2155     if (ei == EI_THREAD_START) {
2156         node->isStarted = JNI_TRUE;
2157         processDeferredEventModes(env, thread, node);
2158     }
2159 
2160     node->current_ei = ei;
2161     eventBag = node->eventBag;
2162     if (node->suspendOnStart) {
2163         threadToSuspend = node->thread;
2164     }
2165     debugMonitorExit(threadLock);
2166 
2167     if (threadToSuspend != NULL) {
2168         /*
2169          * An attempt was made to suspend this thread before it started.
2170          * We must suspend it now, before it starts to run. This must
2171          * be done with no locks held.
2172          */
2173         eventHelper_suspendThread(sessionID, threadToSuspend);
2174     }
2175 

2198         /*
2199          * TO DO: Log error
2200          */
2201         tossGlobalRef(env, &(node->pendingStop));
2202     }
2203 }
2204 
2205 void
2206 threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
2207                                  struct bag *eventBag)
2208 {
2209     ThreadNode *node;
2210 
2211     log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0);
2212 
2213     if (ei == EI_THREAD_END) {
2214         eventHandler_lock(); /* for proper lock order */
2215     }
2216     debugMonitorEnter(threadLock);
2217 
2218     node = findThread(&runningThreads, thread);
2219     if (node == NULL) {
2220         EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2221     } else {
2222         JNIEnv *env;
2223 
2224         env = getEnv();
2225         if (ei == EI_THREAD_END) {
2226             jboolean inResume = (node->resumeFrameDepth > 0);
2227             removeThread(env, &runningThreads, thread);




2228             node = NULL;   /* has been freed */
2229 
2230             /*
2231              * Clean up mechanism used to detect end of
2232              * resume.
2233              */
2234             if (inResume) {
2235                 notifyAppResumeComplete();
2236             }
2237         } else {
2238             /* No point in doing this if the thread is about to die.*/
2239             doPendingTasks(env, node);
2240             node->eventBag = eventBag;
2241             node->current_ei = 0;
2242         }
2243     }
2244 
2245     debugMonitorExit(threadLock);
2246     if (ei == EI_THREAD_END) {
2247         eventHandler_unlock();

2249 }
2250 
2251 /* Returns JDWP flavored status and status flags. */
2252 jvmtiError
2253 threadControl_applicationThreadStatus(jthread thread,
2254                         jdwpThreadStatus *pstatus, jint *statusFlags)
2255 {
2256     ThreadNode *node;
2257     jvmtiError  error;
2258     jint        state;
2259 
2260     log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2261 
2262     debugMonitorEnter(threadLock);
2263 
2264     error = threadState(thread, &state);
2265     *pstatus = map2jdwpThreadStatus(state);
2266     *statusFlags = map2jdwpSuspendStatus(state);
2267 
2268     if (error == JVMTI_ERROR_NONE) {
2269         node = findThread(&runningThreads, thread);
2270         if ((node != NULL) && HANDLING_EVENT(node)) {
2271             /*
2272              * While processing an event, an application thread is always
2273              * considered to be running even if its handler happens to be
2274              * cond waiting on an internal debugger monitor, etc.
2275              *
2276              * Leave suspend status untouched since it is not possible
2277              * to distinguish debugger suspends from app suspends.
2278              */
2279             *pstatus = JDWP_THREAD_STATUS(RUNNING);
2280         }
2281     }





2282 
2283     debugMonitorExit(threadLock);
2284 
2285     return error;
2286 }
2287 
2288 jvmtiError
2289 threadControl_interrupt(jthread thread)
2290 {
2291     ThreadNode *node;
2292     jvmtiError  error;
2293 



2294     error = JVMTI_ERROR_NONE;
2295 
2296     log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2297 
2298     debugMonitorEnter(threadLock);
2299 
2300     node = findThread(&runningThreads, thread);
2301     if ((node == NULL) || !HANDLING_EVENT(node)) {
2302         error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2303                         (gdata->jvmti, thread);
2304     } else {
2305         /*
2306          * Hold any interrupts until after the event is processed.
2307          */
2308         node->pendingInterrupt = JNI_TRUE;
2309     }
2310 
2311     debugMonitorExit(threadLock);
2312 
2313     return error;
2314 }
2315 
2316 void
2317 threadControl_clearCLEInfo(JNIEnv *env, jthread thread)
2318 {
2319     ThreadNode *node;
2320 
2321     debugMonitorEnter(threadLock);
2322 
2323     node = findThread(&runningThreads, thread);
2324     if (node != NULL) {
2325         node->cleInfo.ei = 0;
2326         if (node->cleInfo.clazz != NULL) {
2327             tossGlobalRef(env, &(node->cleInfo.clazz));
2328         }
2329     }
2330 
2331     debugMonitorExit(threadLock);
2332 }
2333 
2334 jboolean
2335 threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz,
2336                          jmethodID method, jlocation location)
2337 {
2338     ThreadNode *node;
2339     jboolean    result;
2340 
2341     result = JNI_FALSE;
2342 
2343     debugMonitorEnter(threadLock);
2344 
2345     node = findThread(&runningThreads, thread);
2346     if (node != NULL && node->cleInfo.ei != 0 &&
2347         node->cleInfo.method == method &&
2348         node->cleInfo.location == location &&
2349         (isSameObject(env, node->cleInfo.clazz, clazz))) {
2350         result = JNI_TRUE; /* we have a match */
2351     }
2352 
2353     debugMonitorExit(threadLock);
2354 
2355     return result;
2356 }
2357 
2358 void
2359 threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
2360                           jclass clazz, jmethodID method, jlocation location)
2361 {
2362     ThreadNode *node;
2363 
2364     debugMonitorEnter(threadLock);
2365 
2366     node = findThread(&runningThreads, thread);
2367     if (node != NULL) {
2368         node->cleInfo.ei = ei;
2369         /* Create a class ref that will live beyond */
2370         /* the end of this call */
2371         saveGlobalRef(env, clazz, &(node->cleInfo.clazz));
2372         /* if returned clazz is NULL, we just won't match */
2373         node->cleInfo.method    = method;
2374         node->cleInfo.location  = location;
2375     }
2376 
2377     debugMonitorExit(threadLock);
2378 }
2379 
2380 void
2381 threadControl_setPendingInterrupt(jthread thread)
2382 {
2383     ThreadNode *node;
2384 



2385     debugMonitorEnter(threadLock);
2386 
2387     node = findThread(&runningThreads, thread);
2388     if (node != NULL) {
2389         node->pendingInterrupt = JNI_TRUE;
2390     }
2391 
2392     debugMonitorExit(threadLock);
2393 }
2394 
2395 jvmtiError
2396 threadControl_stop(jthread thread, jobject throwable)
2397 {
2398     ThreadNode *node;
2399     jvmtiError  error;
2400 



2401     error = JVMTI_ERROR_NONE;
2402 
2403     log_debugee_location("threadControl_stop()", thread, NULL, 0);
2404 
2405     debugMonitorEnter(threadLock);
2406 
2407     node = findThread(&runningThreads, thread);
2408     if ((node == NULL) || !HANDLING_EVENT(node)) {
2409         error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2410                         (gdata->jvmti, thread, throwable);
2411     } else {
2412         JNIEnv *env;
2413 
2414         /*
2415          * Hold any stops until after the event is processed.
2416          */
2417         env = getEnv();
2418         saveGlobalRef(env, throwable, &(node->pendingStop));
2419     }
2420 

2450         LOG_MISC(("thread=%p resumed", node->thread));
2451         (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, node->thread);
2452         node->frameGeneration++; /* Increment on each resume */
2453     }
2454     stepControl_clearRequest(node->thread, &node->currentStep);
2455     node->toBeResumed = JNI_FALSE;
2456     node->suspendCount = 0;
2457     node->suspendOnStart = JNI_FALSE;
2458 
2459     return JVMTI_ERROR_NONE;
2460 }
2461 
2462 void
2463 threadControl_reset(void)
2464 {
2465     JNIEnv *env;
2466 
2467     env = getEnv();
2468     eventHandler_lock(); /* for proper lock order */
2469     debugMonitorEnter(threadLock);












2470     (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2471     (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);

2472 
2473     removeResumed(env, &otherThreads);
2474 
2475     freeDeferredEventModes(env);
2476 
2477     suspendAllCount = 0;
2478 
2479     /* Everything should have been resumed */
2480     JDI_ASSERT(otherThreads.first == NULL);
2481 
2482     debugMonitorExit(threadLock);
2483     eventHandler_unlock();
2484 }
2485 
2486 jvmtiEventMode
2487 threadControl_getInstructionStepMode(jthread thread)
2488 {
2489     ThreadNode    *node;
2490     jvmtiEventMode mode;
2491 
2492     mode = JVMTI_DISABLE;
2493 
2494     debugMonitorEnter(threadLock);
2495     node = findThread(&runningThreads, thread);
2496     if (node != NULL) {
2497         mode = node->instructionStepMode;
2498     }
2499     debugMonitorExit(threadLock);
2500     return mode;
2501 }
2502 
2503 jvmtiError
2504 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2505 {
2506     jvmtiError error;
2507 
2508     /* Global event */
2509     if ( thread == NULL ) {
2510         error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2511                     (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2512     } else {
2513         /* Thread event */
2514         ThreadNode *node;
2515 
2516         debugMonitorEnter(threadLock);
2517         {
2518             node = findThread(&runningThreads, thread);
2519             if ((node == NULL) || (!node->isStarted)) {
2520                 JNIEnv *env;
2521 
2522                 env = getEnv();
2523                 error = addDeferredEventMode(env, mode, ei, thread);
2524             } else {
2525                 error = threadSetEventNotificationMode(node,
2526                         mode, ei, thread);
2527             }
2528         }
2529         debugMonitorExit(threadLock);
2530 
2531     }
2532     return error;
2533 }
2534 
2535 /*
2536  * Returns the current thread, if the thread has generated at least
2537  * one event, and has not generated a thread end event.
2538  */

2556 jlong
2557 threadControl_getFrameGeneration(jthread thread)
2558 {
2559     jlong frameGeneration = -1;
2560 
2561     debugMonitorEnter(threadLock);
2562     {
2563         ThreadNode *node;
2564 
2565         node = findThread(NULL, thread);
2566 
2567         if (node != NULL) {
2568             frameGeneration = node->frameGeneration;
2569         }
2570     }
2571     debugMonitorExit(threadLock);
2572 
2573     return frameGeneration;
2574 }
2575 
















































2576 /***** debugging *****/
2577 
2578 #ifdef DEBUG
2579 
2580 void
2581 threadControl_dumpAllThreads()
2582 {
2583     tty_message("Dumping runningThreads:\n");
2584     dumpThreadList(&runningThreads);
2585     tty_message("Dumping otherThreads:\n");


2586     dumpThreadList(&otherThreads);
2587 }
2588 
2589 void
2590 threadControl_dumpThread(jthread thread)
2591 {
2592     ThreadNode* node = findThread(NULL, thread);
2593     if (node == NULL) {
2594         tty_message("Thread not found");
2595     } else {
2596         dumpThread(node);
2597     }
2598 }
2599 
2600 static void
2601 dumpThreadList(ThreadList *list)
2602 {
2603     ThreadNode *node;
2604     for (node = list->first; node != NULL; node = node->next) {
2605         if (!node->isDebugThread) {

  52 /**
  53  * The main data structure in threadControl is the ThreadNode.
  54  * This is a per-thread structure that is allocated on the
  55  * first event that occurs in a thread. It is freed after the
  56  * thread's thread end event has completed processing. The
  57  * structure contains state information on its thread including
  58  * suspend counts. It also acts as a repository for other
  59  * per-thread state such as the current method invocation or
  60  * current step.
  61  *
  62  * suspendCount is the number of outstanding suspends
  63  * from the debugger. suspends from the app itself are
  64  * not included in this count.
  65  */
  66 typedef struct ThreadNode {
  67     jthread thread;
  68     unsigned int toBeResumed : 1;      /* true if this thread was successfully suspended. */
  69     unsigned int pendingInterrupt : 1; /* true if thread is interrupted while handling an event. */
  70     unsigned int isDebugThread : 1;    /* true if this is one of our debug agent threads. */
  71     unsigned int suspendOnStart : 1;   /* true for new threads if we are currently in a VM.suspend(). */
  72     unsigned int isStarted : 1;        /* THREAD_START or VIRTUAL_THREAD_START event received. */
  73     unsigned int is_vthread : 1;
  74     unsigned int popFrameEvent : 1;
  75     unsigned int popFrameProceed : 1;
  76     unsigned int popFrameThread : 1;
  77     EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */
  78     jobject pendingStop;   /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */
  79     jint suspendCount;
  80     jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */
  81     jvmtiEventMode instructionStepMode;
  82     StepRequest currentStep;
  83     InvokeRequest currentInvoke;
  84     struct bag *eventBag;       /* Accumulation of JDWP events to be sent as a reply. */
  85     CoLocatedEventInfo cleInfo; /* See comment above deferEventReport() for an explanation. */
  86     struct ThreadNode *next;
  87     struct ThreadNode *prev;
  88     jlong frameGeneration;    /* used to generate a unique frameID. Incremented whenever existing frameID
  89                                  needs to be invalidated, such as when the thread is resumed. */
  90     struct ThreadList *list;  /* Tells us what list this thread is in. */
  91 #ifdef DEBUG_THREADNAME
  92     char name[256];
  93 #endif

 108  * popFrameProceedLock is used to assure that the event thread is
 109  * re-suspended immediately after the event is acknowledged.
 110  */
 111 static jrawMonitorID popFrameProceedLock = NULL;
 112 
 113 static jrawMonitorID threadLock;
 114 static jlocation resumeLocation;
 115 static HandlerNode *breakpointHandlerNode;
 116 static HandlerNode *framePopHandlerNode;
 117 static HandlerNode *catchHandlerNode;
 118 
 119 static jvmtiError threadControl_removeDebugThread(jthread thread);
 120 
 121 /*
 122  * Threads which have issued thread start events and not yet issued thread
 123  * end events are maintained in the "runningThreads" list. All other threads known
 124  * to this module are kept in the "otherThreads" list.
 125  */
 126 static ThreadList runningThreads;
 127 static ThreadList otherThreads;
 128 static ThreadList runningVThreads; /* VThreads we have seen. */
 129 
 130 #define MAX_DEBUG_THREADS 10
 131 static int debugThreadCount;
 132 static jthread debugThreads[MAX_DEBUG_THREADS];
 133 
 134 typedef struct DeferredEventMode {
 135     EventIndex ei;
 136     jvmtiEventMode mode;
 137     jthread thread;
 138     struct DeferredEventMode *next;
 139 } DeferredEventMode;
 140 
 141 typedef struct {
 142     DeferredEventMode *first;
 143     DeferredEventMode *last;
 144 } DeferredEventModeList;
 145 
 146 static DeferredEventModeList deferredEventModes;
 147 
 148 #ifdef DEBUG

 214  *   It assumed that this logic is never dealing with terminated threads,
 215  *   since the ThreadEnd events always delete the ThreadNode while the
 216  *   jthread is still alive.  So we can only look at the ThreadNode's that
 217  *   have never had their TLS set, making the search much faster.
 218  *   But keep in mind, this kind of search should rarely be needed.
 219  */
 220 static ThreadNode *
 221 nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
 222 {
 223     ThreadNode *node;
 224 
 225     for (node = list->first; node != NULL; node = node->next) {
 226         if (isSameObject(env, node->thread, thread)) {
 227             break;
 228         }
 229     }
 230     return node;
 231 }
 232 
 233 /*
 234  * These functions maintain the linked list of currently running threads and vthreads.
 235  * All assume that the threadLock is held before calling.
 236  */
 237 
 238 /*
 239  * Search for a thread on the list. If list==NULL, search all lists.
 240  */
 241 static ThreadNode *
 242 findThread(ThreadList *list, jthread thread)
 243 {
 244     ThreadNode *node;
 245     JNIEnv *env = getEnv();
 246 
 247     /* Get thread local storage for quick thread -> node access */
 248     node = getThreadLocalStorage(thread);
 249 
 250     if ( node == NULL ) {
 251         /*
 252          * If the thread was not yet started when the ThreadNode was created, then it
 253          * got added to the otherThreads list and its thread local storage was not set.
 254          * Search for it in the otherThreads list.
 255          */
 256         if ( list == NULL || list == &otherThreads ) {
 257             node = nonTlsSearch(getEnv(), &otherThreads, thread);
 258         }
 259         /*
 260          * Normally we can assume that a thread with no TLS will never be in the runningThreads
 261          * list. This is because we always set the TLS when adding to runningThreads.
 262          * However, when a thread exits, its TLS is automatically cleared. Normally this
 263          * is not a problem because the debug agent will first get a THREAD_END event,
 264          * and that will cause the thread to be removed from runningThreads, thus we
 265          * avoid this situation of having a thread in runningThreads, but with no TLS.

 281         } else {
 282             /*
 283              * Search the runningThreads list. The TLS lookup may have failed because the
 284              * thread has terminated, but we never got the THREAD_END event.
 285              */
 286             if ( node == NULL ) {
 287                 if ( list == NULL || list == &runningThreads ) {
 288                     node = nonTlsSearch(getEnv(), &runningThreads, thread);
 289                 }
 290             }
 291         }
 292     }
 293 
 294     /* If a list is supplied, only return ones in this list */
 295     if ( node != NULL && list != NULL && node->list != list ) {
 296         return NULL;
 297     }
 298     return node;
 299 }
 300 
 301 /* Search for a running thread, including vthreads. */
 302 static ThreadNode *
 303 findRunningThread(jthread thread)
 304 {
 305     ThreadNode *node;
 306     if (isVThread(thread)) {
 307         node = findThread(&runningVThreads, thread);
 308     } else {
 309         node = findThread(&runningThreads, thread);
 310     }
 311     return node;
 312 }
 313 
 314 /* Remove a ThreadNode from a ThreadList */
 315 static void
 316 removeNode(ThreadList *list, ThreadNode *node)
 317 {
 318     ThreadNode *prev;
 319     ThreadNode *next;
 320 
 321     prev = node->prev;
 322     next = node->next;
 323     if ( prev != NULL ) {
 324         prev->next = next;
 325     }
 326     if ( next != NULL ) {
 327         next->prev = prev;
 328     }
 329     if ( prev == NULL ) {
 330         list->first = next;
 331     }
 332     node->next = NULL;
 333     node->prev = NULL;

 339 addNode(ThreadList *list, ThreadNode *node)
 340 {
 341     node->next = NULL;
 342     node->prev = NULL;
 343     node->list = NULL;
 344     if ( list->first == NULL ) {
 345         list->first = node;
 346     } else {
 347         list->first->prev = node;
 348         node->next = list->first;
 349         list->first = node;
 350     }
 351     node->list = list;
 352 }
 353 
 354 static ThreadNode *
 355 insertThread(JNIEnv *env, ThreadList *list, jthread thread)
 356 {
 357     ThreadNode *node;
 358     struct bag *eventBag;
 359     jboolean is_vthread = (list == &runningVThreads);
 360 
 361     node = findThread(list, thread);
 362     if (node == NULL) {
 363         node = jvmtiAllocate(sizeof(*node));
 364         if (node == NULL) {
 365             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 366             return NULL;
 367         }
 368         (void)memset(node, 0, sizeof(*node));
 369         eventBag = eventHelper_createEventBag();
 370         if (eventBag == NULL) {
 371             jvmtiDeallocate(node);
 372             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 373             return NULL;
 374         }
 375 
 376         /*
 377          * Init all flags false, all refs NULL, all counts 0
 378          */
 379 
 380         saveGlobalRef(env, thread, &(node->thread));
 381         if (node->thread == NULL) {
 382             jvmtiDeallocate(node);
 383             bagDestroyBag(eventBag);
 384             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 385             return NULL;
 386         }
 387         if (!is_vthread) {
 388             if (threadControl_isDebugThread(node->thread)) {
 389                 /* Remember if it is a debug thread */
 390                 node->isDebugThread = JNI_TRUE;
 391             } else {
 392                 if (suspendAllCount > 0) {
 393                     /*
 394                      * If there is a pending suspendAll, all new threads should
 395                      * be initialized as if they were suspended by the suspendAll,
 396                      * and the thread will need to be suspended when it starts.
 397                      */
 398                     node->suspendCount = suspendAllCount;
 399                     node->suspendOnStart = JNI_TRUE;
 400                 }
 401             }
 402         } else { /* vthread */
 403             jint vthread_state = 0;
 404             jvmtiError error = threadState(node->thread, &vthread_state);
 405             if (error != JVMTI_ERROR_NONE) {
 406                 EXIT_ERROR(error, "getting thread state");
 407             }
 408             if (suspendAllCount > 0) {
 409                 // Assume the suspendAllCount, just like the regular thread case above.
 410                 node->suspendCount = suspendAllCount;
 411                 if (vthread_state == 0) {
 412                     // If state == 0, then this is a new vthread that has not been started yet.
 413                     // Need to suspendOnStart in that case, just like the regular thread case above.
 414                     node->suspendOnStart = JNI_TRUE;
 415                     list = &otherThreads; // Put on otherThreads list instead of runningVThreads
 416                 }
 417             }
 418             if (vthread_state != 0) {
 419                 // This is an already started vthread that we were not already tracking.
 420                 node->isStarted = JNI_TRUE;
 421             }
 422         }
 423 
 424         node->current_ei = 0;
 425         node->is_vthread = is_vthread;
 426         node->instructionStepMode = JVMTI_DISABLE;
 427         node->eventBag = eventBag;
 428         addNode(list, node);
 429 
 430 #ifdef DEBUG_THREADNAME
 431         {
 432             /* Set the thread name */
 433             jvmtiThreadInfo info;
 434             jvmtiError error;
 435 
 436             memset(&info, 0, sizeof(info));
 437             error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
 438                     (gdata->jvmti, node->thread, &info);
 439             if (info.name != NULL) {
 440                 strncpy(node->name, info.name, sizeof(node->name) - 1);
 441                 jvmtiDeallocate(info.name);
 442             }
 443         }
 444 #endif
 445 

 488 
 489 static void
 490 removeResumed(JNIEnv *env, ThreadList *list)
 491 {
 492     ThreadNode *node;
 493 
 494     node = list->first;
 495     while (node != NULL) {
 496         ThreadNode *temp = node->next;
 497         if (node->suspendCount == 0) {
 498             removeThread(env, list, node->thread);
 499         }
 500         node = temp;
 501     }
 502 }
 503 
 504 static void
 505 moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node)
 506 {
 507     removeNode(source, node);
 508     // vthread fixme: we should really fix the caller to pass the right list
 509     if (node->is_vthread && dest == &runningThreads) {
 510         dest = &runningVThreads;
 511     }
 512     JDI_ASSERT(findThread(dest, node->thread) == NULL);
 513     addNode(dest, node);
 514 }
 515 
 516 typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);
 517 
 518 static jvmtiError
 519 enumerateOverThreadList(JNIEnv *env, ThreadList *list,
 520                         ThreadEnumerateFunction function, void *arg)
 521 {
 522     ThreadNode *node;
 523     jvmtiError error = JVMTI_ERROR_NONE;
 524 
 525     for (node = list->first; node != NULL; node = node->next) {
 526         error = (*function)(env, node, arg);
 527         if ( error != JVMTI_ERROR_NONE ) {
 528             break;
 529         }
 530     }
 531     return error;

 655 static void
 656 releaseLocks(void)
 657 {
 658     debugMonitorExit(threadLock);
 659     commonRef_unlock();
 660     stepControl_unlock();
 661     eventHelper_unlock();
 662     invoker_unlock();
 663     eventHandler_unlock();
 664 }
 665 
 666 void
 667 threadControl_initialize(void)
 668 {
 669     jlocation unused;
 670     jvmtiError error;
 671 
 672     suspendAllCount = 0;
 673     runningThreads.first = NULL;
 674     otherThreads.first = NULL;
 675     runningVThreads.first = NULL;
 676     debugThreadCount = 0;
 677     threadLock = debugMonitorCreate("JDWP Thread Lock");
 678     if (gdata->threadClass==NULL) {
 679         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class");
 680     }
 681     if (gdata->threadResume==0) {
 682         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread");
 683     }
 684     /* Get the java.lang.Thread.resume() method beginning location */
 685     error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
 686     if (error != JVMTI_ERROR_NONE) {
 687         EXIT_ERROR(error, "getting method location");
 688     }
 689 }
 690 
 691 static jthread
 692 getResumee(jthread resumingThread)
 693 {
 694     jthread resumee = NULL;
 695     jvmtiError error;

 714     list = &runningThreads;
 715     node = list->first;
 716     while (node != NULL) {
 717         if (node->resumeFrameDepth > 0) {
 718             if (includeSuspended) {
 719                 return JNI_TRUE;
 720             } else {
 721                 jvmtiError error;
 722                 jint       state;
 723 
 724                 error = threadState(node->thread, &state);
 725                 if (error != JVMTI_ERROR_NONE) {
 726                     EXIT_ERROR(error, "getting thread state");
 727                 }
 728                 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
 729                     return JNI_TRUE;
 730                 }
 731             }
 732         }
 733         node = node->next;
 734         if (node == NULL && list == &runningThreads) {
 735             // We need to look at runningVThreads after we are done with runningThreads.
 736             list = &runningVThreads;
 737             node = list->first;
 738         }
 739     }
 740     return JNI_FALSE;
 741 }
 742 
 743 static void
 744 notifyAppResumeComplete(void)
 745 {
 746     debugMonitorNotifyAll(threadLock);
 747     if (!pendingAppResume(JNI_TRUE)) {
 748         if (framePopHandlerNode != NULL) {
 749             (void)eventHandler_free(framePopHandlerNode);
 750             framePopHandlerNode = NULL;
 751         }
 752         if (catchHandlerNode != NULL) {
 753             (void)eventHandler_free(catchHandlerNode);
 754             catchHandlerNode = NULL;
 755         }
 756     }
 757 }
 758 
 759 /*
 760  * Event handler for FRAME_POP and EXCEPTION_CATCH when in Thread.resume()
 761  * so we can detect its completion.
 762  */
 763 static void
 764 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
 765                           HandlerNode *handlerNode,
 766                           struct bag *eventBag)
 767 {
 768     ThreadNode *node;
 769     jthread     thread;
 770 
 771     thread = evinfo->thread;
 772 
 773     debugMonitorEnter(threadLock);
 774 
 775     node = findRunningThread(thread);
 776     if (node != NULL) {
 777         if (node->resumeFrameDepth > 0) {
 778             jint compareDepth = getStackDepth(thread);
 779             if (evinfo->ei == EI_FRAME_POP) {
 780                 compareDepth--;
 781             }
 782             if (compareDepth < node->resumeFrameDepth) {
 783                 node->resumeFrameDepth = 0;
 784                 notifyAppResumeComplete();
 785             }
 786         }
 787     }
 788 
 789     debugMonitorExit(threadLock);
 790 }
 791 
 792 static void
 793 blockOnDebuggerSuspend(jthread thread)
 794 {
 795     ThreadNode *node;
 796 
 797     node = findThread(NULL, thread);
 798     if (node != NULL) {
 799         while (node && node->suspendCount > 0) {
 800             debugMonitorWait(threadLock);
 801             node = findThread(NULL, thread);
 802         }
 803     }
 804 }
 805 
 806 static void
 807 trackAppResume(jthread thread)
 808 {
 809     jvmtiError  error;
 810     FrameNumber fnum;
 811     ThreadNode *node;
 812 
 813     fnum = 0;
 814     node = findRunningThread(thread);
 815     if (node != NULL) {
 816         JDI_ASSERT(node->resumeFrameDepth == 0);
 817         error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
 818                         (gdata->jvmti, thread, fnum);
 819         if (error == JVMTI_ERROR_NONE) {
 820             jint frameDepth = getStackDepth(thread);
 821             if ((frameDepth > 0) && (framePopHandlerNode == NULL)) {
 822                 framePopHandlerNode = eventHandler_createInternalThreadOnly(
 823                                            EI_FRAME_POP,
 824                                            handleAppResumeCompletion,
 825                                            thread);
 826                 catchHandlerNode = eventHandler_createInternalThreadOnly(
 827                                            EI_EXCEPTION_CATCH,
 828                                            handleAppResumeCompletion,
 829                                            thread);
 830                 if ((framePopHandlerNode == NULL) ||
 831                     (catchHandlerNode == NULL)) {
 832                     (void)eventHandler_free(framePopHandlerNode);
 833                     framePopHandlerNode = NULL;
 834                     (void)eventHandler_free(catchHandlerNode);

1082     if (node->suspendCount > 0) {
1083         node->suspendCount--;
1084         debugMonitorNotifyAll(threadLock);
1085         if ((node->suspendCount == 0) && node->toBeResumed &&
1086             !node->suspendOnStart) {
1087             LOG_MISC(("thread=%p resumed", node->thread));
1088             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
1089                         (gdata->jvmti, node->thread);
1090             node->frameGeneration++; /* Increment on each resume */
1091             node->toBeResumed = JNI_FALSE;
1092             if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
1093                 /*
1094                  * We successfully "suspended" this thread, but
1095                  * we never received a THREAD_START event for it.
1096                  * Since the thread never ran, we can ignore our
1097                  * failure to resume the thread.
1098                  */
1099                 error = JVMTI_ERROR_NONE;
1100             }
1101         }
1102         // vthread fixme: If this is a vthread and suspendCount == 0, we should delete the node.
1103     }
1104 
1105     return error;
1106 }
1107 
1108 /*
1109  * Functions which respond to user requests to suspend/resume
1110  * threads.
1111  * Suspends and resumes add and subtract from a count respectively.
1112  * The thread is only suspended when the count goes from 0 to 1 and
1113  * resumed only when the count goes from 1 to 0.
1114  *
1115  * These functions suspend and resume application threads
1116  * without changing the
1117  * state of threads that were already suspended beforehand.
1118  * They must not be called from an application thread because
1119  * that thread may be suspended somewhere in the  middle of things.
1120  */
1121 static void
1122 preSuspend(void)

1147         debugMonitorExit(threadLock);
1148 
1149         getLocks();
1150     }
1151 }
1152 
1153 static void
1154 postSuspend(void)
1155 {
1156     releaseLocks();
1157 }
1158 
1159 /*
1160  * This function must be called after preSuspend and before postSuspend.
1161  */
1162 static jvmtiError
1163 commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1164 {
1165     ThreadNode *node;
1166 
1167     node = findRunningThread(thread);
1168 
1169     if (node == NULL) {
1170         if (isVThread(thread)) {
1171             /*
1172              * Since we don't track all vthreads, it might not be in the list already. Start
1173              * tracking it now.
1174              */
1175             node = insertThread(env, &runningVThreads, thread);
1176         } else {
1177             /*
1178              * If the thread is not between its start and end events, we should
1179              * still suspend it. To keep track of things, add the thread
1180              * to a separate list of threads so that we'll resume it later.
1181              */
1182             node = insertThread(env, &otherThreads, thread);
1183         }
1184     }
1185 
1186 #if 0
1187     tty_message("commonSuspend: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1188 #endif



1189 
1190     if ( deferred ) {
1191         return deferredSuspendThreadByNode(node);
1192     } else {
1193         return suspendThreadByNode(node);
1194     }
1195 }
1196 
1197 
1198 static jvmtiError
1199 resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1200 {
1201     if (node->isDebugThread) {
1202         /* never suspended by debugger => don't ever try to resume */
1203         return JVMTI_ERROR_NONE;
1204     }
1205 
1206     if (node->suspendCount > 1) {
1207         node->suspendCount--;
1208         /* nested suspend so just undo one level */
1209         return JVMTI_ERROR_NONE;
1210     }
1211 
1212     /*
1213      * This thread was marked for suspension since its THREAD_START
1214      * event came in during a suspendAll, but the helper hasn't
1215      * completed the job yet. We decrement the count so the helper
1216      * won't suspend this thread after we are done with the resumeAll.
1217      * Another case to be handled here is when the debugger suspends
1218      * the thread while the app has it suspended. In this case,
1219      * the toBeResumed flag has been cleared indicating that
1220      * the thread should not be resumed when the debugger does a resume.
1221      * In this case, we also have to decrement the suspend count.
1222      * If we don't then when the app resumes the thread and our Thread.resume
1223      * bkpt handler is called, blockOnDebuggerSuspend will not resume
1224      * the thread because suspendCount will be 1 meaning that the
1225      * debugger has the thread suspended.  See bug 6224859.
1226      */
1227     if (node->suspendCount == 1 && (!node->toBeResumed || node->suspendOnStart)) {
1228         node->suspendCount--;
1229         // vthread fixme: If this is a vthread, we should delete the node.
1230         return JVMTI_ERROR_NONE;
1231     }
1232 
1233     if (arg == NULL) {
1234         /* nothing to hard resume so we're done */
1235         return JVMTI_ERROR_NONE;
1236     }
1237 
1238     /*
1239      * This is tricky. A suspendCount of 1 and toBeResumed means that
1240      * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called
1241      * on this thread. The check for !suspendOnStart is paranoia that
1242      * we inherited from resumeThreadByNode().
1243      */
1244     if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) {
1245         jthread **listPtr = (jthread **)arg;
1246 
1247         **listPtr = node->thread;
1248         (*listPtr)++;
1249     }

1311  * in resumeCountHelper(), but then resumeCopyHelper() would see
1312  * "post-resume" state in the accounting values (suspendCount and
1313  * toBeResumed) and would not be able to distinguish between a thread
1314  * that needs a hard resume versus a thread that is already running.
1315  */
1316 static jvmtiError
1317 commonResumeList(JNIEnv *env)
1318 {
1319     jvmtiError   error;
1320     jint         i;
1321     jint         reqCnt;
1322     jthread     *reqList;
1323     jthread     *reqPtr;
1324     jvmtiError  *results;
1325 
1326     reqCnt = 0;
1327 
1328     /* count number of threads to hard resume */
1329     (void) enumerateOverThreadList(env, &runningThreads, resumeCountHelper,
1330                                    &reqCnt);
1331     (void) enumerateOverThreadList(env, &runningVThreads, resumeCountHelper,
1332                                    &reqCnt);
1333     if (reqCnt == 0) {
1334         /* nothing to hard resume so do just the accounting part */
1335         (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1336                                        NULL);
1337         (void) enumerateOverThreadList(env, &runningVThreads, resumeCopyHelper,
1338                                        NULL);
1339         return JVMTI_ERROR_NONE;
1340     }
1341 
1342     /*LINTED*/
1343     reqList = newArray(reqCnt, sizeof(jthread));
1344     if (reqList == NULL) {
1345         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume request list");
1346     }
1347     /*LINTED*/
1348     results = newArray(reqCnt, sizeof(jvmtiError));
1349     if (results == NULL) {
1350         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume list");
1351     }
1352 
1353     /* copy the jthread values for threads to hard resume */
1354     reqPtr = reqList;
1355     (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper,
1356                                    &reqPtr);
1357     (void) enumerateOverThreadList(env, &runningVThreads, resumeCopyHelper,
1358                                    &reqPtr);
1359 
1360     error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThreadList)
1361                 (gdata->jvmti, reqCnt, reqList, results);
1362     for (i = 0; i < reqCnt; i++) {
1363         ThreadNode *node;
1364 
1365         node = findRunningThread(reqList[i]);
1366         if (node == NULL) {
1367             EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in running thread table");
1368         }
1369         LOG_MISC(("thread=%p resumed as part of list", node->thread));
1370 
1371         /*
1372          * resumeThreadByNode() assumes that JVM/DI ResumeThread()
1373          * always works and does all the accounting updates. We do
1374          * the same here. We also don't clear the error.
1375          */
1376         node->suspendCount--;
1377         node->toBeResumed = JNI_FALSE;
1378         node->frameGeneration++; /* Increment on each resume */
1379 
1380         // vthread fixme: If this is a vthread, we should delete the node.
1381     }
1382     deleteArray(results);
1383     deleteArray(reqList);
1384 
1385     debugMonitorNotifyAll(threadLock);
1386 
1387     return error;
1388 }
1389 
1390 
1391 /*
1392  * This function must be called after preSuspend and before postSuspend.
1393  */
1394 static jvmtiError
1395 commonSuspendList(JNIEnv *env, jint initCount, jthread *initList)
1396 {
1397     jvmtiError  error;
1398     jint        i;
1399     jint        reqCnt;
1400     jthread    *reqList;

1556     eventHandler_lock(); /* for proper lock order */
1557     debugMonitorEnter(threadLock);
1558     error = commonResume(thread);
1559     removeResumed(env, &otherThreads);
1560     debugMonitorExit(threadLock);
1561     eventHandler_unlock();
1562 
1563     if (do_unblock) {
1564         /* let eventHelper.c: commandLoop() know we resumed one thread */
1565         unblockCommandLoop();
1566     }
1567 
1568     return error;
1569 }
1570 
1571 jvmtiError
1572 threadControl_suspendCount(jthread thread, jint *count)
1573 {
1574     jvmtiError  error;
1575     ThreadNode *node;
1576     jboolean is_vthread = isVThread(thread);
1577 
1578     debugMonitorEnter(threadLock);
1579 
1580     if (is_vthread) {
1581         node = findThread(&runningVThreads, thread);
1582     } else {
1583         node = findThread(&runningThreads, thread);
1584     }
1585     if (node == NULL) {
1586         node = findThread(&otherThreads, thread);
1587     }
1588 
1589     error = JVMTI_ERROR_NONE;
1590     if (node != NULL) {
1591         *count = node->suspendCount;
1592     } else {
1593         /*
1594          * If the node is in neither list, the debugger never suspended
1595          * this thread, so the suspend count is 0.
1596          */
1597       if (is_vthread) {
1598           jint vthread_state = 0;
1599           jvmtiError error = threadState(thread, &vthread_state);
1600           if (error != JVMTI_ERROR_NONE) {
1601               EXIT_ERROR(error, "getting thread state");
1602           }
1603           if (vthread_state == 0) {
1604               // If state == 0, then this is a new vthread that has not been started yet.
1605               *count = 0;
1606           } else {
1607               // This is a started vthread that we are not tracking. Use suspendAllCount.
1608               *count = suspendAllCount;
1609           }
1610       } else {
1611         *count = 0;
1612       }
1613     }
1614 
1615     debugMonitorExit(threadLock);
1616 
1617     return error;
1618 }
1619 
1620 static jboolean
1621 contains(JNIEnv *env, jthread *list, jint count, jthread item)
1622 {
1623     int i;
1624 
1625     for (i = 0; i < count; i++) {
1626         if (isSameObject(env, list[i], item)) {
1627             return JNI_TRUE;
1628         }
1629     }
1630     return JNI_FALSE;
1631 }
1632 
1633 
1634 static jvmtiError
1635 incrementSuspendCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1636 {
1637     node->toBeResumed = JNI_TRUE;
1638     node->suspendCount++;
1639     return JVMTI_ERROR_NONE;
1640 }
1641 
1642 typedef struct {
1643     jthread *list;
1644     jint count;
1645 } SuspendAllArg;
1646 
1647 static jvmtiError
1648 suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1649 {
1650     SuspendAllArg *saArg = (SuspendAllArg *)arg;
1651     jvmtiError error = JVMTI_ERROR_NONE;
1652     jthread *list = saArg->list;
1653     jint count = saArg->count;
1654     if (!contains(env, list, count, node->thread)) {
1655         error = commonSuspend(env, node->thread, JNI_FALSE);
1656     }
1657     return error;
1658 }
1659 
1660 jvmtiError
1661 threadControl_suspendAll(void)

1663     jvmtiError error;
1664     JNIEnv    *env;
1665 #if 0
1666     tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount);
1667 #endif
1668 
1669     env = getEnv();
1670 
1671     log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0);
1672 
1673     preSuspend();
1674 
1675     /*
1676      * Get a list of all threads and suspend them.
1677      */
1678     WITH_LOCAL_REFS(env, 1) {
1679 
1680         jthread *threads;
1681         jint count;
1682 
1683         if (gdata->vthreadsSupported) {
1684             /* Tell JVMTI to suspend all virtual threads. */
1685             if (suspendAllCount == 0) {
1686                 error = JVMTI_FUNC_PTR(gdata->jvmti, SuspendAllVirtualThreads)
1687                         (gdata->jvmti, 0, NULL);
1688                 if (error != JVMTI_ERROR_NONE) {
1689                     EXIT_ERROR(error, "cannot suspend all virtual threads");
1690                 }
1691             }
1692 
1693             /*
1694              * Increment suspendCount of each virtual thread that we are tracking. Note the
1695              * compliment to this that happens during the resumeAll() is handled by
1696              * commonResumeList(), so it's a bit orthogonal to how we handle incrementing
1697              * the suspendCount.
1698              */
1699             error = enumerateOverThreadList(env, &runningVThreads, incrementSuspendCountHelper, NULL);
1700             JDI_ASSERT(error == JVMTI_ERROR_NONE);
1701         }
1702 
1703         threads = allThreads(&count);
1704         if (threads == NULL) {
1705             error = AGENT_ERROR_OUT_OF_MEMORY;
1706             goto err;
1707         }
1708         error = commonSuspendList(env, count, threads);
1709         if (error != JVMTI_ERROR_NONE) {
1710             goto err;
1711         }
1712 
1713         /*
1714          * Update the suspend count of any threads not yet (or no longer)
1715          * in the thread list above.
1716          */
1717         {
1718             SuspendAllArg arg;
1719             arg.list = threads;
1720             arg.count = count;
1721             error = enumerateOverThreadList(env, &otherThreads,
1722                                             suspendAllHelper, &arg);

1736         jvmtiDeallocate(threads);
1737 
1738     } END_WITH_LOCAL_REFS(env)
1739 
1740     postSuspend();
1741 
1742     return error;
1743 }
1744 
1745 static jvmtiError
1746 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1747 {
1748     /*
1749      * Since this helper is called with the threadLock held, we
1750      * don't need to recheck to see if the node is still on one
1751      * of the two thread lists.
1752      */
1753     return resumeThreadByNode(node);
1754 }
1755 
1756 static jvmtiError
1757 excludeCountHelper(JNIEnv *env, ThreadNode *node, void *arg)
1758 {
1759     JDI_ASSERT(node->is_vthread);
1760     if (node->suspendCount > 0) {
1761         jint *counter = (jint *)arg;
1762         (*counter)++;
1763     }
1764     return JVMTI_ERROR_NONE;
1765 }
1766 
1767 static jvmtiError
1768 excludeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1769 {
1770     JDI_ASSERT(node->is_vthread);
1771     if (node->suspendCount > 0) {
1772         jthread **listPtr = (jthread **)arg;
1773         **listPtr = node->thread;
1774         (*listPtr)++;
1775     }
1776     return JVMTI_ERROR_NONE;
1777 }
1778 
1779 jvmtiError
1780 threadControl_resumeAll(void)
1781 {
1782     jvmtiError error;
1783     JNIEnv    *env;
1784 #if 0
1785     tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount);
1786 #endif
1787 
1788     env = getEnv();
1789 
1790     log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1791 
1792     eventHandler_lock(); /* for proper lock order */
1793     debugMonitorEnter(threadLock);
1794 
1795     if (gdata->vthreadsSupported) {
1796         if (suspendAllCount == 1) {
1797             jint excludeCnt = 0;
1798             jthread *excludeList = NULL;
1799             /*
1800              * Tell JVMTI to resume all virtual threads except for those we
1801              * are tracking separately. The commonResumeList() call below will
1802              * resume any vthread with a suspendCount == 1, and we want to ignore
1803              * vthreads with a suspendCount > 0. Therefor we don't want
1804              * ResumeAllVirtualThreads resuming these vthreads. We must first
1805              * build a list of them to pass to as the exclude list.
1806              */
1807             enumerateOverThreadList(env, &runningVThreads, excludeCountHelper,
1808                                     &excludeCnt);
1809             if (excludeCnt > 0) {
1810                 excludeList = newArray(excludeCnt, sizeof(jthread));
1811                 if (excludeList == NULL) {
1812                     EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"exclude list");
1813                 }
1814                 {
1815                     jthread *excludeListPtr = excludeList;
1816                     enumerateOverThreadList(env, &runningVThreads, excludeCopyHelper,
1817                                             &excludeListPtr);
1818                 }
1819             }
1820             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeAllVirtualThreads)
1821                     (gdata->jvmti, excludeCnt, excludeList);
1822             if (error != JVMTI_ERROR_NONE) {
1823                 EXIT_ERROR(error, "cannot resume all virtual threads");
1824             }
1825         }
1826     }
1827 
1828     /*
1829      * Resume only those threads that the debugger has suspended. All
1830      * such threads must have a node in one of the thread lists, so there's
1831      * no need to get the whole thread list from JVMTI (unlike
1832      * suspendAll).
1833      */
1834     error = commonResumeList(env);
1835     if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1836         error = enumerateOverThreadList(env, &otherThreads,
1837                                         resumeHelper, NULL);
1838         removeResumed(env, &otherThreads);
1839     }
1840 
1841     if (suspendAllCount > 0) {
1842         /*
1843          * Unpin all objects.
1844          */
1845         commonRef_unpinAll();
1846 
1847         suspendAllCount--;

1849 
1850     debugMonitorExit(threadLock);
1851     eventHandler_unlock();
1852     /* let eventHelper.c: commandLoop() know we are resuming */
1853     unblockCommandLoop();
1854 
1855     return error;
1856 }
1857 
1858 
1859 StepRequest *
1860 threadControl_getStepRequest(jthread thread)
1861 {
1862     ThreadNode  *node;
1863     StepRequest *step;
1864 
1865     step = NULL;
1866 
1867     debugMonitorEnter(threadLock);
1868 
1869     node = findRunningThread(thread);
1870     if (node != NULL) {
1871         step = &node->currentStep;
1872     }
1873 
1874     debugMonitorExit(threadLock);
1875 
1876     return step;
1877 }
1878 
1879 InvokeRequest *
1880 threadControl_getInvokeRequest(jthread thread)
1881 {
1882     ThreadNode    *node;
1883     InvokeRequest *request;
1884 
1885     request = NULL;
1886 
1887     debugMonitorEnter(threadLock);
1888 
1889     node = findRunningThread(thread);
1890     if (node != NULL) {
1891          request = &node->currentInvoke;
1892     }
1893 
1894     debugMonitorExit(threadLock);
1895 
1896     return request;
1897 }
1898 
1899 jvmtiError
1900 threadControl_addDebugThread(jthread thread)
1901 {
1902     jvmtiError error;
1903 
1904     debugMonitorEnter(threadLock);
1905     if (debugThreadCount >= MAX_DEBUG_THREADS) {
1906         error = AGENT_ERROR_OUT_OF_MEMORY;
1907     } else {
1908         JNIEnv    *env;
1909 

2235                                EI_SINGLE_STEP, thread);
2236 
2237     return error;
2238 }
2239 
2240 /* Check to see if any events are being consumed by a popFrame(). */
2241 static jboolean
2242 checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread)
2243 {
2244     if ( getPopFrameThread(thread) ) {
2245         switch (ei) {
2246             case EI_THREAD_START:
2247                 /* Excuse me? */
2248                 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame");
2249                 break;
2250             case EI_THREAD_END:
2251                 /* Thread wants to end? let it. */
2252                 setPopFrameThread(thread, JNI_FALSE);
2253                 popFrameCompleteEvent(thread);
2254                 break;
2255             case EI_VIRTUAL_THREAD_START:
2256             case EI_VIRTUAL_THREAD_END:
2257                 JDI_ASSERT(JNI_FALSE);
2258                 break;
2259             case EI_SINGLE_STEP:
2260                 /* This is an event we requested to mark the */
2261                 /*        completion of the pop frame */
2262                 popFrameCompleteEvent(thread);
2263                 return JNI_TRUE;
2264             case EI_BREAKPOINT:
2265             case EI_EXCEPTION:
2266             case EI_FIELD_ACCESS:
2267             case EI_FIELD_MODIFICATION:
2268             case EI_METHOD_ENTRY:
2269             case EI_METHOD_EXIT:
2270                 /* Tell event handler to assume event has been consumed. */
2271                 return JNI_TRUE;
2272             default:
2273                 break;
2274         }
2275     }
2276     /* Pretend we were never called */
2277     return JNI_FALSE;
2278 }

2311      * Check the list of unknown threads maintained by suspend
2312      * and resume. If this thread is currently present in the
2313      * list, it should be
2314      * moved to the runningThreads list, since it is a
2315      * well-known thread now.
2316      */
2317     node = findThread(&otherThreads, thread);
2318     if (node != NULL) {
2319         moveNode(&otherThreads, &runningThreads, node);
2320         /* Now that we know the thread has started, we can set its TLS.*/
2321         setThreadLocalStorage(thread, (void*)node);
2322     } else {
2323         /*
2324          * Get a thread node for the reporting thread. For thread start
2325          * events, or if this event precedes a thread start event,
2326          * the thread node may need to be created.
2327          *
2328          * It is possible for certain events (notably method entry/exit)
2329          * to precede thread start for some VM implementations.
2330          */
2331         if (evinfo->is_vthread) {
2332           /* fiber fixme: don't add the vthread if this is an EI_THREAD_START or
2333              EI_THREAD_EXIT event. Otherwise we end up adding every vthread. This
2334              is an issue when notifyVThreads is true, which is the default.
2335           */
2336             node = insertThread(env, &runningVThreads, thread);
2337         } else {
2338             node = insertThread(env, &runningThreads, thread);
2339         }
2340     }
2341 
2342     if (ei == EI_THREAD_START || ei == EI_VIRTUAL_THREAD_START) {
2343         node->isStarted = JNI_TRUE;
2344         processDeferredEventModes(env, thread, node);
2345     }
2346 
2347     node->current_ei = ei;
2348     eventBag = node->eventBag;
2349     if (node->suspendOnStart) {
2350         threadToSuspend = node->thread;
2351     }
2352     debugMonitorExit(threadLock);
2353 
2354     if (threadToSuspend != NULL) {
2355         /*
2356          * An attempt was made to suspend this thread before it started.
2357          * We must suspend it now, before it starts to run. This must
2358          * be done with no locks held.
2359          */
2360         eventHelper_suspendThread(sessionID, threadToSuspend);
2361     }
2362 

2385         /*
2386          * TO DO: Log error
2387          */
2388         tossGlobalRef(env, &(node->pendingStop));
2389     }
2390 }
2391 
2392 void
2393 threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
2394                                  struct bag *eventBag)
2395 {
2396     ThreadNode *node;
2397 
2398     log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0);
2399 
2400     if (ei == EI_THREAD_END) {
2401         eventHandler_lock(); /* for proper lock order */
2402     }
2403     debugMonitorEnter(threadLock);
2404 
2405     node = findRunningThread(thread);
2406     if (node == NULL) {
2407         EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2408     } else {
2409         JNIEnv *env;
2410 
2411         env = getEnv();
2412         if (ei == EI_THREAD_END) {
2413             jboolean inResume = (node->resumeFrameDepth > 0);
2414             if (isVThread(thread)) {
2415                 removeThread(env, &runningVThreads, thread);
2416             } else {
2417                 removeThread(env, &runningThreads, thread);
2418             }
2419             node = NULL;   /* has been freed */
2420 
2421             /*
2422              * Clean up mechanism used to detect end of
2423              * resume.
2424              */
2425             if (inResume) {
2426                 notifyAppResumeComplete();
2427             }
2428         } else {
2429             /* No point in doing this if the thread is about to die.*/
2430             doPendingTasks(env, node);
2431             node->eventBag = eventBag;
2432             node->current_ei = 0;
2433         }
2434     }
2435 
2436     debugMonitorExit(threadLock);
2437     if (ei == EI_THREAD_END) {
2438         eventHandler_unlock();

2440 }
2441 
2442 /* Returns JDWP flavored status and status flags. */
2443 jvmtiError
2444 threadControl_applicationThreadStatus(jthread thread,
2445                         jdwpThreadStatus *pstatus, jint *statusFlags)
2446 {
2447     ThreadNode *node;
2448     jvmtiError  error;
2449     jint        state;
2450 
2451     log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2452 
2453     debugMonitorEnter(threadLock);
2454 
2455     error = threadState(thread, &state);
2456     *pstatus = map2jdwpThreadStatus(state);
2457     *statusFlags = map2jdwpSuspendStatus(state);
2458 
2459     if (error == JVMTI_ERROR_NONE) {
2460         node = findRunningThread(thread);
2461         if ((node != NULL) && HANDLING_EVENT(node)) {
2462             /*
2463              * While processing an event, an application thread is always
2464              * considered to be running even if its handler happens to be
2465              * cond waiting on an internal debugger monitor, etc.
2466              *
2467              * Leave suspend status untouched since it is not possible
2468              * to distinguish debugger suspends from app suspends.
2469              */
2470             *pstatus = JDWP_THREAD_STATUS(RUNNING);
2471         }
2472     }
2473 #if 0
2474     tty_message("status %s: node(%p) suspendCount(%d) %d %d %s",
2475                 isVThread(thread) ? "vthread" : "thread",
2476                 node, node->suspendCount, *pstatus, *statusFlags, node->name);
2477 #endif
2478 
2479     debugMonitorExit(threadLock);
2480 
2481     return error;
2482 }
2483 
2484 jvmtiError
2485 threadControl_interrupt(jthread thread)
2486 {
2487     ThreadNode *node;
2488     jvmtiError  error;
2489 
2490     // vthread fixme: should this work for vthreads?
2491     JDI_ASSERT(!isVThread(thread));
2492 
2493     error = JVMTI_ERROR_NONE;
2494 
2495     log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2496 
2497     debugMonitorEnter(threadLock);
2498 
2499     node = findThread(&runningThreads, thread);
2500     if ((node == NULL) || !HANDLING_EVENT(node)) {
2501         error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2502                         (gdata->jvmti, thread);
2503     } else {
2504         /*
2505          * Hold any interrupts until after the event is processed.
2506          */
2507         node->pendingInterrupt = JNI_TRUE;
2508     }
2509 
2510     debugMonitorExit(threadLock);
2511 
2512     return error;
2513 }
2514 
2515 void
2516 threadControl_clearCLEInfo(JNIEnv *env, jthread thread)
2517 {
2518     ThreadNode *node;
2519 
2520     debugMonitorEnter(threadLock);
2521 
2522     node = findRunningThread(thread);
2523     if (node != NULL) {
2524         node->cleInfo.ei = 0;
2525         if (node->cleInfo.clazz != NULL) {
2526             tossGlobalRef(env, &(node->cleInfo.clazz));
2527         }
2528     }
2529 
2530     debugMonitorExit(threadLock);
2531 }
2532 
2533 jboolean
2534 threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz,
2535                          jmethodID method, jlocation location)
2536 {
2537     ThreadNode *node;
2538     jboolean    result;
2539 
2540     result = JNI_FALSE;
2541 
2542     debugMonitorEnter(threadLock);
2543 
2544     node = findRunningThread(thread);
2545     if (node != NULL && node->cleInfo.ei != 0 &&
2546         node->cleInfo.method == method &&
2547         node->cleInfo.location == location &&
2548         (isSameObject(env, node->cleInfo.clazz, clazz))) {
2549         result = JNI_TRUE; /* we have a match */
2550     }
2551 
2552     debugMonitorExit(threadLock);
2553 
2554     return result;
2555 }
2556 
2557 void
2558 threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
2559                           jclass clazz, jmethodID method, jlocation location)
2560 {
2561     ThreadNode *node;
2562 
2563     debugMonitorEnter(threadLock);
2564 
2565     node = findRunningThread(thread);
2566     if (node != NULL) {
2567         node->cleInfo.ei = ei;
2568         /* Create a class ref that will live beyond */
2569         /* the end of this call */
2570         saveGlobalRef(env, clazz, &(node->cleInfo.clazz));
2571         /* if returned clazz is NULL, we just won't match */
2572         node->cleInfo.method    = method;
2573         node->cleInfo.location  = location;
2574     }
2575 
2576     debugMonitorExit(threadLock);
2577 }
2578 
2579 void
2580 threadControl_setPendingInterrupt(jthread thread)
2581 {
2582     ThreadNode *node;
2583 
2584     // vthread fixme: should this work for vthreads?
2585     JDI_ASSERT(!isVThread(thread));
2586 
2587     debugMonitorEnter(threadLock);
2588 
2589     node = findThread(&runningThreads, thread);
2590     if (node != NULL) {
2591         node->pendingInterrupt = JNI_TRUE;
2592     }
2593 
2594     debugMonitorExit(threadLock);
2595 }
2596 
2597 jvmtiError
2598 threadControl_stop(jthread thread, jobject throwable)
2599 {
2600     ThreadNode *node;
2601     jvmtiError  error;
2602 
2603     // vthread fixme: should this work for vthreads?
2604     JDI_ASSERT(!isVThread(thread));
2605 
2606     error = JVMTI_ERROR_NONE;
2607 
2608     log_debugee_location("threadControl_stop()", thread, NULL, 0);
2609 
2610     debugMonitorEnter(threadLock);
2611 
2612     node = findThread(&runningThreads, thread);
2613     if ((node == NULL) || !HANDLING_EVENT(node)) {
2614         error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2615                         (gdata->jvmti, thread, throwable);
2616     } else {
2617         JNIEnv *env;
2618 
2619         /*
2620          * Hold any stops until after the event is processed.
2621          */
2622         env = getEnv();
2623         saveGlobalRef(env, throwable, &(node->pendingStop));
2624     }
2625 

2655         LOG_MISC(("thread=%p resumed", node->thread));
2656         (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, node->thread);
2657         node->frameGeneration++; /* Increment on each resume */
2658     }
2659     stepControl_clearRequest(node->thread, &node->currentStep);
2660     node->toBeResumed = JNI_FALSE;
2661     node->suspendCount = 0;
2662     node->suspendOnStart = JNI_FALSE;
2663 
2664     return JVMTI_ERROR_NONE;
2665 }
2666 
2667 void
2668 threadControl_reset(void)
2669 {
2670     JNIEnv *env;
2671 
2672     env = getEnv();
2673     eventHandler_lock(); /* for proper lock order */
2674     debugMonitorEnter(threadLock);
2675 
2676     if (gdata->vthreadsSupported) {
2677         if (suspendAllCount > 0) {
2678             /* Tell JVMTI to resume all virtual threads. */
2679             jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeAllVirtualThreads)
2680               (gdata->jvmti, 0, NULL);
2681             if (error != JVMTI_ERROR_NONE) {
2682                 EXIT_ERROR(error, "cannot resume all virtual threads");
2683             }
2684         }
2685     }
2686 
2687     (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2688     (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);
2689     (void)enumerateOverThreadList(env, &runningVThreads, resetHelper, NULL);
2690 
2691     removeResumed(env, &otherThreads);
2692 
2693     freeDeferredEventModes(env);
2694 
2695     suspendAllCount = 0;
2696 
2697     /* Everything should have been resumed */
2698     JDI_ASSERT(otherThreads.first == NULL);
2699 
2700     debugMonitorExit(threadLock);
2701     eventHandler_unlock();
2702 }
2703 
2704 jvmtiEventMode
2705 threadControl_getInstructionStepMode(jthread thread)
2706 {
2707     ThreadNode    *node;
2708     jvmtiEventMode mode;
2709 
2710     mode = JVMTI_DISABLE;
2711 
2712     debugMonitorEnter(threadLock);
2713     node = findRunningThread(thread);
2714     if (node != NULL) {
2715         mode = node->instructionStepMode;
2716     }
2717     debugMonitorExit(threadLock);
2718     return mode;
2719 }
2720 
2721 jvmtiError
2722 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2723 {
2724     jvmtiError error;
2725 
2726     /* Global event */
2727     if ( thread == NULL ) {
2728         error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2729                     (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2730     } else {
2731         /* Thread event */
2732         ThreadNode *node;
2733 
2734         debugMonitorEnter(threadLock);
2735         {
2736             node = findRunningThread(thread);
2737             if ((node == NULL) || (!node->isStarted)) {
2738                 JNIEnv *env;
2739 
2740                 env = getEnv();
2741                 error = addDeferredEventMode(env, mode, ei, thread);
2742             } else {
2743                 error = threadSetEventNotificationMode(node,
2744                         mode, ei, thread);
2745             }
2746         }
2747         debugMonitorExit(threadLock);
2748 
2749     }
2750     return error;
2751 }
2752 
2753 /*
2754  * Returns the current thread, if the thread has generated at least
2755  * one event, and has not generated a thread end event.
2756  */

2774 jlong
2775 threadControl_getFrameGeneration(jthread thread)
2776 {
2777     jlong frameGeneration = -1;
2778 
2779     debugMonitorEnter(threadLock);
2780     {
2781         ThreadNode *node;
2782 
2783         node = findThread(NULL, thread);
2784 
2785         if (node != NULL) {
2786             frameGeneration = node->frameGeneration;
2787         }
2788     }
2789     debugMonitorExit(threadLock);
2790 
2791     return frameGeneration;
2792 }
2793 
2794 jthread *
2795 threadControl_allVThreads(jint *numVThreads)
2796 {
2797     JNIEnv *env;
2798     ThreadNode *node;
2799     jthread* vthreads;
2800 
2801     env = getEnv();
2802     debugMonitorEnter(threadLock);
2803 
2804     /* Count the number of vthreads */
2805     /* vthread fixme: we should keep a running total so no counting is needed. */
2806     *numVThreads = 0;
2807     for (node = runningVThreads.first; node != NULL; node = node->next) {
2808         (*numVThreads)++;
2809     }
2810 
2811     /* Allocate and fill in the vthreads array. */
2812     vthreads = jvmtiAllocate(*numVThreads * sizeof(jthread*));
2813     if (vthreads != NULL) {
2814         int i = 0;
2815         for (node = runningVThreads.first; node != NULL;  node = node->next) {
2816             vthreads[i++] = node->thread;
2817         }
2818     }
2819 
2820     debugMonitorExit(threadLock);
2821 
2822     return vthreads;
2823 }
2824 
2825 jboolean threadControl_isKnownVThread(jthread vthread) {
2826     ThreadNode *vthreadNode;
2827     debugMonitorEnter(threadLock);
2828     vthreadNode = findThread(&runningVThreads, vthread);
2829     debugMonitorExit(threadLock);
2830     return vthreadNode != NULL;
2831 }
2832 
2833 void
2834 threadControl_addVThread(jthread vthread)
2835 {
2836     ThreadNode *vthreadNode;
2837     debugMonitorEnter(threadLock);
2838     vthreadNode = insertThread(getEnv(), &runningVThreads, vthread);
2839     debugMonitorExit(threadLock);
2840 }
2841 
2842 /***** debugging *****/
2843 
2844 #ifdef DEBUG
2845 
2846 void
2847 threadControl_dumpAllThreads()
2848 {
2849     tty_message("Dumping runningThreads:");
2850     dumpThreadList(&runningThreads);
2851     tty_message("\nDumping runningVThreads:");
2852     dumpThreadList(&runningVThreads);
2853     tty_message("\nDumping otherThreads:");
2854     dumpThreadList(&otherThreads);
2855 }
2856 
2857 void
2858 threadControl_dumpThread(jthread thread)
2859 {
2860     ThreadNode* node = findThread(NULL, thread);
2861     if (node == NULL) {
2862         tty_message("Thread not found");
2863     } else {
2864         dumpThread(node);
2865     }
2866 }
2867 
2868 static void
2869 dumpThreadList(ThreadList *list)
2870 {
2871     ThreadNode *node;
2872     for (node = list->first; node != NULL; node = node->next) {
2873         if (!node->isDebugThread) {
< prev index next >