< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "util.h"
  27 #include "eventHandler.h"
  28 #include "threadControl.h"
  29 #include "commonRef.h"
  30 #include "eventHelper.h"
  31 #include "stepControl.h"
  32 #include "invoker.h"
  33 #include "bag.h"
  34 
  35 #define HANDLING_EVENT(node) ((node)->current_ei != 0)
  36 
  37 /*
  38  * Collection of info for properly handling co-located events.
  39  * If the ei field is non-zero, then one of the possible
  40  * co-located events has been posted and the other fields describe
  41  * the event's location.


  42  */
  43 typedef struct CoLocatedEventInfo_ {
  44     EventIndex ei;
  45     jclass    clazz;
  46     jmethodID method;
  47     jlocation location;
  48 } CoLocatedEventInfo;
  49 
  50 /**
  51  * The main data structure in threadControl is the ThreadNode.
  52  * This is a per-thread structure that is allocated on the
  53  * first event that occurs in a thread. It is freed after the
  54  * thread's thread end event has completed processing. The
  55  * structure contains state information on its thread including
  56  * suspend counts. It also acts as a repository for other
  57  * per-thread state such as the current method invocation or
  58  * current step.
  59  *
  60  * suspendCount is the number of outstanding suspends
  61  * from the debugger. suspends from the app itself are
  62  * not included in this count.
  63  */
  64 typedef struct ThreadNode {
  65     jthread thread;
  66     unsigned int toBeResumed : 1;
  67     unsigned int pendingInterrupt : 1;
  68     unsigned int isDebugThread : 1;
  69     unsigned int suspendOnStart : 1;
  70     unsigned int isStarted : 1;

  71     unsigned int popFrameEvent : 1;
  72     unsigned int popFrameProceed : 1;
  73     unsigned int popFrameThread : 1;
  74     EventIndex current_ei;
  75     jobject pendingStop;
  76     jint suspendCount;
  77     jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */
  78     jvmtiEventMode instructionStepMode;
  79     StepRequest currentStep;
  80     InvokeRequest currentInvoke;
  81     struct bag *eventBag;
  82     CoLocatedEventInfo cleInfo;





  83     struct ThreadNode *next;
  84     struct ThreadNode *prev;
  85     jlong frameGeneration;
  86     struct ThreadList *list;  /* Tells us what list this thread is in */




  87 } ThreadNode;
  88 
  89 static jint suspendAllCount;
  90 


  91 typedef struct ThreadList {
  92     ThreadNode *first;
  93 } ThreadList;
  94 
  95 /*
  96  * popFrameEventLock is used to notify that the event has been received
  97  */
  98 static jrawMonitorID popFrameEventLock = NULL;
  99 
 100 /*
 101  * popFrameProceedLock is used to assure that the event thread is
 102  * re-suspended immediately after the event is acknowledged.
 103  */
 104 static jrawMonitorID popFrameProceedLock = NULL;
 105 
 106 static jrawMonitorID threadLock;
 107 static jlocation resumeLocation;
 108 static HandlerNode *breakpointHandlerNode;
 109 static HandlerNode *framePopHandlerNode;
 110 static HandlerNode *catchHandlerNode;
 111 
 112 static jvmtiError threadControl_removeDebugThread(jthread thread);
 113 
 114 /*
 115  * Threads which have issued thread start events and not yet issued thread
 116  * end events are maintained in the "runningThreads" list. All other threads known
 117  * to this module are kept in the "otherThreads" list.
 118  */
 119 static ThreadList runningThreads;
 120 static ThreadList otherThreads;

 121 
 122 #define MAX_DEBUG_THREADS 10
 123 static int debugThreadCount;
 124 static jthread debugThreads[MAX_DEBUG_THREADS];
 125 
 126 typedef struct DeferredEventMode {
 127     EventIndex ei;
 128     jvmtiEventMode mode;
 129     jthread thread;
 130     struct DeferredEventMode *next;
 131 } DeferredEventMode;
 132 
 133 typedef struct {
 134     DeferredEventMode *first;
 135     DeferredEventMode *last;
 136 } DeferredEventModeList;
 137 
 138 static DeferredEventModeList deferredEventModes;
 139 
 140 static jint


 201  *   It assumed that this logic is never dealing with terminated threads,
 202  *   since the ThreadEnd events always delete the ThreadNode while the
 203  *   jthread is still alive.  So we can only look at the ThreadNode's that
 204  *   have never had their TLS set, making the search much faster.
 205  *   But keep in mind, this kind of search should rarely be needed.
 206  */
 207 static ThreadNode *
 208 nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
 209 {
 210     ThreadNode *node;
 211 
 212     for (node = list->first; node != NULL; node = node->next) {
 213         if (isSameObject(env, node->thread, thread)) {
 214             break;
 215         }
 216     }
 217     return node;
 218 }
 219 
 220 /*
 221  * These functions maintain the linked list of currently running threads.
 222  * All assume that the threadLock is held before calling.
 223  * If list==NULL, search both lists.




 224  */
 225 static ThreadNode *
 226 findThread(ThreadList *list, jthread thread)
 227 {
 228     ThreadNode *node;














 229 
 230     /* Get thread local storage for quick thread -> node access */
 231     node = getThreadLocalStorage(thread);
 232 
 233     /* In some rare cases we might get NULL, so we check the list manually for
 234      *   any threads that we could match.
 235      */
 236     if ( node == NULL ) {
 237         JNIEnv *env;
 238 
 239         env = getEnv();
 240         if ( list != NULL ) {
 241             node = nonTlsSearch(env, list, thread);
 242         } else {
 243             node = nonTlsSearch(env, &runningThreads, thread);
 244             if ( node == NULL ) {
 245                 node = nonTlsSearch(env, &otherThreads, thread);
 246             }
 247         }
 248         if ( node != NULL ) {
 249             /* Here we make another attempt to set TLS, it's ok if this fails */
 250             setThreadLocalStorage(thread, (void*)node);
 251         }
 252     }
 253 
 254     /* If a list is supplied, only return ones in this list */
 255     if ( node != NULL && list != NULL && node->list != list ) {
 256         return NULL;
 257     }
 258     return node;
 259 }


 286 addNode(ThreadList *list, ThreadNode *node)
 287 {
 288     node->next = NULL;
 289     node->prev = NULL;
 290     node->list = NULL;
 291     if ( list->first == NULL ) {
 292         list->first = node;
 293     } else {
 294         list->first->prev = node;
 295         node->next = list->first;
 296         list->first = node;
 297     }
 298     node->list = list;
 299 }
 300 
 301 static ThreadNode *
 302 insertThread(JNIEnv *env, ThreadList *list, jthread thread)
 303 {
 304     ThreadNode *node;
 305     struct bag *eventBag;

 306 
 307     node = findThread(list, thread);
 308     if (node == NULL) {
 309         node = jvmtiAllocate(sizeof(*node));
 310         if (node == NULL) {
 311             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 312             return NULL;
 313         }
 314         (void)memset(node, 0, sizeof(*node));
 315         eventBag = eventHelper_createEventBag();
 316         if (eventBag == NULL) {
 317             jvmtiDeallocate(node);
 318             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 319             return NULL;
 320         }
 321 
 322         /*
 323          * Init all flags false, all refs NULL, all counts 0
 324          */
 325 
 326         saveGlobalRef(env, thread, &(node->thread));
 327         if (node->thread == NULL) {
 328             jvmtiDeallocate(node);
 329             bagDestroyBag(eventBag);
 330             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 331             return NULL;
 332         }
 333         /*
 334          * Remember if it is a debug thread
 335          */
 336         if (threadControl_isDebugThread(node->thread)) {
 337             node->isDebugThread = JNI_TRUE;
 338         } else if (suspendAllCount > 0){
 339             /*
 340              * If there is a pending suspendAll, all new threads should
 341              * be initialized as if they were suspended by the suspendAll,
 342              * and the thread will need to be suspended when it starts.
 343              */
 344             node->suspendCount = suspendAllCount;
 345             node->suspendOnStart = JNI_TRUE;
 346         }
 347         node->current_ei = 0;

 348         node->instructionStepMode = JVMTI_DISABLE;
 349         node->eventBag = eventBag;
 350         addNode(list, node);
 351 
 352         /* Set thread local storage for quick thread -> node access.
 353          *   Some threads may not be in a state that allows setting of TLS,
 354          *   which is ok, see findThread, it deals with threads without TLS set.
 355          */
 356         setThreadLocalStorage(node->thread, (void*)node);






 357     }
 358 
 359     return node;
 360 }
 361 
 362 static void
 363 clearThread(JNIEnv *env, ThreadNode *node)
 364 {
 365     if (node->pendingStop != NULL) {
 366         tossGlobalRef(env, &(node->pendingStop));
 367     }
 368     stepControl_clearRequest(node->thread, &node->currentStep);
 369     if (node->isDebugThread) {
 370         (void)threadControl_removeDebugThread(node->thread);
 371     }
 372     /* Clear out TLS on this thread (just a cleanup action) */
 373     setThreadLocalStorage(node->thread, NULL);


 374     tossGlobalRef(env, &(node->thread));
 375     bagDestroyBag(node->eventBag);
 376     jvmtiDeallocate(node);
 377 }
 378 
 379 static void
 380 removeThread(JNIEnv *env, ThreadList *list, jthread thread)
 381 {
 382     ThreadNode *node;
 383 
 384     node = findThread(list, thread);
 385     if (node != NULL) {
 386         removeNode(list, node);
 387         clearThread(env, node);
 388     }
 389 }
 390 
 391 static void
 392 removeResumed(JNIEnv *env, ThreadList *list)
 393 {


 553 static void
 554 releaseLocks(void)
 555 {
 556     debugMonitorExit(threadLock);
 557     commonRef_unlock();
 558     stepControl_unlock();
 559     eventHelper_unlock();
 560     invoker_unlock();
 561     eventHandler_unlock();
 562 }
 563 
 564 void
 565 threadControl_initialize(void)
 566 {
 567     jlocation unused;
 568     jvmtiError error;
 569 
 570     suspendAllCount = 0;
 571     runningThreads.first = NULL;
 572     otherThreads.first = NULL;

 573     debugThreadCount = 0;
 574     threadLock = debugMonitorCreate("JDWP Thread Lock");
 575     if (gdata->threadClass==NULL) {
 576         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class");
 577     }
 578     if (gdata->threadResume==0) {
 579         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread");
 580     }
 581     /* Get the java.lang.Thread.resume() method beginning location */
 582     error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
 583     if (error != JVMTI_ERROR_NONE) {
 584         EXIT_ERROR(error, "getting method location");
 585     }
 586 }
 587 
 588 static jthread
 589 getResumee(jthread resumingThread)
 590 {
 591     jthread resumee = NULL;
 592     jvmtiError error;


 639     if (!pendingAppResume(JNI_TRUE)) {
 640         if (framePopHandlerNode != NULL) {
 641             (void)eventHandler_free(framePopHandlerNode);
 642             framePopHandlerNode = NULL;
 643         }
 644         if (catchHandlerNode != NULL) {
 645             (void)eventHandler_free(catchHandlerNode);
 646             catchHandlerNode = NULL;
 647         }
 648     }
 649 }
 650 
 651 static void
 652 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
 653                           HandlerNode *handlerNode,
 654                           struct bag *eventBag)
 655 {
 656     ThreadNode *node;
 657     jthread     thread;
 658 



 659     thread = evinfo->thread;
 660 
 661     debugMonitorEnter(threadLock);
 662 
 663     node = findThread(&runningThreads, thread);
 664     if (node != NULL) {
 665         if (node->resumeFrameDepth > 0) {
 666             jint compareDepth = getStackDepth(thread);
 667             if (evinfo->ei == EI_FRAME_POP) {
 668                 compareDepth--;
 669             }
 670             if (compareDepth < node->resumeFrameDepth) {
 671                 node->resumeFrameDepth = 0;
 672                 notifyAppResumeComplete();
 673             }
 674         }
 675     }
 676 
 677     debugMonitorExit(threadLock);
 678 }


 720                     (void)eventHandler_free(framePopHandlerNode);
 721                     framePopHandlerNode = NULL;
 722                     (void)eventHandler_free(catchHandlerNode);
 723                     catchHandlerNode = NULL;
 724                 }
 725             }
 726             if ((framePopHandlerNode != NULL) &&
 727                 (catchHandlerNode != NULL) &&
 728                 (frameDepth > 0)) {
 729                 node->resumeFrameDepth = frameDepth;
 730             }
 731         }
 732     }
 733 }
 734 
 735 static void
 736 handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo,
 737                           HandlerNode *handlerNode,
 738                           struct bag *eventBag)
 739 {



 740     jthread resumer = evinfo->thread;
 741     jthread resumee = getResumee(resumer);
 742 
 743     debugMonitorEnter(threadLock);
 744     if (resumee != NULL) {
 745         /*
 746          * Hold up any attempt to resume as long as the debugger
 747          * has suspended the resumee.
 748          */
 749         blockOnDebuggerSuspend(resumee);
 750     }
 751 
 752     if (resumer != NULL) {
 753         /*
 754          * Track the resuming thread by marking it as being within
 755          * a resume and by setting up for notification on
 756          * a frame pop or exception. We won't allow the debugger
 757          * to suspend threads while any thread is within a
 758          * call to resume. This (along with the block above)
 759          * ensures that when the debugger


 826                 node = insertThread(env, &runningThreads, thread);
 827 
 828                 /*
 829                  * This is a tiny bit risky. We have to assume that the
 830                  * pre-existing threads have been started because we
 831                  * can't rely on a thread start event for them. The chances
 832                  * of a problem related to this are pretty slim though, and
 833                  * there's really no choice because without setting this flag
 834                  * there is no way to enable stepping and other events on
 835                  * the threads that already exist (e.g. the finalizer thread).
 836                  */
 837                 node->isStarted = JNI_TRUE;
 838             }
 839         }
 840 
 841     } END_WITH_LOCAL_REFS(env)
 842 
 843     debugMonitorExit(threadLock);
 844 }
 845 








































































































 846 static jvmtiError
 847 commonSuspendByNode(ThreadNode *node)
 848 {
 849     jvmtiError error;
 850 
 851     LOG_MISC(("thread=%p suspended", node->thread));
 852     error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)
 853                 (gdata->jvmti, node->thread);
 854 
 855     /*
 856      * Mark for resume only if suspend succeeded
 857      */
 858     if (error == JVMTI_ERROR_NONE) {
 859         node->toBeResumed = JNI_TRUE;
 860     }
 861 
 862     /*
 863      * If the thread was suspended by another app thread,
 864      * do nothing and report no error (we won't resume it later).
 865      */


 932     }
 933 
 934     if (node->suspendCount == 0) {
 935         error = commonSuspendByNode(node);
 936 
 937         if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
 938             /*
 939              * This error means that the thread is either a zombie or not yet
 940              * started. In either case, we ignore the error. If the thread
 941              * is a zombie, suspend/resume are no-ops. If the thread is not
 942              * started, it will be suspended for real during the processing
 943              * of its thread start event.
 944              */
 945             node->suspendOnStart = JNI_TRUE;
 946             error = JVMTI_ERROR_NONE;
 947         }
 948     }
 949 
 950     if (error == JVMTI_ERROR_NONE) {
 951         node->suspendCount++;














 952     }
 953 
 954     debugMonitorNotifyAll(threadLock);
 955 
 956     return error;
 957 }
 958 
 959 static jvmtiError
 960 resumeThreadByNode(ThreadNode *node)
 961 {
 962     jvmtiError error = JVMTI_ERROR_NONE;
 963 
 964     if (node->isDebugThread) {
 965         /* never suspended by debugger => don't ever try to resume */
 966         return JVMTI_ERROR_NONE;
 967     }
 968     if (node->suspendCount > 0) {
















 969         node->suspendCount--;
 970         debugMonitorNotifyAll(threadLock);
 971         if ((node->suspendCount == 0) && node->toBeResumed &&
 972             !node->suspendOnStart) {
 973             LOG_MISC(("thread=%p resumed", node->thread));
 974             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
 975                         (gdata->jvmti, node->thread);
 976             node->frameGeneration++; /* Increment on each resume */
 977             node->toBeResumed = JNI_FALSE;
 978             if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
 979                 /*
 980                  * We successfully "suspended" this thread, but
 981                  * we never received a THREAD_START event for it.
 982                  * Since the thread never ran, we can ignore our
 983                  * failure to resume the thread.
 984                  */
 985                 error = JVMTI_ERROR_NONE;
 986             }
 987         }
 988     }


