static void handleReportVMInitCommand(JNIEnv* env, ReportVMInitCommand *command) { PacketOutputStream out; if (command->suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) { (void)threadControl_suspendAll(); } else if (command->suspendPolicy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) { (void)threadControl_suspendThread(command->thread, JNI_FALSE); } outStream_initCommand(&out, uniqueID(), 0x0, JDWP_COMMAND_SET(Event), JDWP_COMMAND(Event, Composite)); (void)outStream_writeByte(&out, command->suspendPolicy); (void)outStream_writeInt(&out, 1); /* Always one component */ (void)outStream_writeByte(&out, JDWP_EVENT(VM_INIT)); (void)outStream_writeInt(&out, 0); /* Not in response to an event req. */ (void)outStream_writeObjectRef(env, &out, command->thread); outStream_sendCommand(&out); outStream_destroy(&out); /* Why aren't we tossing this: tossGlobalRef(env, &(command->thread)); */ }
static void handleReportEventCompositeCommand(JNIEnv *env, ReportEventCompositeCommand *recc) { PacketOutputStream out; jint count = recc->eventCount; jint i; if (recc->suspendPolicy != JDWP_SUSPEND_POLICY(NONE)) { /* must determine thread to interrupt before writing */ /* since writing destroys it */ jthread thread = NULL; for (i = 0; i < count; i++) { CommandSingle *single = &(recc->singleCommand[i]); switch (single->singleKind) { case COMMAND_SINGLE_EVENT: thread = single->u.eventCommand.info.thread; break; case COMMAND_SINGLE_FRAME_EVENT: thread = single->u.frameEventCommand.thread; break; } if (thread != NULL) { break; } } if (thread == NULL) { (void)threadControl_suspendAll(); } else { suspendWithInvokeEnabled(recc->suspendPolicy, thread); } } outStream_initCommand(&out, uniqueID(), 0x0, JDWP_COMMAND_SET(Event), JDWP_COMMAND(Event, Composite)); (void)outStream_writeByte(&out, recc->suspendPolicy); (void)outStream_writeInt(&out, count); for (i = 0; i < count; i++) { CommandSingle *single = &(recc->singleCommand[i]); switch (single->singleKind) { case COMMAND_SINGLE_EVENT: handleEventCommandSingle(env, &out, &single->u.eventCommand); break; case COMMAND_SINGLE_UNLOAD: handleUnloadCommandSingle(env, &out, &single->u.unloadCommand); break; case COMMAND_SINGLE_FRAME_EVENT: handleFrameEventCommandSingle(env, &out, &single->u.frameEventCommand); break; } } outStream_sendCommand(&out); outStream_destroy(&out); }
void debugLoop_run(void) { jboolean shouldListen; jdwpPacket p; jvmtiStartFunction func; /* Initialize all statics */ /* We may be starting a new connection after an error */ cmdQueue = NULL; cmdQueueLock = debugMonitorCreate("JDWP Command Queue Lock"); transportError = JNI_FALSE; shouldListen = JNI_TRUE; func = &reader; (void)spawnNewThread(func, NULL, "JDWP Command Reader"); standardHandlers_onConnect(); threadControl_onConnect(); /* Okay, start reading cmds! */ while (shouldListen) { if (!dequeue(&p)) { break; } if (p.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) { /* * Its a reply packet. */ continue; } else { /* * Its a cmd packet. */ jdwpCmdPacket *cmd = &p.type.cmd; PacketInputStream in; PacketOutputStream out; CommandHandler func; /* Should reply be sent to sender. * For error handling, assume yes, since * only VM/exit does not reply */ jboolean replyToSender = JNI_TRUE; /* * For VirtualMachine.Resume commands we hold the resumeLock * while executing and replying to the command. This ensures * that a Resume after VM_DEATH will be allowed to complete * before the thread posting the VM_DEATH continues VM * termination. */ if (resumeCommand(cmd)) { debugMonitorEnter(resumeLock); } /* Initialize the input and output streams */ inStream_init(&in, p); outStream_initReply(&out, inStream_id(&in)); LOG_MISC(("Command set %d, command %d", cmd->cmdSet, cmd->cmd)); func = debugDispatch_getHandler(cmd->cmdSet,cmd->cmd); if (func == NULL) { /* we've never heard of this, so I guess we * haven't implemented it. * Handle gracefully for future expansion * and platform / vendor expansion. */ outStream_setError(&out, JDWP_ERROR(NOT_IMPLEMENTED)); } else if (gdata->vmDead && ((cmd->cmdSet) != JDWP_COMMAND_SET(VirtualMachine))) { /* Protect the VM from calls while dead. * VirtualMachine cmdSet quietly ignores some cmds * after VM death, so, it sends it's own errors. */ outStream_setError(&out, JDWP_ERROR(VM_DEAD)); } else { /* Call the command handler */ replyToSender = func(&in, &out); } /* Reply to the sender */ if (replyToSender) { if (inStream_error(&in)) { outStream_setError(&out, inStream_error(&in)); } outStream_sendReply(&out); } /* * Release the resumeLock as the reply has been posted. */ if (resumeCommand(cmd)) { debugMonitorExit(resumeLock); } inStream_destroy(&in); outStream_destroy(&out); shouldListen = !lastCommand(cmd); } } threadControl_onDisconnect(); standardHandlers_onDisconnect(); /* * Cut off the transport immediately. This has the effect of * cutting off any events that the eventHelper thread might * be trying to send. */ transport_close(); debugMonitorDestroy(cmdQueueLock); /* Reset for a new connection to this VM if it's still alive */ if ( ! gdata->vmDead ) { debugInit_reset(getEnv()); } }