void eventHelper_initialize(jbyte sessionID) { jvmtiStartFunction func; currentSessionID = sessionID; holdEvents = JNI_FALSE; commandQueue.head = NULL; commandQueue.tail = NULL; commandQueueLock = debugMonitorCreate("JDWP Event Helper Queue Monitor"); commandCompleteLock = debugMonitorCreate("JDWP Event Helper Completion Monitor"); blockCommandLoopLock = debugMonitorCreate("JDWP Event Block CommandLoop Monitor"); /* Start the event handler thread */ func = &commandLoop; (void)spawnNewThread(func, NULL, "JDWP Event Helper Thread"); }
jdwpError transport_startTransport(jboolean isServer, char *name, char *address, long timeout) { jvmtiStartFunction func; jdwpTransportEnv *trans; char threadName[MAXPATHLEN + 100]; jint err; jdwpError serror; /* * If the transport is already loaded then use it * Note: We're assuming here that we don't support multiple * transports - when we do then we need to handle the case * where the transport library only supports a single environment. * That probably means we have a bag a transport environments * to correspond to the transports bag. */ if (transport != NULL) { trans = transport; } else { serror = loadTransport(name, &trans); if (serror != JDWP_ERROR(NONE)) { return serror; } } if (isServer) { char *retAddress; char *launchCommand; TransportInfo *info; jvmtiError error; int len; char* prop_value; info = jvmtiAllocate(sizeof(*info)); if (info == NULL) { return JDWP_ERROR(OUT_OF_MEMORY); } info->name = jvmtiAllocate((int)strlen(name)+1); (void)strcpy(info->name, name); info->address = NULL; info->timeout = timeout; if (info->name == NULL) { serror = JDWP_ERROR(OUT_OF_MEMORY); goto handleError; } if (address != NULL) { info->address = jvmtiAllocate((int)strlen(address)+1); (void)strcpy(info->address, address); if (info->address == NULL) { serror = JDWP_ERROR(OUT_OF_MEMORY); goto handleError; } } info->transport = trans; err = (*trans)->StartListening(trans, address, &retAddress); if (err != JDWPTRANSPORT_ERROR_NONE) { printLastError(trans, err); serror = JDWP_ERROR(TRANSPORT_INIT); goto handleError; } /* * Record listener address in a system property */ len = (int)strlen(name) + (int)strlen(retAddress) + 2; /* ':' and '\0' */ prop_value = (char*)jvmtiAllocate(len); strcpy(prop_value, name); strcat(prop_value, ":"); strcat(prop_value, retAddress); setTransportProperty(getEnv(), prop_value); jvmtiDeallocate(prop_value); (void)strcpy(threadName, "JDWP Transport Listener: "); (void)strcat(threadName, name); func = &acceptThread; error = spawnNewThread(func, (void*)info, threadName); if (error != JVMTI_ERROR_NONE) { serror = map2jdwpError(error); goto handleError; } launchCommand = debugInit_launchOnInit(); if (launchCommand != NULL) { serror = launch(launchCommand, name, retAddress); if (serror != JDWP_ERROR(NONE)) { goto handleError; } } else { if ( ! gdata->quiet ) { TTY_MESSAGE(("Listening for transport %s at address: %s", name, retAddress)); } } return JDWP_ERROR(NONE); handleError: jvmtiDeallocate(info->name); jvmtiDeallocate(info->address); jvmtiDeallocate(info); } else { /* * Note that we don't attempt to do a launch here. Launching * is currently supported only in server mode. */ /* * If we're connecting to another process, there shouldn't be * any concurrent listens, so its ok if we block here in this * thread, waiting for the attach to finish. */ err = (*trans)->Attach(trans, address, timeout, 0); if (err != JDWPTRANSPORT_ERROR_NONE) { printLastError(trans, err); serror = JDWP_ERROR(TRANSPORT_INIT); return serror; } /* * Start the transport loop in a separate thread */ (void)strcpy(threadName, "JDWP Transport Listener: "); (void)strcat(threadName, name); func = &attachThread; err = spawnNewThread(func, (void*)trans, threadName); serror = map2jdwpError(err); } return serror; }
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()); } }