1032         debugMonitorExit(threadLock);
1033 
1034         getLocks();
1035     }
1036 }
1037 
1038 static void
1039 postSuspend(void)
1040 {
1041     releaseLocks();
1042 }
1043 
1044 /*
1045  * This function must be called after preSuspend and before postSuspend.
1046  */
1047 static jvmtiError
1048 commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1049 {
1050     ThreadNode *node;
1051 



































1052     /*
1053      * If the thread is not between its start and end events, we should
1054      * still suspend it. To keep track of things, add the thread
1055      * to a separate list of threads so that we'll resume it later.
1056      */
1057     node = findThread(&runningThreads, thread);



1058     if (node == NULL) {
1059         node = insertThread(env, &otherThreads, thread);
1060     }
1061 
1062     if ( deferred ) {
1063         return deferredSuspendThreadByNode(node);
1064     } else {
1065         return suspendThreadByNode(node);
1066     }
1067 }
1068 
1069 
1070 static jvmtiError
1071 resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1072 {
1073     if (node->isDebugThread) {
1074         /* never suspended by debugger => don't ever try to resume */
1075         return JVMTI_ERROR_NONE;
1076     }
1077 


1345                  * during the processing of its thread start event.
1346                  */
1347                 node->suspendOnStart = JNI_TRUE;
1348                 results[i] = JVMTI_ERROR_NONE;
1349             }
1350 
1351             /* count real, app and deferred (suspendOnStart) suspensions */
1352             if (results[i] == JVMTI_ERROR_NONE) {
1353                 node->suspendCount++;
1354             }
1355         }
1356         deleteArray(results);
1357     }
1358     deleteArray(reqList);
1359 
1360     debugMonitorNotifyAll(threadLock);
1361 
1362     return error;
1363 }
1364 
1365 
1366 static jvmtiError
1367 commonResume(jthread thread)
1368 {
1369     jvmtiError  error;
1370     ThreadNode *node;
1371 


















































1372     /*
1373      * The thread is normally between its start and end events, but if
1374      * not, check the auxiliary list used by threadControl_suspendThread.
1375      */
1376     node = findThread(NULL, thread);



1377 
1378     /*
1379      * If the node is in neither list, the debugger never suspended
1380      * this thread, so do nothing.
1381      */
1382     error = JVMTI_ERROR_NONE;
1383     if (node != NULL) {
1384         error = resumeThreadByNode(node);
1385     }

1386     return error;
1387 }
1388 
1389 
1390 jvmtiError
1391 threadControl_suspendThread(jthread thread, jboolean deferred)
1392 {
1393     jvmtiError error;
1394     JNIEnv    *env;
1395 
1396     env = getEnv();
1397 
1398     log_debugee_location("threadControl_suspendThread()", thread, NULL, 0);
1399 
1400     preSuspend();
1401     error = commonSuspend(env, thread, deferred);
1402     postSuspend();
1403 
1404     return error;
1405 }


1417     eventHandler_lock(); /* for proper lock order */
1418     debugMonitorEnter(threadLock);
1419     error = commonResume(thread);
1420     removeResumed(env, &otherThreads);
1421     debugMonitorExit(threadLock);
1422     eventHandler_unlock();
1423 
1424     if (do_unblock) {
1425         /* let eventHelper.c: commandLoop() know we resumed one thread */
1426         unblockCommandLoop();
1427     }
1428 
1429     return error;
1430 }
1431 
1432 jvmtiError
1433 threadControl_suspendCount(jthread thread, jint *count)
1434 {
1435     jvmtiError  error;
1436     ThreadNode *node;

1437 
1438     debugMonitorEnter(threadLock);
1439 
1440     node = findThread(&runningThreads, thread);
1441     if (node == NULL) {
1442         node = findThread(&otherThreads, thread);




1443     }
1444 
1445     error = JVMTI_ERROR_NONE;
1446     if (node != NULL) {
1447         *count = node->suspendCount;


















1448     } else {
1449         /*
1450          * If the node is in neither list, the debugger never suspended
1451          * this thread, so the suspend count is 0.
1452          */
1453         *count = 0;
1454     }
1455 
1456     debugMonitorExit(threadLock);
1457 
1458     return error;
1459 }
1460 
1461 static jboolean
1462 contains(JNIEnv *env, jthread *list, jint count, jthread item)
1463 {
1464     int i;
1465 
1466     for (i = 0; i < count; i++) {
1467         if (isSameObject(env, list[i], item)) {


1478 } SuspendAllArg;
1479 
1480 static jvmtiError
1481 suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1482 {
1483     SuspendAllArg *saArg = (SuspendAllArg *)arg;
1484     jvmtiError error = JVMTI_ERROR_NONE;
1485     jthread *list = saArg->list;
1486     jint count = saArg->count;
1487     if (!contains(env, list, count, node->thread)) {
1488         error = commonSuspend(env, node->thread, JNI_FALSE);
1489     }
1490     return error;
1491 }
1492 
1493 jvmtiError
1494 threadControl_suspendAll(void)
1495 {
1496     jvmtiError error;
1497     JNIEnv    *env;



1498 
1499     env = getEnv();
1500 
1501     log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0);
1502 
1503     preSuspend();
1504 
1505     /*
1506      * Get a list of all threads and suspend them.
1507      */
1508     WITH_LOCAL_REFS(env, 1) {
1509 
1510         jthread *threads;
1511         jint count;
1512 
1513         threads = allThreads(&count);
1514         if (threads == NULL) {
1515             error = AGENT_ERROR_OUT_OF_MEMORY;
1516             goto err;
1517         }
1518         if (canSuspendResumeThreadLists()) {
1519             error = commonSuspendList(env, count, threads);
1520             if (error != JVMTI_ERROR_NONE) {
1521                 goto err;
1522             }
1523         } else {
1524 
1525             int i;
1526 
1527             for (i = 0; i < count; i++) {
1528                 error = commonSuspend(env, threads[i], JNI_FALSE);
1529 
1530                 if (error != JVMTI_ERROR_NONE) {
1531                     goto err;
1532                 }
1533             }
1534         }
1535 
1536         /*
1537          * Update the suspend count of any threads not yet (or no longer)
1538          * in the thread list above.
1539          */
1540         {
1541             SuspendAllArg arg;
1542             arg.list = threads;
1543             arg.count = count;
1544             error = enumerateOverThreadList(env, &otherThreads,
1545                                             suspendAllHelper, &arg);
1546         }
1547 















1548         if (error == JVMTI_ERROR_NONE) {
1549             suspendAllCount++;
1550         }
1551 
1552     err: ;
1553 
1554     } END_WITH_LOCAL_REFS(env)
1555 
1556     postSuspend();
1557 
1558     return error;
1559 }
1560 
1561 static jvmtiError
1562 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1563 {
1564     /*
1565      * Since this helper is called with the threadLock held, we
1566      * don't need to recheck to see if the node is still on one
1567      * of the two thread lists.
1568      */
1569     return resumeThreadByNode(node);
1570 }
1571 
1572 jvmtiError
1573 threadControl_resumeAll(void)
1574 {
1575     jvmtiError error;
1576     JNIEnv    *env;



1577 
1578     env = getEnv();
1579 
1580     log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1581 
1582     eventHandler_lock(); /* for proper lock order */
1583     debugMonitorEnter(threadLock);
1584 
1585     /*
1586      * Resume only those threads that the debugger has suspended. All
1587      * such threads must have a node in one of the thread lists, so there's
1588      * no need to get the whole thread list from JVMTI (unlike
1589      * suspendAll).
1590      */
1591     if (canSuspendResumeThreadLists()) {
1592         error = commonResumeList(env);
1593     } else {
1594         error = enumerateOverThreadList(env, &runningThreads,
1595                                         resumeHelper, NULL);
1596     }
1597     if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1598         error = enumerateOverThreadList(env, &otherThreads,
1599                                         resumeHelper, NULL);
1600         removeResumed(env, &otherThreads);
1601     }
1602 
1603     if (suspendAllCount > 0) {
1604         suspendAllCount--;
1605     }
1606 




















1607     debugMonitorExit(threadLock);
1608     eventHandler_unlock();
1609     /* let eventHelper.c: commandLoop() know we are resuming */
1610     unblockCommandLoop();
1611 
1612     return error;
1613 }
1614 
1615 
1616 StepRequest *
1617 threadControl_getStepRequest(jthread thread)
1618 {
1619     ThreadNode  *node;
1620     StepRequest *step;
1621 
1622     step = NULL;
1623 
1624     debugMonitorEnter(threadLock);
1625 
1626     node = findThread(&runningThreads, thread);


2014                 /*        completion of the pop frame */
2015                 popFrameCompleteEvent(thread);
2016                 return JNI_TRUE;
2017             case EI_BREAKPOINT:
2018             case EI_EXCEPTION:
2019             case EI_FIELD_ACCESS:
2020             case EI_FIELD_MODIFICATION:
2021             case EI_METHOD_ENTRY:
2022             case EI_METHOD_EXIT:
2023                 /* Tell event handler to assume event has been consumed. */
2024                 return JNI_TRUE;
2025             default:
2026                 break;
2027         }
2028     }
2029     /* Pretend we were never called */
2030     return JNI_FALSE;
2031 }
2032 
2033 struct bag *
2034 threadControl_onEventHandlerEntry(jbyte sessionID, EventIndex ei, jthread thread, jobject currentException)
2035 {
2036     ThreadNode *node;
2037     JNIEnv     *env;
2038     struct bag *eventBag;
2039     jthread     threadToSuspend;
2040     jboolean    consumed;


2041 
2042     env             = getEnv();
2043     threadToSuspend = NULL;
2044 
2045     log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL, 0);
2046 
2047     /* Events during pop commands may need to be ignored here. */
2048     consumed = checkForPopFrameEvents(env, ei, thread);
2049     if ( consumed ) {
2050         /* Always restore any exception (see below). */
2051         if (currentException != NULL) {
2052             JNI_FUNC_PTR(env,Throw)(env, currentException);
2053         } else {
2054             JNI_FUNC_PTR(env,ExceptionClear)(env);
2055         }
2056         return NULL;
2057     }
2058 
2059     debugMonitorEnter(threadLock);
2060 


