1/*
2 * Copyright (c) 1998, 2006, 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
47typedef struct EventCommandSingle {
48    jbyte suspendPolicy; /* NOTE: Must be the first field */
49    jint id;
50    EventInfo info;
51} EventCommandSingle;
52
53typedef struct UnloadCommandSingle {
54    char *classSignature;
55    jint id;
56} UnloadCommandSingle;
57
58typedef 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
71typedef struct CommandSingle {
72    jint singleKind;
73    union {
74        EventCommandSingle eventCommand;
75        UnloadCommandSingle unloadCommand;
76        FrameEventCommandSingle frameEventCommand;
77    } u;
78} CommandSingle;
79
80typedef struct ReportInvokeDoneCommand {
81    jthread thread;
82} ReportInvokeDoneCommand;
83
84typedef struct ReportVMInitCommand {
85    jbyte suspendPolicy; /* NOTE: Must be the first field */
86    jthread thread;
87} ReportVMInitCommand;
88
89typedef struct SuspendThreadCommand {
90    jthread thread;
91} SuspendThreadCommand;
92
93typedef struct ReportEventCompositeCommand {
94    jbyte suspendPolicy; /* NOTE: Must be the first field */
95    jint eventCount;
96    CommandSingle singleCommand[1]; /* variable length */
97} ReportEventCompositeCommand;
98
99typedef 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
115typedef struct {
116    HelperCommand *head;
117    HelperCommand *tail;
118} CommandQueue;
119
120static CommandQueue commandQueue;
121static jrawMonitorID commandQueueLock;
122static jrawMonitorID commandCompleteLock;
123static jrawMonitorID blockCommandLoopLock;
124static jint maxQueueSize = 50 * 1024; /* TO DO: Make this configurable */
125static jboolean holdEvents;
126static jint currentQueueSize = 0;
127static jint currentSessionID;
128
129static void saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo);
130static void tossEventInfoRefs(JNIEnv *env, EventInfo *evinfo);
131
132static jint
133commandSize(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
148static void
149freeCommand(HelperCommand *command)
150{
151    if ( command == NULL )
152        return;
153    jvmtiDeallocate(command);
154}
155
156static void
157enqueueCommand(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
204static void
205completeCommand(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
218static HelperCommand *
219dequeueCommand(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 a
244         * previously attached debugger.
245         */
246        if (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
264void eventHelper_holdEvents(void)
265{
266    debugMonitorEnter(commandQueueLock);
267    holdEvents = JNI_TRUE;
268    debugMonitorNotifyAll(commandQueueLock);
269    debugMonitorExit(commandQueueLock);
270}
271
272void eventHelper_releaseEvents(void)
273{
274    debugMonitorEnter(commandQueueLock);
275    holdEvents = JNI_FALSE;
276    debugMonitorNotifyAll(commandQueueLock);
277    debugMonitorExit(commandQueueLock);
278}
279
280static void
281writeSingleStepEvent(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
287static void
288writeBreakpointEvent(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
294static void
295writeFieldAccessEvent(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
310static void
311writeFieldModificationEvent(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
329static void
330writeExceptionEvent(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
340static void
341writeThreadEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
342{
343    (void)outStream_writeObjectRef(env, out, evinfo->thread);
344}
345
346static void
347writeMonitorEvent(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
374static void
375writeClassEvent(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
397static void
398writeVMDeathEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
399{
400}
401
402static void
403handleEventCommandSingle(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
451static void
452handleUnloadCommandSingle(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
462static void
463handleFrameEventCommandSingle(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
485static void
486suspendWithInvokeEnabled(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
497static void
498handleReportEventCompositeCommand(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
559static void
560handleReportInvokeDoneCommand(JNIEnv* env, ReportInvokeDoneCommand *command)
561{
562    invoker_completeInvokeRequest(command->thread);
563    tossGlobalRef(env, &(command->thread));
564}
565
566static void
567handleReportVMInitCommand(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
592static void
593handleSuspendThreadCommand(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
603static void
604handleCommand(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 */
641static jboolean blockCommandLoop = JNI_FALSE;
642
643/*
644 * We wait for either ThreadReferenceImpl.c: resume() or
645 * VirtualMachineImpl.c: resume() to be called.
646 */
647static void
648doBlockCommandLoop(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 */
661static jboolean
662needBlockCommandLoop(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 */
679void
680unblockCommandLoop(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 */
690static void JNICALL
691commandLoop(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
715void
716eventHelper_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
734void
735eventHelper_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 */
748void
749eventHelper_lock(void)
750{
751    debugMonitorEnter(commandQueueLock);
752    debugMonitorEnter(commandCompleteLock);
753}
754
755void
756eventHelper_unlock(void)
757{
758    debugMonitorExit(commandCompleteLock);
759    debugMonitorExit(commandQueueLock);
760}
761
762/* Change all references to global in the EventInfo struct */
763static void
764saveEventInfoRefs(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
838static void
839tossEventInfoRefs(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
878struct bag *
879eventHelper_createEventBag(void)
880{
881    return bagCreateBag(sizeof(CommandSingle), 5 /* events */ );
882}
883
884/* Return the combined suspend policy for the event set
885 */
886static jboolean
887enumForCombinedSuspendPolicy(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 */
921static jboolean
922enumForVMDeath(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
936struct singleTracker {
937    ReportEventCompositeCommand *recc;
938    int index;
939};
940
941static jboolean
942enumForCopyingSingles(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
951jbyte
952eventHelper_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
995void
996eventHelper_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
1017void
1018eventHelper_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
1029void
1030eventHelper_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
1076void
1077eventHelper_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 */
1095void
1096eventHelper_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
1110void
1111eventHelper_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