Home | History | Annotate | Download | only in back
      1 /*
      2  * Copyright (c) 1998, 2017, 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 "outStream.h"
     28 #include "eventHandler.h"
     29 #include "threadControl.h"
     30 #include "invoker.h"
     31 
     32 /*
     33  * Event helper thread command commandKinds
     34  */
     35 #define COMMAND_REPORT_EVENT_COMPOSITE          1
     36 #define COMMAND_REPORT_INVOKE_DONE              2
     37 #define COMMAND_REPORT_VM_INIT                  3
     38 #define COMMAND_SUSPEND_THREAD                  4
     39 
     40 /*
     41  * Event helper thread command singleKinds
     42  */
     43 #define COMMAND_SINGLE_EVENT                    11
     44 #define COMMAND_SINGLE_UNLOAD                   12
     45 #define COMMAND_SINGLE_FRAME_EVENT              13
     46 
     47 typedef struct EventCommandSingle {
     48     jbyte suspendPolicy; /* NOTE: Must be the first field */
     49     jint id;
     50     EventInfo info;
     51 } EventCommandSingle;
     52 
     53 typedef struct UnloadCommandSingle {
     54     char *classSignature;
     55     jint id;
     56 } UnloadCommandSingle;
     57 
     58 typedef struct FrameEventCommandSingle {
     59     jbyte suspendPolicy; /* NOTE: Must be the first field */
     60     jint id;
     61     EventIndex ei;
     62     jthread thread;
     63     jclass clazz;
     64     jmethodID method;
     65     jlocation location;
     66     char typeKey;         /* Not used for method entry events */
     67                           /* If typeKey is 0, then no return value is needed */
     68     jvalue returnValue;   /* Not used for method entry events */
     69 } FrameEventCommandSingle;
     70 
     71 typedef struct CommandSingle {
     72     jint singleKind;
     73     union {
     74         EventCommandSingle eventCommand;
     75         UnloadCommandSingle unloadCommand;
     76         FrameEventCommandSingle frameEventCommand;
     77     } u;
     78 } CommandSingle;
     79 
     80 typedef struct ReportInvokeDoneCommand {
     81     jthread thread;
     82 } ReportInvokeDoneCommand;
     83 
     84 typedef struct ReportVMInitCommand {
     85     jbyte suspendPolicy; /* NOTE: Must be the first field */
     86     jthread thread;
     87 } ReportVMInitCommand;
     88 
     89 typedef struct SuspendThreadCommand {
     90     jthread thread;
     91 } SuspendThreadCommand;
     92 
     93 typedef struct ReportEventCompositeCommand {
     94     jbyte suspendPolicy; /* NOTE: Must be the first field */
     95     jint eventCount;
     96     CommandSingle singleCommand[1]; /* variable length */
     97 } ReportEventCompositeCommand;
     98 
     99 typedef struct HelperCommand {
    100     jint commandKind;
    101     jboolean done;
    102     jboolean waiting;
    103     jbyte sessionID;
    104     struct HelperCommand *next;
    105     union {
    106         /* NOTE: Each of the structs below must have the same first field */
    107         ReportEventCompositeCommand reportEventComposite;
    108         ReportInvokeDoneCommand     reportInvokeDone;
    109         ReportVMInitCommand         reportVMInit;
    110         SuspendThreadCommand        suspendThread;
    111     } u;
    112     /* composite array expand out, put nothing after */
    113 } HelperCommand;
    114 
    115 typedef struct {
    116     HelperCommand *head;
    117     HelperCommand *tail;
    118 } CommandQueue;
    119 
    120 static CommandQueue commandQueue;
    121 static jrawMonitorID commandQueueLock;
    122 static jrawMonitorID commandCompleteLock;
    123 static jrawMonitorID blockCommandLoopLock;
    124 static jint maxQueueSize = 50 * 1024; /* TO DO: Make this configurable */
    125 static jboolean holdEvents;
    126 static jint currentQueueSize = 0;
    127 static jint currentSessionID;
    128 
    129 static void saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo);
    130 static void tossEventInfoRefs(JNIEnv *env, EventInfo *evinfo);
    131 
    132 static jint
    133 commandSize(HelperCommand *command)
    134 {
    135     jint size = sizeof(HelperCommand);
    136     if (command->commandKind == COMMAND_REPORT_EVENT_COMPOSITE) {
    137         /*
    138          * One event is accounted for in the Helper Command. If there are
    139          * more, add to size here.
    140          */
    141         /*LINTED*/
    142         size += ((int)sizeof(CommandSingle) *
    143                      (command->u.reportEventComposite.eventCount - 1));
    144     }
    145     return size;
    146 }
    147 
    148 static void
    149 freeCommand(HelperCommand *command)
    150 {
    151     if ( command == NULL )
    152         return;
    153     jvmtiDeallocate(command);
    154 }
    155 
    156 static void
    157 enqueueCommand(HelperCommand *command,
    158                jboolean wait, jboolean reportingVMDeath)
    159 {
    160     static jboolean vmDeathReported = JNI_FALSE;
    161     CommandQueue *queue = &commandQueue;
    162     jint size = commandSize(command);
    163 
    164     command->done = JNI_FALSE;
    165     command->waiting = wait;
    166     command->next = NULL;
    167 
    168     debugMonitorEnter(commandQueueLock);
    169     while (size + currentQueueSize > maxQueueSize) {
    170         debugMonitorWait(commandQueueLock);
    171     }
    172     log_debugee_location("enqueueCommand(): HelperCommand being processed", NULL, NULL, 0);
    173     if (vmDeathReported) {
    174         /* send no more events after VMDeath and don't wait */
    175         wait = JNI_FALSE;
    176     } else {
    177         currentQueueSize += size;
    178 
    179         if (queue->head == NULL) {
    180             queue->head = command;
    181         } else {
    182             queue->tail->next = command;
    183         }
    184         queue->tail = command;
    185 
    186         if (reportingVMDeath) {
    187             vmDeathReported = JNI_TRUE;
    188         }
    189     }
    190     debugMonitorNotifyAll(commandQueueLock);
    191     debugMonitorExit(commandQueueLock);
    192 
    193     if (wait) {
    194         debugMonitorEnter(commandCompleteLock);
    195         while (!command->done) {
    196             log_debugee_location("enqueueCommand(): HelperCommand wait", NULL, NULL, 0);
    197             debugMonitorWait(commandCompleteLock);
    198         }
    199         freeCommand(command);
    200         debugMonitorExit(commandCompleteLock);
    201     }
    202 }
    203 
    204 static void
    205 completeCommand(HelperCommand *command)
    206 {
    207     if (command->waiting) {
    208         debugMonitorEnter(commandCompleteLock);
    209         command->done = JNI_TRUE;
    210         log_debugee_location("completeCommand(): HelperCommand done waiting", NULL, NULL, 0);
    211         debugMonitorNotifyAll(commandCompleteLock);
    212         debugMonitorExit(commandCompleteLock);
    213     } else {
    214         freeCommand(command);
    215     }
    216 }
    217 
    218 static HelperCommand *
    219 dequeueCommand(void)
    220 {
    221     HelperCommand *command = NULL;
    222     CommandQueue *queue = &commandQueue;
    223     jint size;
    224 
    225     debugMonitorEnter(commandQueueLock);
    226 
    227     while (command == NULL) {
    228         while (holdEvents || (queue->head == NULL)) {
    229             debugMonitorWait(commandQueueLock);
    230         }
    231 
    232         JDI_ASSERT(queue->head);
    233         command = queue->head;
    234         queue->head = command->next;
    235         if (queue->tail == command) {
    236             queue->tail = NULL;
    237         }
    238 
    239         log_debugee_location("dequeueCommand(): command being dequeued", NULL, NULL, 0);
    240 
    241         size = commandSize(command);
    242         /*
    243          * Immediately close out any commands enqueued from
    244          * a dead VM or a previously attached debugger.
    245          */
    246         if (gdata->vmDead || command->sessionID != currentSessionID) {
    247             log_debugee_location("dequeueCommand(): command session removal", NULL, NULL, 0);
    248             completeCommand(command);
    249             command = NULL;
    250         }
    251 
    252         /*
    253          * There's room in the queue for more.
    254          */
    255         currentQueueSize -= size;
    256         debugMonitorNotifyAll(commandQueueLock);
    257     }
    258 
    259     debugMonitorExit(commandQueueLock);
    260 
    261     return command;
    262 }
    263 
    264 void eventHelper_holdEvents(void)
    265 {
    266     debugMonitorEnter(commandQueueLock);
    267     holdEvents = JNI_TRUE;
    268     debugMonitorNotifyAll(commandQueueLock);
    269     debugMonitorExit(commandQueueLock);
    270 }
    271 
    272 void eventHelper_releaseEvents(void)
    273 {
    274     debugMonitorEnter(commandQueueLock);
    275     holdEvents = JNI_FALSE;
    276     debugMonitorNotifyAll(commandQueueLock);
    277     debugMonitorExit(commandQueueLock);
    278 }
    279 
    280 static void
    281 writeSingleStepEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    282 {
    283     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    284     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
    285 }
    286 
    287 static void
    288 writeBreakpointEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    289 {
    290     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    291     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
    292 }
    293 
    294 static void
    295 writeFieldAccessEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    296 {
    297     jbyte fieldClassTag;
    298 
    299     fieldClassTag = referenceTypeTag(evinfo->u.field_access.field_clazz);
    300 
    301     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    302     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
    303     (void)outStream_writeByte(out, fieldClassTag);
    304     (void)outStream_writeObjectRef(env, out, evinfo->u.field_access.field_clazz);
    305     (void)outStream_writeFieldID(out, evinfo->u.field_access.field);
    306     (void)outStream_writeObjectTag(env, out, evinfo->object);
    307     (void)outStream_writeObjectRef(env, out, evinfo->object);
    308 }
    309 
    310 static void
    311 writeFieldModificationEvent(JNIEnv *env, PacketOutputStream *out,
    312                             EventInfo *evinfo)
    313 {
    314     jbyte fieldClassTag;
    315 
    316     fieldClassTag = referenceTypeTag(evinfo->u.field_modification.field_clazz);
    317 
    318     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    319     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
    320     (void)outStream_writeByte(out, fieldClassTag);
    321     (void)outStream_writeObjectRef(env, out, evinfo->u.field_modification.field_clazz);
    322     (void)outStream_writeFieldID(out, evinfo->u.field_modification.field);
    323     (void)outStream_writeObjectTag(env, out, evinfo->object);
    324     (void)outStream_writeObjectRef(env, out, evinfo->object);
    325     (void)outStream_writeValue(env, out, (jbyte)evinfo->u.field_modification.signature_type,
    326                          evinfo->u.field_modification.new_value);
    327 }
    328 
    329 static void
    330 writeExceptionEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    331 {
    332     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    333     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
    334     (void)outStream_writeObjectTag(env, out, evinfo->object);
    335     (void)outStream_writeObjectRef(env, out, evinfo->object);
    336     writeCodeLocation(out, evinfo->u.exception.catch_clazz,
    337                       evinfo->u.exception.catch_method, evinfo->u.exception.catch_location);
    338 }
    339 
    340 static void
    341 writeThreadEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    342 {
    343     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    344 }
    345 
    346 static void
    347 writeMonitorEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    348 {
    349     jclass klass;
    350     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    351     (void)outStream_writeObjectTag(env, out, evinfo->object);
    352     (void)outStream_writeObjectRef(env, out, evinfo->object);
    353     if (evinfo->ei == EI_MONITOR_WAIT || evinfo->ei == EI_MONITOR_WAITED) {
    354         /* clazz of evinfo was set to class of monitor object for monitor wait event class filtering.
    355          * So get the method class to write location info.
    356          * See cbMonitorWait() and cbMonitorWaited() function in eventHandler.c.
    357          */
    358         klass=getMethodClass(gdata->jvmti, evinfo->method);
    359         writeCodeLocation(out, klass, evinfo->method, evinfo->location);
    360         if (evinfo->ei == EI_MONITOR_WAIT) {
    361             (void)outStream_writeLong(out, evinfo->u.monitor.timeout);
    362         } else  if (evinfo->ei == EI_MONITOR_WAITED) {
    363             (void)outStream_writeBoolean(out, evinfo->u.monitor.timed_out);
    364         }
    365         /* This runs in a command loop and this thread may not return to java.
    366          * So we need to delete the local ref created by jvmti GetMethodDeclaringClass.
    367          */
    368         JNI_FUNC_PTR(env,DeleteLocalRef)(env, klass);
    369     } else {
    370         writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
    371     }
    372 }
    373 
    374 static void
    375 writeClassEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    376 {
    377     jbyte classTag;
    378     jint status;
    379     char *signature = NULL;
    380     jvmtiError error;
    381 
    382     classTag = referenceTypeTag(evinfo->clazz);
    383     error = classSignature(evinfo->clazz, &signature, NULL);
    384     if (error != JVMTI_ERROR_NONE) {
    385         EXIT_ERROR(error,"signature");
    386     }
    387     status = classStatus(evinfo->clazz);
    388 
    389     (void)outStream_writeObjectRef(env, out, evinfo->thread);
    390     (void)outStream_writeByte(out, classTag);
    391     (void)outStream_writeObjectRef(env, out, evinfo->clazz);
    392     (void)outStream_writeString(out, signature);
    393     (void)outStream_writeInt(out, map2jdwpClassStatus(status));
    394     jvmtiDeallocate(signature);
    395 }
    396 
    397 static void
    398 writeVMDeathEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
    399 {
    400 }
    401 
    402 static void
    403 handleEventCommandSingle(JNIEnv *env, PacketOutputStream *out,
    404                            EventCommandSingle *command)
    405 {
    406     EventInfo *evinfo = &command->info;
    407 
    408     (void)outStream_writeByte(out, eventIndex2jdwp(evinfo->ei));
    409     (void)outStream_writeInt(out, command->id);
    410 
    411     switch (evinfo->ei) {
    412         case EI_SINGLE_STEP:
    413             writeSingleStepEvent(env, out, evinfo);
    414             break;
    415         case EI_BREAKPOINT:
    416             writeBreakpointEvent(env, out, evinfo);
    417             break;
    418         case EI_FIELD_ACCESS:
    419             writeFieldAccessEvent(env, out, evinfo);
    420             break;
    421         case EI_FIELD_MODIFICATION:
    422             writeFieldModificationEvent(env, out, evinfo);
    423             break;
    424         case EI_EXCEPTION:
    425             writeExceptionEvent(env, out, evinfo);
    426             break;
    427         case EI_THREAD_START:
    428         case EI_THREAD_END:
    429             writeThreadEvent(env, out, evinfo);
    430             break;
    431         case EI_CLASS_LOAD:
    432         case EI_CLASS_PREPARE:
    433             writeClassEvent(env, out, evinfo);
    434             break;
    435         case EI_MONITOR_CONTENDED_ENTER:
    436         case EI_MONITOR_CONTENDED_ENTERED:
    437         case EI_MONITOR_WAIT:
    438         case EI_MONITOR_WAITED:
    439             writeMonitorEvent(env, out, evinfo);
    440             break;
    441         case EI_VM_DEATH:
    442             writeVMDeathEvent(env, out, evinfo);
    443             break;
    444         default:
    445             EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"unknown event index");
    446             break;
    447     }
    448     tossEventInfoRefs(env, evinfo);
    449 }
    450 
    451 static void
    452 handleUnloadCommandSingle(JNIEnv* env, PacketOutputStream *out,
    453                            UnloadCommandSingle *command)
    454 {
    455     (void)outStream_writeByte(out, JDWP_EVENT(CLASS_UNLOAD));
    456     (void)outStream_writeInt(out, command->id);
    457     (void)outStream_writeString(out, command->classSignature);
    458     jvmtiDeallocate(command->classSignature);
    459     command->classSignature = NULL;
    460 }
    461 
    462 static void
    463 handleFrameEventCommandSingle(JNIEnv* env, PacketOutputStream *out,
    464                               FrameEventCommandSingle *command)
    465 {
    466     if (command->typeKey) {
    467         (void)outStream_writeByte(out, JDWP_EVENT(METHOD_EXIT_WITH_RETURN_VALUE));
    468     } else {
    469         (void)outStream_writeByte(out, eventIndex2jdwp(command->ei));
    470     }
    471     (void)outStream_writeInt(out, command->id);
    472     (void)outStream_writeObjectRef(env, out, command->thread);
    473     writeCodeLocation(out, command->clazz, command->method, command->location);
    474     if (command->typeKey) {
    475         (void)outStream_writeValue(env, out, command->typeKey, command->returnValue);
    476         if (isObjectTag(command->typeKey) &&
    477             command->returnValue.l != NULL) {
    478             tossGlobalRef(env, &(command->returnValue.l));
    479         }
    480     }
    481     tossGlobalRef(env, &(command->thread));
    482     tossGlobalRef(env, &(command->clazz));
    483 }
    484 
    485 static void
    486 suspendWithInvokeEnabled(jbyte policy, jthread thread)
    487 {
    488     invoker_enableInvokeRequests(thread);
    489 
    490     if (policy == JDWP_SUSPEND_POLICY(ALL)) {
    491         (void)threadControl_suspendAll();
    492     } else {
    493         (void)threadControl_suspendThread(thread, JNI_FALSE);
    494     }
    495 }
    496 
    497 static void
    498 handleReportEventCompositeCommand(JNIEnv *env,
    499                                   ReportEventCompositeCommand *recc)
    500 {
    501     PacketOutputStream out;
    502     jint count = recc->eventCount;
    503     jint i;
    504 
    505     if (recc->suspendPolicy != JDWP_SUSPEND_POLICY(NONE)) {
    506         /* must determine thread to interrupt before writing */
    507         /* since writing destroys it */
    508         jthread thread = NULL;
    509         for (i = 0; i < count; i++) {
    510             CommandSingle *single = &(recc->singleCommand[i]);
    511             switch (single->singleKind) {
    512                 case COMMAND_SINGLE_EVENT:
    513                     thread = single->u.eventCommand.info.thread;
    514                     break;
    515                 case COMMAND_SINGLE_FRAME_EVENT:
    516                     thread = single->u.frameEventCommand.thread;
    517                     break;
    518             }
    519             if (thread != NULL) {
    520                 break;
    521             }
    522         }
    523 
    524         if (thread == NULL) {
    525             (void)threadControl_suspendAll();
    526         } else {
    527             suspendWithInvokeEnabled(recc->suspendPolicy, thread);
    528         }
    529     }
    530 
    531     outStream_initCommand(&out, uniqueID(), 0x0,
    532                           JDWP_COMMAND_SET(Event),
    533                           JDWP_COMMAND(Event, Composite));
    534     (void)outStream_writeByte(&out, recc->suspendPolicy);
    535     (void)outStream_writeInt(&out, count);
    536 
    537     for (i = 0; i < count; i++) {
    538         CommandSingle *single = &(recc->singleCommand[i]);
    539         switch (single->singleKind) {
    540             case COMMAND_SINGLE_EVENT:
    541                 handleEventCommandSingle(env, &out,
    542                                          &single->u.eventCommand);
    543                 break;
    544             case COMMAND_SINGLE_UNLOAD:
    545                 handleUnloadCommandSingle(env, &out,
    546                                           &single->u.unloadCommand);
    547                 break;
    548             case COMMAND_SINGLE_FRAME_EVENT:
    549                 handleFrameEventCommandSingle(env, &out,
    550                                               &single->u.frameEventCommand);
    551                 break;
    552         }
    553     }
    554 
    555     outStream_sendCommand(&out);
    556     outStream_destroy(&out);
    557 }
    558 
    559 static void
    560 handleReportInvokeDoneCommand(JNIEnv* env, ReportInvokeDoneCommand *command)
    561 {
    562     invoker_completeInvokeRequest(command->thread);
    563     tossGlobalRef(env, &(command->thread));
    564 }
    565 
    566 static void
    567 handleReportVMInitCommand(JNIEnv* env, ReportVMInitCommand *command)
    568 {
    569     PacketOutputStream out;
    570 
    571     if (command->suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) {
    572         (void)threadControl_suspendAll();
    573     } else if (command->suspendPolicy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) {
    574         (void)threadControl_suspendThread(command->thread, JNI_FALSE);
    575     }
    576 
    577     outStream_initCommand(&out, uniqueID(), 0x0,
    578                           JDWP_COMMAND_SET(Event),
    579                           JDWP_COMMAND(Event, Composite));
    580     (void)outStream_writeByte(&out, command->suspendPolicy);
    581     (void)outStream_writeInt(&out, 1);   /* Always one component */
    582     (void)outStream_writeByte(&out, JDWP_EVENT(VM_INIT));
    583     (void)outStream_writeInt(&out, 0);    /* Not in response to an event req. */
    584 
    585     (void)outStream_writeObjectRef(env, &out, command->thread);
    586 
    587     outStream_sendCommand(&out);
    588     outStream_destroy(&out);
    589     /* Why aren't we tossing this: tossGlobalRef(env, &(command->thread)); */
    590 }
    591 
    592 static void
    593 handleSuspendThreadCommand(JNIEnv* env, SuspendThreadCommand *command)
    594 {
    595     /*
    596      * For the moment, there's  nothing that can be done with the
    597      * return code, so we don't check it here.
    598      */
    599     (void)threadControl_suspendThread(command->thread, JNI_TRUE);
    600     tossGlobalRef(env, &(command->thread));
    601 }
    602 
    603 static void
    604 handleCommand(JNIEnv *env, HelperCommand *command)
    605 {
    606     switch (command->commandKind) {
    607         case COMMAND_REPORT_EVENT_COMPOSITE:
    608             handleReportEventCompositeCommand(env,
    609                                         &command->u.reportEventComposite);
    610             break;
    611         case COMMAND_REPORT_INVOKE_DONE:
    612             handleReportInvokeDoneCommand(env, &command->u.reportInvokeDone);
    613             break;
    614         case COMMAND_REPORT_VM_INIT:
    615             handleReportVMInitCommand(env, &command->u.reportVMInit);
    616             break;
    617         case COMMAND_SUSPEND_THREAD:
    618             handleSuspendThreadCommand(env, &command->u.suspendThread);
    619             break;
    620         default:
    621             EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"Event Helper Command");
    622             break;
    623     }
    624 }
    625 
    626 /*
    627  * There was an assumption that only one event with a suspend-all
    628  * policy could be processed by commandLoop() at one time. It was
    629  * assumed that native thread suspension from the first suspend-all
    630  * event would prevent the second suspend-all event from making it
    631  * into the command queue. For the Classic VM, this was a reasonable
    632  * assumption. However, in HotSpot all thread suspension requires a
    633  * VM operation and VM operations take time.
    634  *
    635  * The solution is to add a mechanism to prevent commandLoop() from
    636  * processing more than one event with a suspend-all policy. This is
    637  * accomplished by forcing commandLoop() to wait for either
    638  * ThreadReferenceImpl.c: resume() or VirtualMachineImpl.c: resume()
    639  * when an event with a suspend-all policy has been completed.
    640  */
    641 static jboolean blockCommandLoop = JNI_FALSE;
    642 
    643 /*
    644  * We wait for either ThreadReferenceImpl.c: resume() or
    645  * VirtualMachineImpl.c: resume() to be called.
    646  */
    647 static void
    648 doBlockCommandLoop(void) {
    649     debugMonitorEnter(blockCommandLoopLock);
    650     while (blockCommandLoop == JNI_TRUE) {
    651         debugMonitorWait(blockCommandLoopLock);
    652     }
    653     debugMonitorExit(blockCommandLoopLock);
    654 }
    655 
    656 /*
    657  * If the command that we are about to execute has a suspend-all
    658  * policy, then prepare for either ThreadReferenceImpl.c: resume()
    659  * or VirtualMachineImpl.c: resume() to be called.
    660  */
    661 static jboolean
    662 needBlockCommandLoop(HelperCommand *cmd) {
    663     if (cmd->commandKind == COMMAND_REPORT_EVENT_COMPOSITE
    664     && cmd->u.reportEventComposite.suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) {
    665         debugMonitorEnter(blockCommandLoopLock);
    666         blockCommandLoop = JNI_TRUE;
    667         debugMonitorExit(blockCommandLoopLock);
    668 
    669         return JNI_TRUE;
    670     }
    671 
    672     return JNI_FALSE;
    673 }
    674 
    675 /*
    676  * Used by either ThreadReferenceImpl.c: resume() or
    677  * VirtualMachineImpl.c: resume() to resume commandLoop().
    678  */
    679 void
    680 unblockCommandLoop(void) {
    681     debugMonitorEnter(blockCommandLoopLock);
    682     blockCommandLoop = JNI_FALSE;
    683     debugMonitorNotifyAll(blockCommandLoopLock);
    684     debugMonitorExit(blockCommandLoopLock);
    685 }
    686 
    687 /*
    688  * The event helper thread. Dequeues commands and processes them.
    689  */
    690 static void JNICALL
    691 commandLoop(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
    692 {
    693     LOG_MISC(("Begin command loop thread"));
    694 
    695     while (JNI_TRUE) {
    696         HelperCommand *command = dequeueCommand();
    697         if (command != NULL) {
    698             /*
    699              * Setup for a potential doBlockCommand() call before calling
    700              * handleCommand() to prevent any races.
    701              */
    702             jboolean doBlock = needBlockCommandLoop(command);
    703             log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0);
    704             handleCommand(jni_env, command);
    705             completeCommand(command);
    706             /* if we just finished a suspend-all cmd, then we block here */
    707             if (doBlock) {
    708                 doBlockCommandLoop();
    709             }
    710         }
    711     }
    712     /* This loop never ends, even as connections come and go with server=y */
    713 }
    714 
    715 void
    716 eventHelper_initialize(jbyte sessionID)
    717 {
    718     jvmtiStartFunction func;
    719 
    720     currentSessionID = sessionID;
    721     holdEvents = JNI_FALSE;
    722     commandQueue.head = NULL;
    723     commandQueue.tail = NULL;
    724 
    725     commandQueueLock = debugMonitorCreate("JDWP Event Helper Queue Monitor");
    726     commandCompleteLock = debugMonitorCreate("JDWP Event Helper Completion Monitor");
    727     blockCommandLoopLock = debugMonitorCreate("JDWP Event Block CommandLoop Monitor");
    728 
    729     /* Start the event handler thread */
    730     func = &commandLoop;
    731     (void)spawnNewThread(func, NULL, "JDWP Event Helper Thread");
    732 }
    733 
    734 void
    735 eventHelper_reset(jbyte newSessionID)
    736 {
    737     debugMonitorEnter(commandQueueLock);
    738     currentSessionID = newSessionID;
    739     holdEvents = JNI_FALSE;
    740     debugMonitorNotifyAll(commandQueueLock);
    741     debugMonitorExit(commandQueueLock);
    742 }
    743 
    744 /*
    745  * Provide a means for threadControl to ensure that crucial locks are not
    746  * held by suspended threads.
    747  */
    748 void
    749 eventHelper_lock(void)
    750 {
    751     debugMonitorEnter(commandQueueLock);
    752     debugMonitorEnter(commandCompleteLock);
    753 }
    754 
    755 void
    756 eventHelper_unlock(void)
    757 {
    758     debugMonitorExit(commandCompleteLock);
    759     debugMonitorExit(commandQueueLock);
    760 }
    761 
    762 /* Change all references to global in the EventInfo struct */
    763 static void
    764 saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
    765 {
    766     jthread *pthread;
    767     jclass *pclazz;
    768     jobject *pobject;
    769     jthread thread;
    770     jclass clazz;
    771     jobject object;
    772     char sig;
    773 
    774     JNI_FUNC_PTR(env,ExceptionClear)(env);
    775 
    776     if ( evinfo->thread != NULL ) {
    777         pthread = &(evinfo->thread);
    778         thread = *pthread;
    779         *pthread = NULL;
    780         saveGlobalRef(env, thread, pthread);
    781     }
    782     if ( evinfo->clazz != NULL ) {
    783         pclazz = &(evinfo->clazz);
    784         clazz = *pclazz;
    785         *pclazz = NULL;
    786         saveGlobalRef(env, clazz, pclazz);
    787     }
    788     if ( evinfo->object != NULL ) {
    789         pobject = &(evinfo->object);
    790         object = *pobject;
    791         *pobject = NULL;
    792         saveGlobalRef(env, object, pobject);
    793     }
    794 
    795     switch (evinfo->ei) {
    796         case EI_FIELD_MODIFICATION:
    797             if ( evinfo->u.field_modification.field_clazz != NULL ) {
    798                 pclazz = &(evinfo->u.field_modification.field_clazz);
    799                 clazz = *pclazz;
    800                 *pclazz = NULL;
    801                 saveGlobalRef(env, clazz, pclazz);
    802             }
    803             sig = evinfo->u.field_modification.signature_type;
    804             if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
    805                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
    806                     pobject = &(evinfo->u.field_modification.new_value.l);
    807                     object = *pobject;
    808                     *pobject = NULL;
    809                     saveGlobalRef(env, object, pobject);
    810                 }
    811             }
    812             break;
    813         case EI_FIELD_ACCESS:
    814             if ( evinfo->u.field_access.field_clazz != NULL ) {
    815                 pclazz = &(evinfo->u.field_access.field_clazz);
    816                 clazz = *pclazz;
    817                 *pclazz = NULL;
    818                 saveGlobalRef(env, clazz, pclazz);
    819             }
    820             break;
    821         case EI_EXCEPTION:
    822             if ( evinfo->u.exception.catch_clazz != NULL ) {
    823                 pclazz = &(evinfo->u.exception.catch_clazz);
    824                 clazz = *pclazz;
    825                 *pclazz = NULL;
    826                 saveGlobalRef(env, clazz, pclazz);
    827             }
    828             break;
    829         default:
    830             break;
    831     }
    832 
    833     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
    834         EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"ExceptionOccurred");
    835     }
    836 }
    837 
    838 static void
    839 tossEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
    840 {
    841     char sig;
    842     if ( evinfo->thread != NULL ) {
    843         tossGlobalRef(env, &(evinfo->thread));
    844     }
    845     if ( evinfo->clazz != NULL ) {
    846         tossGlobalRef(env, &(evinfo->clazz));
    847     }
    848     if ( evinfo->object != NULL ) {
    849         tossGlobalRef(env, &(evinfo->object));
    850     }
    851     switch (evinfo->ei) {
    852         case EI_FIELD_MODIFICATION:
    853             if ( evinfo->u.field_modification.field_clazz != NULL ) {
    854                 tossGlobalRef(env, &(evinfo->u.field_modification.field_clazz));
    855             }
    856             sig = evinfo->u.field_modification.signature_type;
    857             if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
    858                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
    859                     tossGlobalRef(env, &(evinfo->u.field_modification.new_value.l));
    860                 }
    861             }
    862             break;
    863         case EI_FIELD_ACCESS:
    864             if ( evinfo->u.field_access.field_clazz != NULL ) {
    865                 tossGlobalRef(env, &(evinfo->u.field_access.field_clazz));
    866             }
    867             break;
    868         case EI_EXCEPTION:
    869             if ( evinfo->u.exception.catch_clazz != NULL ) {
    870                 tossGlobalRef(env, &(evinfo->u.exception.catch_clazz));
    871             }
    872             break;
    873         default:
    874             break;
    875     }
    876 }
    877 
    878 struct bag *
    879 eventHelper_createEventBag(void)
    880 {
    881     return bagCreateBag(sizeof(CommandSingle), 5 /* events */ );
    882 }
    883 
    884 /* Return the combined suspend policy for the event set
    885  */
    886 static jboolean
    887 enumForCombinedSuspendPolicy(void *cv, void *arg)
    888 {
    889     CommandSingle *command = cv;
    890     jbyte thisPolicy;
    891     jbyte *policy = arg;
    892 
    893     switch(command->singleKind) {
    894         case COMMAND_SINGLE_EVENT:
    895             thisPolicy = command->u.eventCommand.suspendPolicy;
    896             break;
    897         case COMMAND_SINGLE_FRAME_EVENT:
    898             thisPolicy = command->u.frameEventCommand.suspendPolicy;
    899             break;
    900         default:
    901             thisPolicy = JDWP_SUSPEND_POLICY(NONE);
    902     }
    903     /* Expand running policy value if this policy demands it */
    904     if (*policy == JDWP_SUSPEND_POLICY(NONE)) {
    905         *policy = thisPolicy;
    906     } else if (*policy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) {
    907         *policy = (thisPolicy == JDWP_SUSPEND_POLICY(ALL))?
    908                         thisPolicy : *policy;
    909     }
    910 
    911     /* Short circuit if we reached maximal suspend policy */
    912     if (*policy == JDWP_SUSPEND_POLICY(ALL)) {
    913         return JNI_FALSE;
    914     } else {
    915         return JNI_TRUE;
    916     }
    917 }
    918 
    919 /* Determine whether we are reporting VM death
    920  */
    921 static jboolean
    922 enumForVMDeath(void *cv, void *arg)
    923 {
    924     CommandSingle *command = cv;
    925     jboolean *reportingVMDeath = arg;
    926 
    927     if (command->singleKind == COMMAND_SINGLE_EVENT) {
    928         if (command->u.eventCommand.info.ei == EI_VM_DEATH) {
    929             *reportingVMDeath = JNI_TRUE;
    930             return JNI_FALSE;
    931         }
    932     }
    933     return JNI_TRUE;
    934 }
    935 
    936 struct singleTracker {
    937     ReportEventCompositeCommand *recc;
    938     int index;
    939 };
    940 
    941 static jboolean
    942 enumForCopyingSingles(void *command, void *tv)
    943 {
    944     struct singleTracker *tracker = (struct singleTracker *)tv;
    945     (void)memcpy(&tracker->recc->singleCommand[tracker->index++],
    946            command,
    947            sizeof(CommandSingle));
    948     return JNI_TRUE;
    949 }
    950 
    951 jbyte
    952 eventHelper_reportEvents(jbyte sessionID, struct bag *eventBag)
    953 {
    954     int size = bagSize(eventBag);
    955     jbyte suspendPolicy = JDWP_SUSPEND_POLICY(NONE);
    956     jboolean reportingVMDeath = JNI_FALSE;
    957     jboolean wait;
    958     int command_size;
    959 
    960     HelperCommand *command;
    961     ReportEventCompositeCommand *recc;
    962     struct singleTracker tracker;
    963 
    964     if (size == 0) {
    965         return suspendPolicy;
    966     }
    967     (void)bagEnumerateOver(eventBag, enumForCombinedSuspendPolicy, &suspendPolicy);
    968     (void)bagEnumerateOver(eventBag, enumForVMDeath, &reportingVMDeath);
    969 
    970     /*LINTED*/
    971     command_size = (int)(sizeof(HelperCommand) +
    972                          sizeof(CommandSingle)*(size-1));
    973     command = jvmtiAllocate(command_size);
    974     (void)memset(command, 0, command_size);
    975     command->commandKind = COMMAND_REPORT_EVENT_COMPOSITE;
    976     command->sessionID = sessionID;
    977     recc = &command->u.reportEventComposite;
    978     recc->suspendPolicy = suspendPolicy;
    979     recc->eventCount = size;
    980     tracker.recc = recc;
    981     tracker.index = 0;
    982     (void)bagEnumerateOver(eventBag, enumForCopyingSingles, &tracker);
    983 
    984     /*
    985      * We must wait if this thread (the event thread) is to be
    986      * suspended or if the VM is about to die. (Waiting in the latter
    987      * case ensures that we get the event out before the process dies.)
    988      */
    989     wait = (jboolean)((suspendPolicy != JDWP_SUSPEND_POLICY(NONE)) ||
    990                       reportingVMDeath);
    991     enqueueCommand(command, wait, reportingVMDeath);
    992     return suspendPolicy;
    993 }
    994 
    995 void
    996 eventHelper_recordEvent(EventInfo *evinfo, jint id, jbyte suspendPolicy,
    997                          struct bag *eventBag)
    998 {
    999     JNIEnv *env = getEnv();
   1000     CommandSingle *command = bagAdd(eventBag);
   1001     if (command == NULL) {
   1002         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"badAdd(eventBag)");
   1003     }
   1004 
   1005     command->singleKind = COMMAND_SINGLE_EVENT;
   1006     command->u.eventCommand.suspendPolicy = suspendPolicy;
   1007     command->u.eventCommand.id = id;
   1008 
   1009     /*
   1010      * Copy the event into the command so that it can be used
   1011      * asynchronously by the event helper thread.
   1012      */
   1013     (void)memcpy(&command->u.eventCommand.info, evinfo, sizeof(*evinfo));
   1014     saveEventInfoRefs(env, &command->u.eventCommand.info);
   1015 }
   1016 
   1017 void
   1018 eventHelper_recordClassUnload(jint id, char *signature, struct bag *eventBag)
   1019 {
   1020     CommandSingle *command = bagAdd(eventBag);
   1021     if (command == NULL) {
   1022         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"bagAdd(eventBag)");
   1023     }
   1024     command->singleKind = COMMAND_SINGLE_UNLOAD;
   1025     command->u.unloadCommand.id = id;
   1026     command->u.unloadCommand.classSignature = signature;
   1027 }
   1028 
   1029 void
   1030 eventHelper_recordFrameEvent(jint id, jbyte suspendPolicy, EventIndex ei,
   1031                              jthread thread, jclass clazz,
   1032                              jmethodID method, jlocation location,
   1033                              int needReturnValue,
   1034                              jvalue returnValue,
   1035                              struct bag *eventBag)
   1036 {
   1037     JNIEnv *env = getEnv();
   1038     FrameEventCommandSingle *frameCommand;
   1039     CommandSingle *command = bagAdd(eventBag);
   1040     jvmtiError err = JVMTI_ERROR_NONE;
   1041     if (command == NULL) {
   1042         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"bagAdd(eventBag)");
   1043     }
   1044 
   1045     command->singleKind = COMMAND_SINGLE_FRAME_EVENT;
   1046     frameCommand = &command->u.frameEventCommand;
   1047     frameCommand->suspendPolicy = suspendPolicy;
   1048     frameCommand->id = id;
   1049     frameCommand->ei = ei;
   1050     saveGlobalRef(env, thread, &(frameCommand->thread));
   1051     saveGlobalRef(env, clazz, &(frameCommand->clazz));
   1052     frameCommand->method = method;
   1053     frameCommand->location = location;
   1054     if (needReturnValue) {
   1055         err = methodReturnType(method, &frameCommand->typeKey);
   1056         JDI_ASSERT(err == JVMTI_ERROR_NONE);
   1057 
   1058         /*
   1059          * V or B C D F I J S Z L <classname> ;    [ ComponentType
   1060          */
   1061         if (isObjectTag(frameCommand->typeKey) &&
   1062             returnValue.l != NULL) {
   1063             saveGlobalRef(env, returnValue.l, &(frameCommand->returnValue.l));
   1064         } else {
   1065             frameCommand->returnValue = returnValue;
   1066         }
   1067     } else {
   1068       /* This is not a JDWP METHOD_EXIT_WITH_RETURN_VALUE request,
   1069        * so signal this by setting typeKey = 0 which is not
   1070        * a legal typekey.
   1071        */
   1072        frameCommand->typeKey = 0;
   1073     }
   1074 }
   1075 
   1076 void
   1077 eventHelper_reportInvokeDone(jbyte sessionID, jthread thread)
   1078 {
   1079     JNIEnv *env = getEnv();
   1080     HelperCommand *command = jvmtiAllocate(sizeof(*command));
   1081     if (command == NULL) {
   1082         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommand");
   1083     }
   1084     (void)memset(command, 0, sizeof(*command));
   1085     command->commandKind = COMMAND_REPORT_INVOKE_DONE;
   1086     command->sessionID = sessionID;
   1087     saveGlobalRef(env, thread, &(command->u.reportInvokeDone.thread));
   1088     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
   1089 }
   1090 
   1091 /*
   1092  * This, currently, cannot go through the normal event handling code
   1093  * because the JVMTI event does not contain a thread.
   1094  */
   1095 void
   1096 eventHelper_reportVMInit(JNIEnv *env, jbyte sessionID, jthread thread, jbyte suspendPolicy)
   1097 {
   1098     HelperCommand *command = jvmtiAllocate(sizeof(*command));
   1099     if (command == NULL) {
   1100         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommmand");
   1101     }
   1102     (void)memset(command, 0, sizeof(*command));
   1103     command->commandKind = COMMAND_REPORT_VM_INIT;
   1104     command->sessionID = sessionID;
   1105     saveGlobalRef(env, thread, &(command->u.reportVMInit.thread));
   1106     command->u.reportVMInit.suspendPolicy = suspendPolicy;
   1107     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
   1108 }
   1109 
   1110 void
   1111 eventHelper_suspendThread(jbyte sessionID, jthread thread)
   1112 {
   1113     JNIEnv *env = getEnv();
   1114     HelperCommand *command = jvmtiAllocate(sizeof(*command));
   1115     if (command == NULL) {
   1116         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommmand");
   1117     }
   1118     (void)memset(command, 0, sizeof(*command));
   1119     command->commandKind = COMMAND_SUSPEND_THREAD;
   1120     command->sessionID = sessionID;
   1121     saveGlobalRef(env, thread, &(command->u.suspendThread.thread));
   1122     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
   1123 }
   1124