2159              * Clean up mechanism used to detect end of
2160              * resume.
2161              */
2162             if (inResume) {
2163                 notifyAppResumeComplete();
2164             }
2165         } else {
2166             /* No point in doing this if the thread is about to die.*/
2167             doPendingTasks(env, node);
2168             node->eventBag = eventBag;
2169             node->current_ei = 0;
2170         }
2171     }
2172 
2173     debugMonitorExit(threadLock);
2174     if (ei == EI_THREAD_END) {
2175         eventHandler_unlock();
2176     }
2177 }
2178 











2179 /* Returns JDWP flavored status and status flags. */
2180 jvmtiError
2181 threadControl_applicationThreadStatus(jthread thread,
2182                         jdwpThreadStatus *pstatus, jint *statusFlags)
2183 {
2184     ThreadNode *node;
2185     jvmtiError  error;
2186     jint        state;

2187 
2188     log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2189 
2190     debugMonitorEnter(threadLock);
2191 
2192     error = threadState(thread, &state);
2193     *pstatus = map2jdwpThreadStatus(state);
2194     *statusFlags = map2jdwpSuspendStatus(state);
2195 
2196     if (error == JVMTI_ERROR_NONE) {
2197         node = findThread(&runningThreads, thread);
2198         if ((node != NULL) && HANDLING_EVENT(node)) {
2199             /*
2200              * While processing an event, an application thread is always
2201              * considered to be running even if its handler happens to be
2202              * cond waiting on an internal debugger monitor, etc.
2203              *
2204              * Leave suspend status untouched since it is not possible
2205              * to distinguish debugger suspends from app suspends.
2206              */
2207             *pstatus = JDWP_THREAD_STATUS(RUNNING);
































2208         }




2209     }
2210 
2211     debugMonitorExit(threadLock);
2212 
2213     return error;
2214 }
2215 
2216 jvmtiError
2217 threadControl_interrupt(jthread thread)
2218 {
2219     ThreadNode *node;
2220     jvmtiError  error;
2221 
2222     error = JVMTI_ERROR_NONE;
2223 
2224     log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2225 
2226     debugMonitorEnter(threadLock);
2227 
2228     node = findThread(&runningThreads, thread);


2380         node->frameGeneration++; /* Increment on each resume */
2381     }
2382     stepControl_clearRequest(node->thread, &node->currentStep);
2383     node->toBeResumed = JNI_FALSE;
2384     node->suspendCount = 0;
2385     node->suspendOnStart = JNI_FALSE;
2386 
2387     return JVMTI_ERROR_NONE;
2388 }
2389 
2390 void
2391 threadControl_reset(void)
2392 {
2393     JNIEnv *env;
2394 
2395     env = getEnv();
2396     eventHandler_lock(); /* for proper lock order */
2397     debugMonitorEnter(threadLock);
2398     (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2399     (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);

2400 
2401     removeResumed(env, &otherThreads);
2402 
2403     freeDeferredEventModes(env);
2404 
2405     suspendAllCount = 0;
2406 
2407     /* Everything should have been resumed */
2408     JDI_ASSERT(otherThreads.first == NULL);
2409 
2410     debugMonitorExit(threadLock);
2411     eventHandler_unlock();
2412 }
2413 
2414 jvmtiEventMode
2415 threadControl_getInstructionStepMode(jthread thread)
2416 {
2417     ThreadNode    *node;
2418     jvmtiEventMode mode;
2419 


2426     }
2427     debugMonitorExit(threadLock);
2428     return mode;
2429 }
2430 
2431 jvmtiError
2432 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2433 {
2434     jvmtiError error;
2435 
2436     /* Global event */
2437     if ( thread == NULL ) {
2438         error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2439                     (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2440     } else {
2441         /* Thread event */
2442         ThreadNode *node;
2443 
2444         debugMonitorEnter(threadLock);
2445         {

















































2446             node = findThread(&runningThreads, thread);
2447             if ((node == NULL) || (!node->isStarted)) {
2448                 JNIEnv *env;
2449 
2450                 env = getEnv();
2451                 error = addDeferredEventMode(env, mode, ei, thread);
2452             } else {
2453                 error = threadSetEventNotificationMode(node,
2454                         mode, ei, thread);
2455             }
2456         }
2457         debugMonitorExit(threadLock);
2458 
2459     }
2460     return error;
2461 }
2462 
2463 /*
2464  * Returns the current thread, if the thread has generated at least
2465  * one event, and has not generated a thread end event.
2466  */
2467 jthread threadControl_currentThread(void)

2468 {
2469     jthread thread;
2470 
2471     debugMonitorEnter(threadLock);
2472     {
2473         ThreadNode *node;
2474 
2475         node = findThread(&runningThreads, NULL);
2476         thread = (node == NULL) ? NULL : node->thread;
2477     }
2478     debugMonitorExit(threadLock);
2479 
2480     return thread;
2481 }
2482 
2483 jlong
2484 threadControl_getFrameGeneration(jthread thread)
2485 {
2486     jlong frameGeneration = -1;
2487 
2488     debugMonitorEnter(threadLock);
2489     {
2490         ThreadNode *node;
2491 
2492         node = findThread(NULL, thread);
2493 
2494         if (node != NULL) {
2495             frameGeneration = node->frameGeneration;
2496         }
2497     }
2498     debugMonitorExit(threadLock);
2499 
2500     return frameGeneration;





















































































































































































































































































































































































































2501 }
   1 /*
   2  * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "util.h"
  27 #include "eventHandler.h"
  28 #include "threadControl.h"
  29 #include "commonRef.h"
  30 #include "eventHelper.h"
  31 #include "stepControl.h"
  32 #include "invoker.h"
  33 #include "bag.h"
  34 
  35 #define HANDLING_EVENT(node) ((node)->current_ei != 0)
  36 
  37 /*
  38  * Collection of info for properly handling co-located events.
  39  * If the ei field is non-zero, then one of the possible
  40  * co-located events has been posted and the other fields describe
  41  * the event's location.
  42  *
  43  * See comment above deferEventReport() for an explanation of co-located events.
  44  */
  45 typedef struct CoLocatedEventInfo_ {
  46     EventIndex ei;
  47     jclass    clazz;
  48     jmethodID method;
  49     jlocation location;
  50 } CoLocatedEventInfo;
  51 
  52 /**
  53  * The main data structure in threadControl is the ThreadNode.
  54  * This is a per-thread structure that is allocated on the
  55  * first event that occurs in a thread. It is freed after the
  56  * thread's thread end event has completed processing. The
  57  * structure contains state information on its thread including
  58  * suspend counts. It also acts as a repository for other
  59  * per-thread state such as the current method invocation or
  60  * current step.
  61  *
  62  * suspendCount is the number of outstanding suspends
  63  * from the debugger. suspends from the app itself are
  64  * not included in this count.
  65  */
  66 typedef struct ThreadNode {
  67     jthread thread;
  68     unsigned int toBeResumed : 1;      /* true if this thread was successfully suspended. */
  69     unsigned int pendingInterrupt : 1; /* true if thread is interrupted while handling an event. */
  70     unsigned int isDebugThread : 1;    /* true if this is one of our debug agent threads. */
  71     unsigned int suspendOnStart : 1;   /* true for new threads if we are currently in a VM.suspend(). */
  72     unsigned int isStarted : 1;        /* THREAD_START or FIBER_SCHEDULED event received. */
  73     unsigned int is_fiber : 1;
  74     unsigned int popFrameEvent : 1;
  75     unsigned int popFrameProceed : 1;
  76     unsigned int popFrameThread : 1;
  77     EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */
  78     jobject pendingStop;   /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */
  79     jint suspendCount;
  80     jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */
  81     jvmtiEventMode instructionStepMode;
  82     StepRequest currentStep;
  83     InvokeRequest currentInvoke;
  84     struct bag *eventBag;       /* Accumulation of JDWP events to be sent as a reply. */
  85     CoLocatedEventInfo cleInfo; /* See comment above deferEventReport() for an explanation. */
  86     jthread fiberHelperThread;  /* Temporary thread created for mounting fiber on to get stack trace
  87                                  * or to support suspending an unmounted fiber. */
  88     jboolean isTrackedSuspendedFiber; /* true if we are tracking the suspendCount of this fiber. */
  89     struct ThreadNode *nextTrackedSuspendedFiber;
  90     struct ThreadNode *prevTrackedSuspendedFiber;
  91     struct ThreadNode *next;
  92     struct ThreadNode *prev;
  93     jlong frameGeneration;    /* used to generate a unique frameID. Incremented whenever existing frameID
  94                                  needs to be invalidated, such as when the thread is resumed. */
  95     struct ThreadList *list;  /* Tells us what list this thread is in. */
  96 #ifdef DEBUG_THREADNAME
  97     char name[256];
  98 #endif
  99 } ThreadNode;
 100 
 101 static jint suspendAllCount;
 102 
 103 struct ThreadNode *trackedSuspendedFibers = NULL;
 104 
 105 typedef struct ThreadList {
 106     ThreadNode *first;
 107 } ThreadList;
 108 
 109 /*
 110  * popFrameEventLock is used to notify that the event has been received
 111  */
 112 static jrawMonitorID popFrameEventLock = NULL;
 113 
 114 /*
 115  * popFrameProceedLock is used to assure that the event thread is
 116  * re-suspended immediately after the event is acknowledged.
 117  */
 118 static jrawMonitorID popFrameProceedLock = NULL;
 119 
 120 static jrawMonitorID threadLock;
 121 static jlocation resumeLocation;
 122 static HandlerNode *breakpointHandlerNode;
 123 static HandlerNode *framePopHandlerNode;
 124 static HandlerNode *catchHandlerNode;
 125 
 126 static jvmtiError threadControl_removeDebugThread(jthread thread);
 127 
 128 /*
 129  * Threads which have issued thread start events and not yet issued thread
 130  * end events are maintained in the "runningThreads" list. All other threads known
 131  * to this module are kept in the "otherThreads" list.
 132  */
 133 static ThreadList runningThreads;
 134 static ThreadList otherThreads;
 135 static ThreadList runningFibers; /* Fibers we have seen. */
 136 
 137 #define MAX_DEBUG_THREADS 10
 138 static int debugThreadCount;
 139 static jthread debugThreads[MAX_DEBUG_THREADS];
 140 
 141 typedef struct DeferredEventMode {
 142     EventIndex ei;
 143     jvmtiEventMode mode;
 144     jthread thread;
 145     struct DeferredEventMode *next;
 146 } DeferredEventMode;
 147 
 148 typedef struct {
 149     DeferredEventMode *first;
 150     DeferredEventMode *last;
 151 } DeferredEventModeList;
 152 
 153 static DeferredEventModeList deferredEventModes;
 154 
 155 static jint


 216  *   It assumed that this logic is never dealing with terminated threads,
 217  *   since the ThreadEnd events always delete the ThreadNode while the
 218  *   jthread is still alive.  So we can only look at the ThreadNode's that
 219  *   have never had their TLS set, making the search much faster.
 220  *   But keep in mind, this kind of search should rarely be needed.
 221  */
 222 static ThreadNode *
 223 nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread)
 224 {
 225     ThreadNode *node;
 226 
 227     for (node = list->first; node != NULL; node = node->next) {
 228         if (isSameObject(env, node->thread, thread)) {
 229             break;
 230         }
 231     }
 232     return node;
 233 }
 234 
 235 /*
 236  * These functions maintain the linked list of currently running threads and fibers.
 237  * All assume that the threadLock is held before calling.
 238  */
 239 
 240 
 241 /*
 242  * Search for a thread on the list. If list==NULL, search all lists.
 243  */
 244 static ThreadNode *
 245 findThread(ThreadList *list, jthread thread)
 246 {
 247     ThreadNode *node;
 248     JNIEnv *env = getEnv();
 249 
 250     if (list == NULL || list == &runningFibers) {
 251         /*
 252          * Search for a fiber.
 253          * fiber fixme: this needs to be done a lot faster. Maybe some sort of TLS for fibers is needed.
 254          * Otherwise we'll need something like a hashlist front end to the runningFibers list so
 255          * we can do quick lookups.
 256          */
 257         ThreadNode *node = nonTlsSearch(env, &runningFibers, thread);
 258         if (node != NULL || list == &runningFibers) {
 259             return node;
 260         }
 261     }    
 262 
 263     /* Get thread local storage for quick thread -> node access */
 264     node = getThreadLocalStorage(thread);
 265 
 266     /* In some rare cases we might get NULL, so we check the list manually for
 267      *   any threads that we could match.
 268      */
 269     if ( node == NULL ) {



 270         if ( list != NULL ) {
 271             node = nonTlsSearch(env, list, thread);
 272         } else {
 273             node = nonTlsSearch(env, &runningThreads, thread);
 274             if ( node == NULL ) {
 275                 node = nonTlsSearch(env, &otherThreads, thread);
 276             }
 277         }
 278         if ( node != NULL ) {
 279             /* Here we make another attempt to set TLS, it's ok if this fails */
 280             setThreadLocalStorage(thread, (void*)node);
 281         }
 282     }
 283 
 284     /* If a list is supplied, only return ones in this list */
 285     if ( node != NULL && list != NULL && node->list != list ) {
 286         return NULL;
 287     }
 288     return node;
 289 }


 316 addNode(ThreadList *list, ThreadNode *node)
 317 {
 318     node->next = NULL;
 319     node->prev = NULL;
 320     node->list = NULL;
 321     if ( list->first == NULL ) {
 322         list->first = node;
 323     } else {
 324         list->first->prev = node;
 325         node->next = list->first;
 326         list->first = node;
 327     }
 328     node->list = list;
 329 }
 330 
 331 static ThreadNode *
 332 insertThread(JNIEnv *env, ThreadList *list, jthread thread)
 333 {
 334     ThreadNode *node;
 335     struct bag *eventBag;
 336     jboolean is_fiber = (list == &runningFibers);
 337 
 338     node = findThread(list, thread);
 339     if (node == NULL) {
 340         node = jvmtiAllocate(sizeof(*node));
 341         if (node == NULL) {
 342             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 343             return NULL;
 344         }
 345         (void)memset(node, 0, sizeof(*node));
 346         eventBag = eventHelper_createEventBag();
 347         if (eventBag == NULL) {
 348             jvmtiDeallocate(node);
 349             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 350             return NULL;
 351         }
 352 
 353         /*
 354          * Init all flags false, all refs NULL, all counts 0
 355          */
 356 
 357         saveGlobalRef(env, thread, &(node->thread));
 358         if (node->thread == NULL) {
 359             jvmtiDeallocate(node);
 360             bagDestroyBag(eventBag);
 361             EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry");
 362             return NULL;
 363         }
 364         /*
 365          * Remember if it is a debug thread
 366          */
 367         if (!is_fiber && threadControl_isDebugThread(node->thread)) {
 368             node->isDebugThread = JNI_TRUE;
 369         } else if (suspendAllCount > 0){
 370             /*
 371              * If there is a pending suspendAll, all new threads should
 372              * be initialized as if they were suspended by the suspendAll,
 373              * and the thread will need to be suspended when it starts.
 374              */
 375             node->suspendCount = suspendAllCount;
 376             node->suspendOnStart = JNI_TRUE;
 377         }
 378         node->current_ei = 0;
 379         node->is_fiber = is_fiber;
 380         node->instructionStepMode = JVMTI_DISABLE;
 381         node->eventBag = eventBag;
 382         addNode(list, node);
 383 
 384         /* Set thread local storage for quick thread -> node access.
 385          *   Some threads may not be in a state that allows setting of TLS,
 386          *   which is ok, see findThread, it deals with threads without TLS set.
 387          */
 388         if (!is_fiber) {
 389             setThreadLocalStorage(node->thread, (void*)node);
 390         }
 391 
 392         if (is_fiber) {
 393             node->isStarted = JNI_TRUE; /* Fibers are considered started by default. */
 394         }
 395     }
 396 
 397     return node;
 398 }
 399 
 400 static void
 401 clearThread(JNIEnv *env, ThreadNode *node)
 402 {
 403     if (node->pendingStop != NULL) {
 404         tossGlobalRef(env, &(node->pendingStop));
 405     }
 406     stepControl_clearRequest(node->thread, &node->currentStep);
 407     if (node->isDebugThread) {
 408         (void)threadControl_removeDebugThread(node->thread);
 409     }
 410     /* Clear out TLS on this thread (just a cleanup action) */
 411     if (!node->is_fiber) {
 412         setThreadLocalStorage(node->thread, NULL);
 413     }
 414     tossGlobalRef(env, &(node->thread));
 415     bagDestroyBag(node->eventBag);
 416     jvmtiDeallocate(node);
 417 }
 418 
 419 static void
 420 removeThread(JNIEnv *env, ThreadList *list, jthread thread)
 421 {
 422     ThreadNode *node;
 423 
 424     node = findThread(list, thread);
 425     if (node != NULL) {
 426         removeNode(list, node);
 427         clearThread(env, node);
 428     }
 429 }
 430 
 431 static void
 432 removeResumed(JNIEnv *env, ThreadList *list)
 433 {


 593 static void
 594 releaseLocks(void)
 595 {
 596     debugMonitorExit(threadLock);
 597     commonRef_unlock();
 598     stepControl_unlock();
 599     eventHelper_unlock();
 600     invoker_unlock();
 601     eventHandler_unlock();
 602 }
 603 
 604 void
 605 threadControl_initialize(void)
 606 {
 607     jlocation unused;
 608     jvmtiError error;
 609 
 610     suspendAllCount = 0;
 611     runningThreads.first = NULL;
 612     otherThreads.first = NULL;
 613     runningFibers.first = NULL;
 614     debugThreadCount = 0;
 615     threadLock = debugMonitorCreate("JDWP Thread Lock");
 616     if (gdata->threadClass==NULL) {
 617         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class");
 618     }
 619     if (gdata->threadResume==0) {
 620         EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread");
 621     }
 622     /* Get the java.lang.Thread.resume() method beginning location */
 623     error = methodLocation(gdata->threadResume, &resumeLocation, &unused);
 624     if (error != JVMTI_ERROR_NONE) {
 625         EXIT_ERROR(error, "getting method location");
 626     }
 627 }
 628 
 629 static jthread
 630 getResumee(jthread resumingThread)
 631 {
 632     jthread resumee = NULL;
 633     jvmtiError error;


 680     if (!pendingAppResume(JNI_TRUE)) {
 681         if (framePopHandlerNode != NULL) {
 682             (void)eventHandler_free(framePopHandlerNode);
 683             framePopHandlerNode = NULL;
 684         }
 685         if (catchHandlerNode != NULL) {
 686             (void)eventHandler_free(catchHandlerNode);
 687             catchHandlerNode = NULL;
 688         }
 689     }
 690 }
 691 
 692 static void
 693 handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo,
 694                           HandlerNode *handlerNode,
 695                           struct bag *eventBag)
 696 {
 697     ThreadNode *node;
 698     jthread     thread;
 699 
 700     /* fiber fixme: it's unclear how this is used and if anything special needs to be done for fibers. */
 701     JDI_ASSERT(!evinfo->matchesFiber);
 702 
 703     thread = evinfo->thread;
 704 
 705     debugMonitorEnter(threadLock);
 706 
 707     node = findThread(&runningThreads, thread);
 708     if (node != NULL) {
 709         if (node->resumeFrameDepth > 0) {
 710             jint compareDepth = getStackDepth(thread);
 711             if (evinfo->ei == EI_FRAME_POP) {
 712                 compareDepth--;
 713             }
 714             if (compareDepth < node->resumeFrameDepth) {
 715                 node->resumeFrameDepth = 0;
 716                 notifyAppResumeComplete();
 717             }
 718         }
 719     }
 720 
 721     debugMonitorExit(threadLock);
 722 }


 764                     (void)eventHandler_free(framePopHandlerNode);
 765                     framePopHandlerNode = NULL;
 766                     (void)eventHandler_free(catchHandlerNode);
 767                     catchHandlerNode = NULL;
 768                 }
 769             }
 770             if ((framePopHandlerNode != NULL) &&
 771                 (catchHandlerNode != NULL) &&
 772                 (frameDepth > 0)) {
 773                 node->resumeFrameDepth = frameDepth;
 774             }
 775         }
 776     }
 777 }
 778 
 779 static void
 780 handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo,
 781                           HandlerNode *handlerNode,
 782                           struct bag *eventBag)
 783 {
 784     /* fiber fixme: it's unclear how this is used and if anything special needs to be done for fibers. */
 785     JDI_ASSERT(!evinfo->matchesFiber);
 786 
 787     jthread resumer = evinfo->thread;
 788     jthread resumee = getResumee(resumer);
 789 
 790     debugMonitorEnter(threadLock);
 791     if (resumee != NULL) {
 792         /*
 793          * Hold up any attempt to resume as long as the debugger
 794          * has suspended the resumee.
 795          */
 796         blockOnDebuggerSuspend(resumee);
 797     }
 798 
 799     if (resumer != NULL) {
 800         /*
 801          * Track the resuming thread by marking it as being within
 802          * a resume and by setting up for notification on
 803          * a frame pop or exception. We won't allow the debugger
 804          * to suspend threads while any thread is within a
 805          * call to resume. This (along with the block above)
 806          * ensures that when the debugger


 873                 node = insertThread(env, &runningThreads, thread);
 874 
 875                 /*
 876                  * This is a tiny bit risky. We have to assume that the
 877                  * pre-existing threads have been started because we
 878                  * can't rely on a thread start event for them. The chances
 879                  * of a problem related to this are pretty slim though, and
 880                  * there's really no choice because without setting this flag
 881                  * there is no way to enable stepping and other events on
 882                  * the threads that already exist (e.g. the finalizer thread).
 883                  */
 884                 node->isStarted = JNI_TRUE;
 885             }
 886         }
 887 
 888     } END_WITH_LOCAL_REFS(env)
 889 
 890     debugMonitorExit(threadLock);
 891 }
 892 
 893 
 894 static jvmtiError
 895 resumeFiberHelperThread(JNIEnv *env, ThreadNode *node, void *ignored)
 896 {
 897     jvmtiError error = JVMTI_ERROR_NONE;
 898     if (node->fiberHelperThread != NULL) {
 899         error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
 900             (gdata->jvmti, node->fiberHelperThread);
 901         tossGlobalRef(env, &node->fiberHelperThread);
 902     }
 903     return error;
 904 }
 905 
 906 static void
 907 startTrackingSuspendedFiber(ThreadNode *fiberNode)
 908 {
 909     /* Add fiberNode to the start of the list. */
 910     fiberNode->prevTrackedSuspendedFiber = NULL;
 911     fiberNode->nextTrackedSuspendedFiber = trackedSuspendedFibers;
 912     trackedSuspendedFibers = fiberNode;
 913 
 914     /* Since we didn't previously increment suspendCount for each suspendAll(), do that now. */
 915     fiberNode->suspendCount = suspendAllCount;
 916 
 917     fiberNode->isTrackedSuspendedFiber = JNI_TRUE;
 918 }
 919 
 920 
 921 static void
 922 stopTrackingSuspendedFiber(ThreadNode *fiberNode)
 923 {
 924     /* Remove fiberNode from the list. */
 925     if (fiberNode->prevTrackedSuspendedFiber == NULL) {
 926         /* Node is at the start of the list. */
 927         trackedSuspendedFibers = fiberNode->nextTrackedSuspendedFiber;
 928     } else {
 929         fiberNode->prevTrackedSuspendedFiber->nextTrackedSuspendedFiber =
 930             fiberNode->nextTrackedSuspendedFiber;
 931     }
 932     if (fiberNode->nextTrackedSuspendedFiber != NULL) {
 933         fiberNode->nextTrackedSuspendedFiber->prevTrackedSuspendedFiber =
 934             fiberNode->prevTrackedSuspendedFiber;
 935     }
 936 
 937     /* If this fiber has a helper thread, we no longer need or want it. */
 938     if (fiberNode->fiberHelperThread != NULL) {
 939         resumeFiberHelperThread(getEnv(), fiberNode, NULL);
 940     }
 941 
 942     fiberNode->isTrackedSuspendedFiber = JNI_FALSE;
 943 }
 944 
 945 static jthread
 946 getFiberHelperThread(jthread fiber)
 947 {
 948     JNIEnv *env;
 949     ThreadNode *fiberNode;
 950     jthread helperThread;
 951 
 952     fiberNode = findThread(&runningFibers, fiber);
 953     if (fiberNode->fiberHelperThread != NULL) {
 954         return fiberNode->fiberHelperThread;
 955     }
 956 
 957     env = getEnv();
 958 
 959     /*
 960      * We need to mount the fiber on a helper thread. This is done by calling
 961      * Fiber.tryMountAndSuspend(), which will create a helper thread for us,
 962      * mount the fiber on the thread, suspend the thread, and then return the thread.
 963      *
 964      * This helper thread is disposed of by resumeFiberHelperThread() when it is 
 965      * determined that the helper thread is no longer need (the fiber was resumed,
 966      * and we are no longer tracking it).
 967      *
 968      * Disable all event handling while doing this, since we don't want to deal
 969      * with any incoming THREAD_START event.
 970      *
 971      * Also release the threadLock, or a deadlock will occur when the 
 972      * CONTINUATION_RUN event arrives on the helper thread.
 973      * fiber fixme: this might not be safe to do.
 974      */
 975     debugMonitorExit(threadLock);    
 976     gdata->ignoreEvents = JNI_TRUE;
 977     helperThread = JNI_FUNC_PTR(env,CallObjectMethod)
 978         (env, fiber, gdata->fiberTryMountAndSuspend);
 979     gdata->ignoreEvents = JNI_FALSE;
 980     debugMonitorEnter(threadLock);
 981 
 982 
 983     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
 984         JNI_FUNC_PTR(env,ExceptionClear)(env);
 985         helperThread = NULL;
 986     }
 987 
 988     if (helperThread != NULL) {
 989         saveGlobalRef(env, helperThread, &(fiberNode->fiberHelperThread));
 990         /* Start tracking this fiber as a suspended one. */
 991         startTrackingSuspendedFiber(fiberNode);
 992     }
 993 
 994     return fiberNode->fiberHelperThread;
 995 }
 996 
 997 static jvmtiError
 998 commonSuspendByNode(ThreadNode *node)
 999 {
1000     jvmtiError error;
1001 
1002     LOG_MISC(("thread=%p suspended", node->thread));
1003     error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)
1004                 (gdata->jvmti, node->thread);
1005 
1006     /*
1007      * Mark for resume only if suspend succeeded
1008      */
1009     if (error == JVMTI_ERROR_NONE) {
1010         node->toBeResumed = JNI_TRUE;
1011     }
1012 
1013     /*
1014      * If the thread was suspended by another app thread,
1015      * do nothing and report no error (we won't resume it later).
1016      */


1083     }
1084 
1085     if (node->suspendCount == 0) {
1086         error = commonSuspendByNode(node);
1087 
1088         if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
1089             /*
1090              * This error means that the thread is either a zombie or not yet
1091              * started. In either case, we ignore the error. If the thread
1092              * is a zombie, suspend/resume are no-ops. If the thread is not
1093              * started, it will be suspended for real during the processing
1094              * of its thread start event.
1095              */
1096             node->suspendOnStart = JNI_TRUE;
1097             error = JVMTI_ERROR_NONE;
1098         }
1099     }
1100 
1101     if (error == JVMTI_ERROR_NONE) {
1102         node->suspendCount++;
1103         if (gdata->fibersSupported) {
1104             /*
1105              * If this is a carrier thread with a mounted fiber, and the fiber
1106              * is being tracked, bump the fiber's suspendCount also.
1107              */
1108             jthread fiber = getThreadFiber(node->thread);
1109             if (fiber != NULL) {
1110                 ThreadNode *fiberNode = findThread(&runningFibers, fiber);
1111                 if (fiberNode != NULL && fiberNode->isTrackedSuspendedFiber) {
1112                     /* If tracking, bump the fiber suspendCount also. */
1113                     fiberNode->suspendCount++;
1114                 }
1115             }
1116         }
1117     }
1118 
1119     debugMonitorNotifyAll(threadLock);
1120 
1121     return error;
1122 }
1123 
1124 static jvmtiError
1125 resumeThreadByNode(ThreadNode *node)
1126 {
1127     jvmtiError error = JVMTI_ERROR_NONE;
1128 
1129     if (node->isDebugThread) {
1130         /* never suspended by debugger => don't ever try to resume */
1131         return JVMTI_ERROR_NONE;
1132     }
1133     if (node->suspendCount > 0) {
1134         if (gdata->fibersSupported) {
1135             /*
1136              * If this is a carrier thread with a mounted fiber, and the fiber
1137              * is being tracked, decrement the fiber's suspendCount also.
1138              */
1139             jthread fiber = getThreadFiber(node->thread);
1140             if (fiber != NULL) {
1141                 ThreadNode *fiberNode = findThread(&runningFibers, fiber);
1142                 if (fiberNode != NULL && fiberNode->isTrackedSuspendedFiber) {
1143                     /* If tracking, decrement the fiber suspendCount also. */
1144                     if (fiberNode->suspendCount > 0) {
1145                         fiberNode->suspendCount--;
1146                     }
1147                 }
1148             }
1149         }
1150         node->suspendCount--;
1151         debugMonitorNotifyAll(threadLock);
1152         if ((node->suspendCount == 0) && node->toBeResumed &&
1153             !node->suspendOnStart) {
1154             LOG_MISC(("thread=%p resumed", node->thread));
1155             error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)
1156                         (gdata->jvmti, node->thread);
1157             node->frameGeneration++; /* Increment on each resume */
1158             node->toBeResumed = JNI_FALSE;
1159             if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) {
1160                 /*
1161                  * We successfully "suspended" this thread, but
1162                  * we never received a THREAD_START event for it.
1163                  * Since the thread never ran, we can ignore our
1164                  * failure to resume the thread.
1165                  */
1166                 error = JVMTI_ERROR_NONE;
1167             }
1168         }
1169     }


1213         debugMonitorExit(threadLock);
1214 
1215         getLocks();
1216     }
1217 }
1218 
1219 static void
1220 postSuspend(void)
1221 {
1222     releaseLocks();
1223 }
1224 
1225 /*
1226  * This function must be called after preSuspend and before postSuspend.
1227  */
1228 static jvmtiError
1229 commonSuspend(JNIEnv *env, jthread thread, jboolean deferred)
1230 {
1231     ThreadNode *node;
1232 
1233     if (isFiber(thread)) {
1234         jvmtiError error = JVMTI_ERROR_NONE;
1235         while (JNI_TRUE) {
1236             jthread carrier_thread = getFiberThread(thread);
1237             if (carrier_thread != NULL) {
1238                 /* Fiber is mounted. Suspend the carrier thread. */
1239                 node = findThread(&runningThreads, carrier_thread);
1240                 error = suspendThreadByNode(node);
1241                 if (error != JVMTI_ERROR_NONE) {
1242                     LOG_MISC(("commonSuspend: failed to suspend carrier thread(%p)", carrier_thread));
1243                     return error;
1244                 }
1245                 if (isSameObject(env, carrier_thread, getFiberThread(thread))) {
1246                     /* Successfully suspended and still mounted on same carrier thread. */
1247                     break;
1248                 }
1249                 /* Fiber moved to new carrier thread before it was suspended. Undo and retry. */
1250                 resumeThreadByNode(node);
1251                 LOG_MISC(("commonSuspend: fiber mounted on different carrier thread(%p)", carrier_thread));
1252             } else {
1253                 /* Fiber is not mounted. Get a suspended helper thread for it. */
1254                 ThreadNode *fiberNode = findThread(&runningFibers, thread);
1255                 if (getFiberHelperThread(thread) == NULL) {
1256                     /* fiber fixme: Sometimes the fiber is in a bad state and we can't create a
1257                      * helper thread for it. For now we just fail. */
1258                     LOG_MISC(("commonSuspend: failed to get fiber helper thread."));
1259                     return JVMTI_ERROR_INTERNAL;
1260                 }
1261                 fiberNode->suspendCount++;
1262                 break;
1263             }
1264         }
1265         return error;
1266     }
1267 
1268     /*
1269      * If the thread is not between its start and end events, we should
1270      * still suspend it. To keep track of things, add the thread
1271      * to a separate list of threads so that we'll resume it later.
1272      */
1273     node = findThread(&runningThreads, thread);
1274 #if 0
1275     tty_message("commonSuspend: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1276 #endif
1277     if (node == NULL) {
1278         node = insertThread(env, &otherThreads, thread);
1279     }
1280 
1281     if ( deferred ) {
1282         return deferredSuspendThreadByNode(node);
1283     } else {
1284         return suspendThreadByNode(node);
1285     }
1286 }
1287 
1288 
1289 static jvmtiError
1290 resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg)
1291 {
1292     if (node->isDebugThread) {
1293         /* never suspended by debugger => don't ever try to resume */
1294         return JVMTI_ERROR_NONE;
1295     }
1296 


1564                  * during the processing of its thread start event.
1565                  */
1566                 node->suspendOnStart = JNI_TRUE;
1567                 results[i] = JVMTI_ERROR_NONE;
1568             }
1569 
1570             /* count real, app and deferred (suspendOnStart) suspensions */
1571             if (results[i] == JVMTI_ERROR_NONE) {
1572                 node->suspendCount++;
1573             }
1574         }
1575         deleteArray(results);
1576     }
1577     deleteArray(reqList);
1578 
1579     debugMonitorNotifyAll(threadLock);
1580 
1581     return error;
1582 }
1583 

1584 static jvmtiError
1585 commonResume(jthread thread)
1586 {
1587     jvmtiError  error;
1588     ThreadNode *node;
1589 
1590     if (isFiber(thread)) {
1591         jthread carrier_thread = getFiberThread(thread);
1592         ThreadNode *fiberNode = findThread(&runningFibers, thread);
1593         if (carrier_thread == NULL) {
1594             /*
1595              * Fiber is not mounted on a carrier thread. We may already be tracking this fiber as a
1596              * suspended fiber at this point. We would not be if a suspendAll was done, and there was
1597              * no suspend of just this fiber. If we are not tracking it, then we need to.
1598              */
1599             if (fiberNode->isTrackedSuspendedFiber) {
1600                 if (fiberNode->suspendCount > 0) {
1601                     fiberNode->suspendCount--;
1602                     /*
1603                      * Note, if suspendCount == 0 but suspendAllCount does not, eventually
1604                      * threadControl_resumeAll() will be responsible for calling
1605                      * stopTrackingSuspendedFiber()
1606                      */
1607                     if (fiberNode->suspendCount == 0 && suspendAllCount == 0) {
1608                         stopTrackingSuspendedFiber(fiberNode);
1609                     }
1610                 }
1611             } else {
1612                 if (suspendAllCount > 0) {
1613                     startTrackingSuspendedFiber(fiberNode);
1614                     fiberNode->suspendCount--;
1615                 }
1616             }
1617             return JVMTI_ERROR_NONE;
1618         } else {
1619             /*
1620              * This is a mounted fiber. If the fiber is being tracked, and the suspendCount
1621              * of the carrier thread is 0, then decrement the fiber's suspendCount here
1622              * since it cannot be done by resumeThreadByNode because we'll have no way to
1623              * get the fiber if the carrier thread is not suspended (getThreadFiber() will
1624              * produce a fatal error).
1625              */
1626             if (fiberNode->isTrackedSuspendedFiber) {
1627                 if (fiberNode->suspendCount > 0) {
1628                     ThreadNode *threadNode = findThread(NULL, thread);
1629                     if (threadNode->suspendCount == 0) {
1630                         fiberNode->suspendCount--;
1631                     }
1632                 }
1633             }
1634             /* Fiber is mounted on a carrier thread. Fall through to code below to resume
1635              * the carrier thread. */
1636             thread = carrier_thread;
1637         }
1638     }
1639 
1640     /*
1641      * The thread is normally between its start and end events, but if
1642      * not, check the auxiliary list used by threadControl_suspendThread.
1643      */
1644     node = findThread(NULL, thread);
1645 #if 0
1646     tty_message("commonResume: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name);
1647 #endif
1648 
1649     /*
1650      * If the node is in neither list, the debugger never suspended
1651      * this thread, so do nothing.
1652      */
1653     error = JVMTI_ERROR_NONE;
1654     if (node != NULL) {
1655         error = resumeThreadByNode(node);
1656     }
1657 
1658     return error;
1659 }
1660 
1661 
1662 jvmtiError
1663 threadControl_suspendThread(jthread thread, jboolean deferred)
1664 {
1665     jvmtiError error;
1666     JNIEnv    *env;
1667 
1668     env = getEnv();
1669 
1670     log_debugee_location("threadControl_suspendThread()", thread, NULL, 0);
1671 
1672     preSuspend();
1673     error = commonSuspend(env, thread, deferred);
1674     postSuspend();
1675 
1676     return error;
1677 }


1689     eventHandler_lock(); /* for proper lock order */
1690     debugMonitorEnter(threadLock);
1691     error = commonResume(thread);
1692     removeResumed(env, &otherThreads);
1693     debugMonitorExit(threadLock);
1694     eventHandler_unlock();
1695 
1696     if (do_unblock) {
1697         /* let eventHelper.c: commandLoop() know we resumed one thread */
1698         unblockCommandLoop();
1699     }
1700 
1701     return error;
1702 }
1703 
1704 jvmtiError
1705 threadControl_suspendCount(jthread thread, jint *count)
1706 {
1707     jvmtiError  error;
1708     ThreadNode *node;
1709     jboolean is_fiber = isFiber(thread);
1710 
1711     debugMonitorEnter(threadLock);
1712 
1713     if (is_fiber) {
1714         node = findThread(&runningFibers, thread);
1715     } else {
1716         node = findThread(&runningThreads, thread);
1717         if (node == NULL) {
1718             node = findThread(&otherThreads, thread);
1719         }
1720     }
1721 
1722     error = JVMTI_ERROR_NONE;
1723     if (node != NULL) {
1724         if (!is_fiber) {
1725             *count = node->suspendCount;
1726         } else {
1727             jthread carrier_thread = getFiberThread(thread);
1728             if (carrier_thread == NULL) {
1729                 if (node->isTrackedSuspendedFiber) {
1730                     /* Already tracking this fiber, so fiber node owns its suspendCount. */
1731                     *count = node->suspendCount;
1732                 } else {
1733                     /* Not tacking this fiber yet, so use suspendAllCount. */
1734                     *count = suspendAllCount;
1735                 }
1736             } else {
1737                 /* It's a mounted fiber, so the carrier thread tracks the suspend count. */
1738                 node = findThread(&runningThreads, carrier_thread);
1739                 JDI_ASSERT(node != NULL);
1740                 *count = node->suspendCount;
1741             }
1742         }
1743     } else {
1744         /*
1745          * If the node is in neither list, the debugger never suspended
1746          * this thread, so the suspend count is 0.
1747          */
1748         *count = 0;
1749     }
1750 
1751     debugMonitorExit(threadLock);
1752 
1753     return error;
1754 }
1755 
1756 static jboolean
1757 contains(JNIEnv *env, jthread *list, jint count, jthread item)
1758 {
1759     int i;
1760 
1761     for (i = 0; i < count; i++) {
1762         if (isSameObject(env, list[i], item)) {


1773 } SuspendAllArg;
1774 
1775 static jvmtiError
1776 suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg)
1777 {
1778     SuspendAllArg *saArg = (SuspendAllArg *)arg;
1779     jvmtiError error = JVMTI_ERROR_NONE;
1780     jthread *list = saArg->list;
1781     jint count = saArg->count;
1782     if (!contains(env, list, count, node->thread)) {
1783         error = commonSuspend(env, node->thread, JNI_FALSE);
1784     }
1785     return error;
1786 }
1787 
1788 jvmtiError
1789 threadControl_suspendAll(void)
1790 {
1791     jvmtiError error;
1792     JNIEnv    *env;
1793 #if 0
1794     tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount);
1795 #endif
1796 
1797     env = getEnv();
1798 
1799     log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0);
1800 
1801     preSuspend();
1802 
1803     /*
1804      * Get a list of all threads and suspend them.
1805      */
1806     WITH_LOCAL_REFS(env, 1) {
1807 
1808         jthread *threads;
1809         jint count;
1810 
1811         threads = allThreads(&count);
1812         if (threads == NULL) {
1813             error = AGENT_ERROR_OUT_OF_MEMORY;
1814             goto err;
1815         }
1816         if (canSuspendResumeThreadLists()) {
1817             error = commonSuspendList(env, count, threads);
1818             if (error != JVMTI_ERROR_NONE) {
1819                 goto err;
1820             }
1821         } else {

1822             int i;

1823             for (i = 0; i < count; i++) {
1824                 error = commonSuspend(env, threads[i], JNI_FALSE);
1825 
1826                 if (error != JVMTI_ERROR_NONE) {
1827                     goto err;
1828                 }
1829             }
1830         }
1831 
1832         /*
1833          * Update the suspend count of any threads not yet (or no longer)
1834          * in the thread list above.
1835          */
1836         {
1837             SuspendAllArg arg;
1838             arg.list = threads;
1839             arg.count = count;
1840             error = enumerateOverThreadList(env, &otherThreads,
1841                                             suspendAllHelper, &arg);
1842         }
1843 
1844         /*
1845          * Update the suspend count of any fiber that was explicitly suspended
1846          * and had a helper thread created for that purpose. These are known
1847          * as "tracked" suspended fibers.
1848          */
1849         debugMonitorEnter(threadLock);
1850         {
1851             ThreadNode *trackedSuspendedFiber = trackedSuspendedFibers;
1852             while (trackedSuspendedFiber != NULL) {
1853                 trackedSuspendedFiber->suspendCount++;
1854                 trackedSuspendedFiber = trackedSuspendedFiber->nextTrackedSuspendedFiber;
1855             }
1856         }
1857         debugMonitorExit(threadLock);
1858 
1859         if (error == JVMTI_ERROR_NONE) {
1860             suspendAllCount++;
1861         }
1862 
1863     err: ;
1864 
1865     } END_WITH_LOCAL_REFS(env)
1866 
1867     postSuspend();
1868 
1869     return error;
1870 }
1871 
1872 static jvmtiError
1873 resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored)
1874 {
1875     /*
1876      * Since this helper is called with the threadLock held, we
1877      * don't need to recheck to see if the node is still on one
1878      * of the two thread lists.
1879      */
1880     return resumeThreadByNode(node);
1881 }
1882 
1883 jvmtiError
1884 threadControl_resumeAll(void)
1885 {
1886     jvmtiError error;
1887     JNIEnv    *env;
1888 #if 0
1889     tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount);
1890 #endif
1891 
1892     env = getEnv();
1893 
1894     log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0);
1895 
1896     eventHandler_lock(); /* for proper lock order */
1897     debugMonitorEnter(threadLock);
1898 
1899     /*
1900      * Resume only those threads that the debugger has suspended. All
1901      * such threads must have a node in one of the thread lists, so there's
1902      * no need to get the whole thread list from JVMTI (unlike
1903      * suspendAll).
1904      */
1905     if (canSuspendResumeThreadLists()) {
1906         error = commonResumeList(env);
1907     } else {
1908         error = enumerateOverThreadList(env, &runningThreads,
1909                                         resumeHelper, NULL);
1910     }
1911     if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) {
1912         error = enumerateOverThreadList(env, &otherThreads,
1913                                         resumeHelper, NULL);
1914         removeResumed(env, &otherThreads);
1915     }
1916 
1917     if (suspendAllCount > 0) {
1918         suspendAllCount--;
1919     }
1920 
1921     /*
1922      * Update the suspend count of any fiber that is being tracked. If it is being
1923      * tracked, that means that either it was explicitly suspended and had a helper
1924      * thread created for helping to suspend it, or it had helper thread created for
1925      * the purpose of getting its stack. If the count reaches zero, then stop tracking the fiber.
1926      */
1927     {
1928         ThreadNode *trackedSuspendedFiber = trackedSuspendedFibers;
1929         while (trackedSuspendedFiber != NULL) {
1930             ThreadNode *fiberNode = trackedSuspendedFiber;
1931             trackedSuspendedFiber = trackedSuspendedFiber->nextTrackedSuspendedFiber;
1932             if (fiberNode->suspendCount > 0) {
1933                 fiberNode->suspendCount--;
1934             }
1935             if (fiberNode->suspendCount == 0 && suspendAllCount == 0) {
1936                 stopTrackingSuspendedFiber(fiberNode);
1937             }
1938         }
1939     }
1940 
1941     debugMonitorExit(threadLock);
1942     eventHandler_unlock();
1943     /* let eventHelper.c: commandLoop() know we are resuming */
1944     unblockCommandLoop();
1945 
1946     return error;
1947 }
1948 
1949 
1950 StepRequest *
1951 threadControl_getStepRequest(jthread thread)
1952 {
1953     ThreadNode  *node;
1954     StepRequest *step;
1955 
1956     step = NULL;
1957 
1958     debugMonitorEnter(threadLock);
1959 
1960     node = findThread(&runningThreads, thread);


2348                 /*        completion of the pop frame */
2349                 popFrameCompleteEvent(thread);
2350                 return JNI_TRUE;
2351             case EI_BREAKPOINT:
2352             case EI_EXCEPTION:
2353             case EI_FIELD_ACCESS:
2354             case EI_FIELD_MODIFICATION:
2355             case EI_METHOD_ENTRY:
2356             case EI_METHOD_EXIT:
2357                 /* Tell event handler to assume event has been consumed. */
2358                 return JNI_TRUE;
2359             default:
2360                 break;
2361         }
2362     }
2363     /* Pretend we were never called */
2364     return JNI_FALSE;
2365 }
2366 
2367 struct bag *
2368 threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject currentException)
2369 {
2370     ThreadNode *node;
2371     JNIEnv     *env;
2372     struct bag *eventBag;
2373     jthread     threadToSuspend;
2374     jboolean    consumed;
2375     EventIndex  ei = evinfo->ei;
2376     jthread     thread = evinfo->thread;
2377 
2378     env             = getEnv();
2379     threadToSuspend = NULL;
2380 
2381     log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL, 0);
2382 
2383     /* Events during pop commands may need to be ignored here. */
2384     consumed = checkForPopFrameEvents(env, ei, thread);
2385     if ( consumed ) {
2386         /* Always restore any exception (see below). */
2387         if (currentException != NULL) {
2388             JNI_FUNC_PTR(env,Throw)(env, currentException);
2389         } else {
2390             JNI_FUNC_PTR(env,ExceptionClear)(env);
2391         }
2392         return NULL;
2393     }
2394 
2395     debugMonitorEnter(threadLock);
2396 


2495              * Clean up mechanism used to detect end of
2496              * resume.
2497              */
2498             if (inResume) {
2499                 notifyAppResumeComplete();
2500             }
2501         } else {
2502             /* No point in doing this if the thread is about to die.*/
2503             doPendingTasks(env, node);
2504             node->eventBag = eventBag;
2505             node->current_ei = 0;
2506         }
2507     }
2508 
2509     debugMonitorExit(threadLock);
2510     if (ei == EI_THREAD_END) {
2511         eventHandler_unlock();
2512     }
2513 }
2514 
2515 void
2516 threadControl_setName(jthread thread, const char *name)
2517 {
2518 #ifdef DEBUG_THREADNAME
2519     ThreadNode *node = findThread(NULL, thread);
2520     if (node != NULL) {
2521         strncpy(node->name, name, sizeof(node->name) - 1);
2522     }
2523 #endif
2524 }
2525 
2526 /* Returns JDWP flavored status and status flags. */
2527 jvmtiError
2528 threadControl_applicationThreadStatus(jthread thread,
2529                         jdwpThreadStatus *pstatus, jint *statusFlags)
2530 {
2531     ThreadNode *node = NULL;
2532     jvmtiError  error;
2533     jint        state;
2534     jboolean    is_fiber = isFiber(thread);
2535 
2536     log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0);
2537 
2538     debugMonitorEnter(threadLock);
2539 
2540     if (!is_fiber) {
2541         error = threadState(thread, &state);
2542         *pstatus = map2jdwpThreadStatus(state);
2543         *statusFlags = map2jdwpSuspendStatus(state);

2544         node = findThread(&runningThreads, thread);
2545 
2546         if (error == JVMTI_ERROR_NONE) {
2547             if ((node != NULL) && HANDLING_EVENT(node)) {
2548                 /*
2549                  * While processing an event, an application thread is always
2550                  * considered to be running even if its handler happens to be
2551                  * cond waiting on an internal debugger monitor, etc.
2552                  *
2553                  * Leave suspend status untouched since it is not possible
2554                  * to distinguish debugger suspends from app suspends.
2555                  */
2556                 *pstatus = JDWP_THREAD_STATUS(RUNNING);
2557             }
2558         }
2559 #if 0
2560         tty_message("status thread: node(%p) suspendCount(%d) %d %d %s",
2561                     node, node->suspendCount, *pstatus, *statusFlags, node->name);
2562 #endif
2563     } else { /* It's a fiber */
2564         int suspendCount;
2565         error = JVMTI_ERROR_NONE;
2566         *pstatus = JDWP_THREAD_STATUS(RUNNING);
2567         *statusFlags = 0;
2568         node = findThread(&runningFibers, thread);
2569         if (node->isTrackedSuspendedFiber) {
2570             /* Already tracking this fiber, so fiber node owns its suspendCount. */
2571             suspendCount = node->suspendCount;
2572         } else {
2573             /* Not tacking this fiber yet, so use suspendAllCount. */
2574             suspendCount = suspendAllCount;
2575         }
2576         if (suspendCount > 0) {
2577             *statusFlags = JDWP_SUSPEND_STATUS(SUSPENDED);
2578         } else {
2579             /* If the fiber was not suspended, maybe it's carrier thread was. */
2580             thread = getFiberThread(thread);
2581             if (thread != NULL) {
2582                 node = findThread(&runningThreads, thread);
2583                 if (node->suspendCount > 0) {
2584                     *statusFlags = JDWP_SUSPEND_STATUS(SUSPENDED);
2585                 }
2586             }
2587         }
2588 #if 0
2589         tty_message("status thread: fiber(%p) suspendCount(%d) %d %d %s",
2590                     node, node->suspendCount, *pstatus, *statusFlags, node->name);
2591 #endif
2592     }
2593 
2594     debugMonitorExit(threadLock);
2595 
2596     return error;
2597 }
2598 
2599 jvmtiError
2600 threadControl_interrupt(jthread thread)
2601 {
2602     ThreadNode *node;
2603     jvmtiError  error;
2604 
2605     error = JVMTI_ERROR_NONE;
2606 
2607     log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
2608 
2609     debugMonitorEnter(threadLock);
2610 
2611     node = findThread(&runningThreads, thread);


2763         node->frameGeneration++; /* Increment on each resume */
2764     }
2765     stepControl_clearRequest(node->thread, &node->currentStep);
2766     node->toBeResumed = JNI_FALSE;
2767     node->suspendCount = 0;
2768     node->suspendOnStart = JNI_FALSE;
2769 
2770     return JVMTI_ERROR_NONE;
2771 }
2772 
2773 void
2774 threadControl_reset(void)
2775 {
2776     JNIEnv *env;
2777 
2778     env = getEnv();
2779     eventHandler_lock(); /* for proper lock order */
2780     debugMonitorEnter(threadLock);
2781     (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL);
2782     (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL);
2783     (void)enumerateOverThreadList(env, &runningFibers, resetHelper, NULL);
2784 
2785     removeResumed(env, &otherThreads);
2786 
2787     freeDeferredEventModes(env);
2788 
2789     suspendAllCount = 0;
2790 
2791     /* Everything should have been resumed */
2792     JDI_ASSERT(otherThreads.first == NULL);
2793 
2794     debugMonitorExit(threadLock);
2795     eventHandler_unlock();
2796 }
2797 
2798 jvmtiEventMode
2799 threadControl_getInstructionStepMode(jthread thread)
2800 {
2801     ThreadNode    *node;
2802     jvmtiEventMode mode;
2803 


2810     }
2811     debugMonitorExit(threadLock);
2812     return mode;
2813 }
2814 
2815 jvmtiError
2816 threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
2817 {
2818     jvmtiError error;
2819 
2820     /* Global event */
2821     if ( thread == NULL ) {
2822         error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
2823                     (gdata->jvmti, mode, eventIndex2jvmti(ei), thread);
2824     } else {
2825         /* Thread event */
2826         ThreadNode *node;
2827 
2828         debugMonitorEnter(threadLock);
2829         {
2830             if (isFiber(thread)) {
2831                 /* fiber fixme: Getting the carrier thread here is just a hack. It does not work if
2832                  * the fiber is not mounted, and even if mounted, does not result in the correct
2833                  * behaviour if the fiber changes carrier threads. If the carrier thread is
2834                  * NULL we need to defer all the code below, most notably
2835                  * threadSetEventNotificationMode(), until after the fiber is mounted. We also need
2836                  * to call threadSetEventNotificationMode() each time there is an unmount or mount
2837                  * since the thread that needs notifications will change as the fiber moves
2838                  * between carrier threads. The best way to manage this might be to move
2839                  * HandlerNodes for unmounted fibers onto a linked list hanging off the fiber's
2840                  * ThreadNode. But that also complicates finding HandlerNodes. For example,
2841                  * when a breakpoint is cleared, we call eventHandler_freeByID(), which would
2842                  * need to also search every fiber for the handler. The other choice is to
2843                  * keep handlers where they are now (off the array of handler chains), but
2844                  * for every mount/unmount, search all the handlers in all the chains for
2845                  * ones that are for the mounting/unmounting fiber. This could be slow,
2846                  * although generally speaking we don't have many HandlerNodes because
2847                  * they are generated indirectly by the debugger as users do things
2848                  * like set breakpoints.
2849                  * A hybrid approach might be best. Keep the handler chains as they are now,
2850                  * but also have each fiber maintain a list of its handler nodes for faster
2851                  * handling during mount/unmount.
2852                  *
2853                  * And it should also be noted here that if the carrier thread is null, the
2854                  * findThread() call ends up returning the current thread, and then 
2855                  * threadSetEventNotificationMode() is called with a NULL thread, resulting
2856                  * in the event being enabled on all threads. This bug actually has the 
2857                  * desireable affect of making breakpoints that are filtered on an unmounted
2858                  * fiber work as expected, because all the carrier threads get the breakpoint
2859                  * event enabled. However, for some odd reason it also works as expected if
2860                  * the fiber is already mounted. I expected that the breakpoint event would only
2861                  * be enabled on the carrier thread in that case, and therefore if the fiber
2862                  * was moved to a different carrier thread, you would stop getting breakpoints
2863                  * until it moved back to the original carrier thread. That's not the case for some
2864                  * reason, and I'm see the breakpoints no matter what carrier thread the fiber
2865                  * runs on. It turns out that the agent installs a global breakpoint for
2866                  * Thread.resume(), so global breakpoints are always enabled.
2867                  * See handleAppResumeBreakpoint.
2868                  *
2869                  * It also should be noted that this does not cause a problem for single stepping
2870                  * because:
2871                  *  - There is at most one single step HandlerNode per thread.
2872                  *  - Fiber mount/unmount events result explicitly dooing the proper
2873                  *    enabling/disabling of the JVMTI single step event on the carrier thread.
2874                  * There is a potential issue with initiating a StepRequest on and unmounted
2875                  * fiber. See the fixme comment in stepControl_beginStep.
2876                  */ 
2877                 thread = getFiberThread(thread);
2878             }
2879             node = findThread(&runningThreads, thread);
2880             if ((node == NULL) || (!node->isStarted)) {
2881                 JNIEnv *env;
2882 
2883                 env = getEnv();
2884                 error = addDeferredEventMode(env, mode, ei, thread);
2885             } else {
2886                 error = threadSetEventNotificationMode(node,
2887                         mode, ei, thread);
2888             }
2889         }
2890         debugMonitorExit(threadLock);
2891 
2892     }
2893     return error;
2894 }
2895 
2896 /*
2897  * Returns the current thread, if the thread has generated at least
2898  * one event, and has not generated a thread end event.
2899  */
2900 jthread
2901 threadControl_currentThread(void)
2902 {
2903     jthread thread;
2904 
2905     debugMonitorEnter(threadLock);
2906     {
2907         ThreadNode *node;
2908 
2909         node = findThread(&runningThreads, NULL);
2910         thread = (node == NULL) ? NULL : node->thread;
2911     }
2912     debugMonitorExit(threadLock);
2913 
2914     return thread;
2915 }
2916 
2917 jlong
2918 threadControl_getFrameGeneration(jthread thread)
2919 {
2920     jlong frameGeneration = -1;
2921 
2922     debugMonitorEnter(threadLock);
2923     {
2924         ThreadNode *node;
2925 
2926         node = findThread(NULL, thread);
2927 
2928         if (node != NULL) {
2929             frameGeneration = node->frameGeneration;
2930         }
2931     }
2932     debugMonitorExit(threadLock);
2933 
2934     return frameGeneration;
2935 }
2936 
2937 jthread
2938 threadControl_getFiberCarrierOrHelperThread(jthread fiber)
2939 {
2940     /* Get the carrier thread that the fiber is running on */
2941     jthread carrier_thread = getFiberThread(fiber);
2942     if (carrier_thread != NULL) {
2943         return carrier_thread;
2944     } else {
2945         jthread helperThread;
2946         debugMonitorEnter(threadLock);
2947         helperThread = getFiberHelperThread(fiber);
2948         debugMonitorExit(threadLock);
2949         if (helperThread == NULL) {
2950             /* fiber fixme: we failed to get the helper thread, probably because the fiber
2951              * is currently in the PARKING state. Still need a solution for this. Fix
2952              * all callers too.
2953              */
2954             LOG_MISC(("threadControl_getFiberCarrierOrHelperThread: getFiberHelperThread() failed"));
2955         }
2956         return helperThread;
2957     }
2958 }
2959 
2960 jthread *
2961 threadControl_allFibers(jint *numFibers)
2962 {
2963     JNIEnv *env;
2964     ThreadNode *node;
2965     jthread* fibers;
2966 
2967     env = getEnv();
2968     debugMonitorEnter(threadLock);
2969 
2970     /* Count the number of fibers */
2971     /* fiber fixme: we should keep a running total so no counting is needed. */
2972     *numFibers = 0;
2973     for (node = runningFibers.first; node != NULL; node = node->next) {
2974         (*numFibers)++;
2975     }
2976 
2977     /* Allocate and fill in the fibers array. */
2978     fibers = jvmtiAllocate(*numFibers * sizeof(jthread*));
2979     if (fibers != NULL) {
2980         int i = 0;
2981         for (node = runningFibers.first; node != NULL;  node = node->next) {
2982             fibers[i++] = node->thread;
2983         }
2984     }
2985 
2986     debugMonitorExit(threadLock);
2987 
2988     return fibers;
2989 }
2990 
2991 jboolean threadControl_isKnownFiber(jthread fiber) {
2992     ThreadNode *fiberNode;
2993     debugMonitorEnter(threadLock);
2994     fiberNode = findThread(&runningFibers, fiber);
2995     debugMonitorExit(threadLock);
2996     return fiberNode != NULL;
2997 }
2998 
2999 void
3000 threadControl_addFiber(jthread fiber)
3001 {
3002     ThreadNode *fiberNode;
3003     debugMonitorEnter(threadLock);
3004     fiberNode = insertThread(getEnv(), &runningFibers, fiber);
3005     debugMonitorExit(threadLock);
3006 }
3007 
3008 void
3009 threadControl_mountFiber(jthread fiber, jthread thread, jbyte sessionID) {
3010     /* fiber fixme: this funciton no longer serves any purpose now that we rely on
3011      * continuation events instead. remove.
3012      */
3013 }
3014 
3015 
3016 void
3017 threadControl_unmountFiber(jthread fiber, jthread thread)
3018 {
3019     /* fiber fixme: this funciton no longer serves any purpose now that we rely on
3020      * continuation events instead. remove.
3021      */
3022 }
3023 
3024 void
3025 threadControl_continuationRun(jthread thread, jint continuation_frame_count)
3026 {
3027     debugMonitorEnter(threadLock);
3028     {
3029         JNIEnv *env = getEnv();
3030         ThreadNode *threadNode;
3031         ThreadNode *fiberNode;
3032         jthread fiber;
3033 
3034         threadNode = findThread(&runningThreads, thread);
3035 
3036         /*
3037          * fiber fixme: For now, NULL implies that this is a helper thread created by
3038          * getFiberHelperThread(). We should actually verify that, but for now just
3039          * assume it is the case and ignore the event. The need for helper threads will
3040          * hopefully go away, in which case the assert can be re-added.
3041          */
3042         //JDI_ASSERT(threadNode != NULL);
3043         if (threadNode == NULL) {
3044             debugMonitorExit(threadLock);
3045             return;
3046         }
3047 
3048         JDI_ASSERT(threadNode->isStarted);
3049         JDI_ASSERT(bagSize(threadNode->eventBag) == 0);
3050 
3051         if (threadNode->currentStep.pending) {
3052             /*
3053              * If we are doing a STEP_INTO and are doing class filtering (usually library
3054              * classes), we are relying on METHOD_ENTRY events to tell us if we've stepped
3055              * back into user code. We won't get this event if when we resume the
3056              * continuation, so we need to let the stepControl now that we got a
3057              * CONTINUATION_RUN event so it can do the right thing in absense of
3058              * the METHOD_ENTRY event. There's also a FramePop setup situation that
3059              * stepControl needs to deal with, which is another reason it needs to
3060              * know about CONTINUATION_RUN events.
3061              */
3062             stepControl_handleContinuationRun(env, thread, &threadNode->currentStep);
3063         }
3064 
3065         fiber = getThreadFiber(threadNode->thread);
3066         if (fiber == NULL) {
3067             debugMonitorExit(threadLock);
3068             return; /* Nothing more to do if thread is not executing a fiber. */
3069         }
3070 
3071         fiberNode = findThread(&runningFibers, fiber);
3072         if (!gdata->notifyDebuggerOfAllFibers && fiberNode == NULL) {
3073             /* This is not a fiber we are tracking, so nothing to do. */
3074             debugMonitorExit(threadLock);
3075             return;
3076         }
3077 
3078         JDI_ASSERT(fiberNode != NULL);
3079         JDI_ASSERT(fiberNode->isStarted);
3080         JDI_ASSERT(bagSize(fiberNode->eventBag) == 0);
3081 
3082         /* If we are not single stepping in this fiber then there is nothing to do. */
3083         if (!fiberNode->currentStep.pending) {
3084             debugMonitorExit(threadLock);
3085             return;
3086         }
3087         JDI_ASSERT(fiberNode->currentStep.is_fiber);
3088 
3089         /*
3090          * Move the single step state from the fiberNode to threadNode, but only if we aren't
3091          * already single stepping on the carrier thread.
3092          */
3093         if (!threadNode->currentStep.pending) {
3094             /* Copy fiber currentStep struct to carrier thread. */
3095             memcpy(&threadNode->currentStep, &fiberNode->currentStep, sizeof(fiberNode->currentStep));
3096 
3097             /* Enable JVMTI single step on the carrier thread if necessary. */
3098             if (fiberNode->instructionStepMode == JVMTI_ENABLE) {
3099                 stepControl_enableStepping(thread);
3100                 threadNode->instructionStepMode = JVMTI_ENABLE;
3101             }
3102 
3103             /* Restore the NotifyFramePop that was in place when this Fiber yielded. */
3104             {
3105                 jvmtiError error;
3106                 jint depth;
3107                 /* NotifyFramePop was originally called with a depth of 0 to indicate the current
3108                  * frame. However, frames have been pushed since then, so we need to adjust the
3109                  * depth to get to the right frame.
3110                  *
3111                  * fromStackDepth represents the number of frames on the stack when the STEP_OVER
3112                  * was started. NotifyFramePop was called on the method that was entered, which is
3113                  * one frame below (fromStackDepth + 1). To account for new frames pushed since
3114                  * then, we subtract fromStackDepth from the current number of frames. This
3115                  * represents the frame where the STEP_OVER was done, but since we want one
3116                  * frame below this point, we also subtract one.
3117                  */
3118                 depth = getThreadFrameCount(thread) - fiberNode->currentStep.fromStackDepth;
3119                 depth--; /* We actually want the frame one below the adjusted fromStackDepth. */
3120                 if (depth >= 0) {
3121                     error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)(gdata->jvmti, thread, depth);
3122                     if (error == JVMTI_ERROR_DUPLICATE) {
3123                       error = JVMTI_ERROR_NONE;
3124                       /* Already being notified, continue without error */
3125                     } else if (error != JVMTI_ERROR_NONE) {
3126                       EXIT_ERROR(error, "NotifyFramePop failed during mountFiber");
3127                     }
3128                 } else {
3129                     /*
3130                      * If the less than 0, then that means we were single stepping over
3131                      * the Continuation.doYield() call. In this case NotifyFramePop is not going to work
3132                      * since there was never one setup (doYield() was never actually entered). So
3133                      * all that needs to be done is to restore single stepping, and we'll stop
3134                      * on the next bytecode after the doYield() call.
3135                      */
3136                     JDI_ASSERT(depth == -1);
3137                     if (fiberNode->instructionStepMode == JVMTI_DISABLE) {
3138                       stepControl_enableStepping(thread);
3139                       threadNode->instructionStepMode = JVMTI_ENABLE;
3140                     }
3141                 }
3142             }
3143    
3144             /* Enable events */
3145             threadControl_setEventMode(JVMTI_ENABLE, EI_EXCEPTION_CATCH, thread);
3146             threadControl_setEventMode(JVMTI_ENABLE, EI_FRAME_POP, thread);
3147             if (threadNode->currentStep.methodEnterHandlerNode != NULL) {
3148                 threadControl_setEventMode(JVMTI_ENABLE, EI_METHOD_ENTRY, thread);
3149             }
3150         }
3151 
3152         /* Always clear the fiber single step state, regardless of what we've done above. */
3153         fiberNode->instructionStepMode = JVMTI_DISABLE;
3154         memset(&fiberNode->currentStep, 0, sizeof(fiberNode->currentStep));
3155 
3156         /*
3157          * If for any reason we are tracking this fiber, then that must mean during a 
3158          * suspendAll there was a resume done on this fiber. So we started tracking it
3159          * and decremented its suspendCount (which normally would put it at 0).
3160          */
3161         if (fiberNode->isTrackedSuspendedFiber) {
3162             JDI_ASSERT(suspendAllCount > 0 && fiberNode->suspendCount == 0);
3163         }
3164         if (suspendAllCount > 0) {
3165             /*
3166              * If there is an outstanding suspendAll, then we suspend the carrier thread. The
3167              * way this typically ends up happening is if initially all threads were suspended
3168              * (perhaps when a breakpoing was hit), and then the debugger user decides to resume
3169              * the fiber or carrier thread. This could allow a new fiber to be mounted on the
3170              * carrier thread, but the fiber is implied to be suspended because suspendAllCount
3171              * is >0. In order to keep the fiber from running we must suspened the carrier thread.
3172              */
3173             /* fiber fixme XXX: disable this feature for now. */
3174             //eventHelper_suspendThread(sessionID, thread);
3175         }
3176     }
3177     debugMonitorExit(threadLock);
3178 }
3179 
3180 void
3181 threadControl_continuationYield(jthread thread, jint continuation_frame_count)
3182 {
3183     /* fiber fixme: need to figure out what to do with these 4 ThreadNode fields:
3184        unsigned int popFrameEvent : 1;
3185        unsigned int popFrameProceed : 1;
3186        unsigned int popFrameThread : 1;
3187        InvokeRequest currentInvoke;
3188     */
3189     debugMonitorEnter(threadLock);
3190     {
3191         JNIEnv *env = getEnv();
3192         ThreadNode *threadNode;
3193         jint total_frame_count;
3194         jint fromDepth;
3195 
3196         threadNode = findThread(&runningThreads, thread);
3197 
3198         /*
3199          * fiber fixme: For now, NULL implies that this is a helper thread created by
3200          * getFiberHelperThread(). We should actually verify that, but for now just
3201          * assume it is the case and ignore the event. The need for helper threads will
3202          * hopefully go away, in which case the assert can be re-added.
3203          */
3204         //JDI_ASSERT(threadNode != NULL);
3205         if (threadNode == NULL) {
3206             debugMonitorExit(threadLock);
3207             return; /* Nothing to do if thread is not known */
3208         }
3209 
3210         JDI_ASSERT(threadNode->isStarted);
3211         JDI_ASSERT(bagSize(threadNode->eventBag) == 0);
3212 
3213         /*
3214          * If we are not single stepping in this thread, then there is nothing to do.
3215          */
3216         if (!threadNode->currentStep.pending) {
3217             debugMonitorExit(threadLock);
3218             return; /* Nothing to do. */
3219         }
3220 
3221         /* At what depth were we single stepping. */
3222         fromDepth = threadNode->currentStep.fromStackDepth;
3223 
3224         /*
3225          * Note the continuation has already been unmounted, so total_frame_count will not
3226          * include the continuation frames.
3227          */
3228         total_frame_count = getThreadFrameCount(thread);
3229 
3230         if (threadNode->currentStep.depth == JDWP_STEP_DEPTH(OVER) &&
3231             total_frame_count == fromDepth) {
3232             /*
3233              * We were stepping over Continuation.doContinue() in Continuation.run(). This
3234              * is a special case. Before the continuation was unmounted do to the yield, the
3235              * stack looked like:
3236              *    java.lang.Continuation.yield0
3237              *    java.lang.Continuation.yield
3238              *    <fiber frames>  <-- if Fiber, otherwise just additional continuation frames
3239              *    java.lang.Continuation.enter  <-- bottommost continuation frame
3240              *    java.lang.Continuation.run    <-- doContinue() call jumps into continuation
3241              *    java.lang.Fiber.runContinuation  <-- if Fiber, otherwise will be different
3242              *    <scheduler frames>
3243              * All frames above run(), starting with enter(), are continuation frames. The
3244              * correct thing to do here is just enable single stepping. This will resume single
3245              * stepping in Continuation.run() right after the Continuation.doContinue() call.
3246              */
3247             JDI_ASSERT(threadNode->instructionStepMode == JVMTI_DISABLE);
3248             {
3249                 stepControl_enableStepping(thread);
3250                 threadNode->instructionStepMode = JVMTI_ENABLE;
3251             }
3252         } else if (!threadNode->currentStep.is_fiber) {
3253             /* We were single stepping, but not in a fiber. */
3254             if (total_frame_count < fromDepth) { /* Check if fromDepth is in the continuation. */
3255                 /*
3256                  * This means the frame we were single stepping in was part of the set of
3257                  * frames that will were frozen when this continuation yielded. Because of that
3258                  * we need to re-enable single stepping because we won't ever be getting
3259                  * the FRAME_POP event for returning to that frame. This will resume single
3260                  * stepping in Continuation.run() right after the Continuation.enter() call.
3261                  */
3262                 if (threadNode->instructionStepMode == JVMTI_DISABLE) {
3263                     stepControl_enableStepping(thread);
3264                     threadNode->instructionStepMode = JVMTI_ENABLE;
3265                 }
3266             } else {
3267                 /*
3268                  * We are not single stepping in the continuation, and from the earlier check we
3269                  * know we are not single stepping in Continuation.run(), because that would imply
3270                  * we were single stepping over the doContinue() call, and we already checked
3271                  * for that. There is nothing to do in this case. A NotifyFramePop is already setup
3272                  * for a frame further up the stack.
3273                  */
3274             }
3275         } else {
3276             /*
3277              * We are single stepping the fiber, not the carrier thread. Move the single step
3278              * state to the fiberNode.
3279              */
3280             jthread fiber = getThreadFiber(thread);
3281             ThreadNode *fiberNode;
3282             JDI_ASSERT(fiber != NULL);
3283 
3284             fiberNode = findThread(&runningFibers, fiber);
3285             if (!gdata->notifyDebuggerOfAllFibers && fiberNode == NULL) {
3286                 /* This is not a fiber we are tracking. */
3287                 debugMonitorExit(threadLock);
3288                 return;
3289             }
3290 
3291             JDI_ASSERT(fiberNode != NULL);
3292             JDI_ASSERT(fiberNode->isStarted);
3293             JDI_ASSERT(bagSize(fiberNode->eventBag) == 0);
3294 
3295             if (threadNode->currentStep.depth == JDWP_STEP_DEPTH(INTO) &&
3296                 (total_frame_count + continuation_frame_count == fromDepth)) {
3297                 /* We are stepping into Continuation.doYield(), so leave single stepping enabled.
3298                  * This will resume single stepping in Continuation.run() right after the
3299                  * Continuation.enter() call.
3300                  */
3301             } else if (total_frame_count >= fromDepth) { /* Check if fromDepth is NOT in the continuation. */
3302                 /*
3303                  * This means the single stepping was initiated stepping in a fiber, but in that small
3304                  * window after Thread.setFiber(this) has been called, and before the fiber's
3305                  * continuation was actually mounted. An example of this is stepping over the cont.run()
3306                  * call in Fiber.runContinuation(). In this case we just leave the carrier thread's
3307                  * single step state in place. We should eventually get a FramePop event to 
3308                  * enable single stepping again.
3309                  */
3310                 JDI_ASSERT(threadNode->currentStep.depth == JDWP_STEP_DEPTH(OVER));
3311             } else {
3312                 /*
3313                  * We were single stepping in the fiber, and now we need to stop doing that since
3314                  * we are leaving the fiber. We will copy our single step state from the carrier
3315                  * thread to the fiber so we can later restore it when the fiber is mounted again
3316                  * and we get a CONTINUATION_RUN event.
3317                  */
3318 
3319                 /* Clean up JVMTI SINGLE_STEP state. */
3320                 if (threadNode->instructionStepMode == JVMTI_ENABLE) {
3321                     stepControl_disableStepping(thread);
3322                     threadNode->instructionStepMode = JVMTI_DISABLE;
3323                     fiberNode->instructionStepMode = JVMTI_ENABLE;
3324                 }
3325    
3326                 /* Disable events */
3327                 threadControl_setEventMode(JVMTI_DISABLE, EI_EXCEPTION_CATCH, thread);
3328                 threadControl_setEventMode(JVMTI_DISABLE, EI_FRAME_POP, thread);
3329                 if (threadNode->currentStep.methodEnterHandlerNode != NULL) {
3330                     threadControl_setEventMode(JVMTI_DISABLE, EI_METHOD_ENTRY, thread);
3331                 }
3332 
3333                 /* Copy currentStep struct from the threadNode to the fiberNode and then zero out the threadNode. */
3334                 memcpy(&fiberNode->currentStep, &threadNode->currentStep, sizeof(threadNode->currentStep));
3335                 memset(&threadNode->currentStep, 0, sizeof(threadNode->currentStep));
3336             }
3337         }
3338     }
3339     debugMonitorExit(threadLock);
3340 }
< prev index next >