DebuggerProxyPtr Debugger::createProxy(req::ptr<Socket> socket, bool local) { TRACE(2, "Debugger::createProxy\n"); // Creates a proxy and threads needed to handle it. At this point, there is // not enough information to attach a sandbox. auto proxy = std::make_shared<DebuggerProxy>(socket, local); { // Place this new proxy into the proxy map keyed on the dummy sandbox id. // This keeps the proxy alive in the server case, which drops the result of // this function on the floor. It also makes the proxy findable when a // dummy sandbox thread needs to interrupt. const StringData* sid = makeStaticString(proxy->getDummyInfo().id()); assertx(sid); ProxyMap::accessor acc; m_proxyMap.insert(acc, sid); acc->second = proxy; } if (!local) { proxy->startDummySandbox(); } proxy->startSignalThread(); return proxy; }
/* * This file represents the client half of the JCEP communication. It * operates in much the same way as the RMI skeleton expect for two important * points: * 1) It doesn't use JRMP. Instead it uses JCEP. JCEP is a much simpler and * more expressive protocol for this specific task. This means that all the * complicated unwinding of serialized Java objects that the RMI skeleton had * are no longer necesasary. This JCEP skeleton does not have to understand * one lick of Java. * 2) It is a two-way communication. The RMI skeleton just feed a job to the * server and read the response, which either said it was received or not. It * did not continue running for the duration of the job. That means that SGE * couldn't track the job past its submission. That also meant that problems * with the job that came after execution started had to be passed back to the * ComputeProxy is be logged. Now the skeleton runs through the entire * duration of the job. Any messages or errors generated as the job runs are * sent to the skeleton, which will print them out to stdout or stderr so that * SGE can log them. That means that all information from the running of the * job is in the same SGE-generated files. It also means that the job continues * to be trackable by SGE throughout its duration. This two-way communication * also means that the JCEP skeleton has to be multi-threaded. * * Only one JCEPskeleton may be allowed to attach to a given job. The reason is * that a failed command for one will terminate them all. See the comments on * listenerThread() about line 600 for more info. */ int main (int argc, char** argv) { int serverPort, threadStatus, code; char serverIP[32]; pthread_t threadId, sigThreadId; //Process arguments processArgs (argc, argv); //Set the buffering on STDOUT to line buffering setlinebuf (stdout); //Connect to server if (debug) { printf ("**DEBUG: Beginning skeleton...\n"); printf ("**DEBUG: Creating socket to JCEP server...\n"); } // Open a socket to RMI registry if (createConnection ("127.0.0.1", PORT) < 0) { fprintf (stderr, "Unable to establish connection to JCEP server:\n\t%s\n", errorMessage); exit (1); } if (debug) { printf ("**DEBUG: Connection established.\n"); } /* The order of the following events is purposeful. The signal thread must * start before the listener thread so that the listener thread can inherit * the signal mask set in startSignalThread(). The signal thread has to * start after the command is sent because otherwise there could be * synchronization problems with the main thread and the signal thread both * trying to send a command to the server at the same time. Starting the * signal thread after the command does leave a small hole, where if SGE * tried to cancel or suspend the job immediately after starting it, the * signal could come before the signal thread is ready. This should be fixed * in the future with some explicit synchronization. */ if (taskType == SUBMIT_JOB) { /* Send job to server */ submitJob (); } else if (taskType == SHUTDOWN) { shutdownServer (); } else if (taskType == CHECKPOINT_JOB) { checkpointJob (jobId); } else if (taskType == CANCEL_JOB) { cancelJob (jobId); } else if (taskType == REGISTER) { listenToJob (jobId); } else if (taskType == SUSPEND) { suspendJob (jobId); } else if (taskType == RESUME) { resumeJob (jobId); } /* Start up a thread to handle SIGUSR1 (pending suspend), SIGUSR2 (pending * cancel), and SIGCONT (just resumed). */ if ((code = startSignalThread (&sigThreadId)) != 0) { fprintf (stderr, "Unable to start signal thread: error code %d.\n", code); exit (1); } /* Start listener thread */ if ((code = startListenerThread (&threadId)) != 0) { fprintf (stderr, "Unable to start listener thread: error code %d.\n", code); exit (1); } /* Wait for a job finished notice */ pthread_join (threadId, (void**)&threadStatus); if (debug) { printf ("**DEBUG: Listener thread has exited.\n"); } if (threadStatus < 0) { fprintf (stderr, "Listener thread received the following error:\n\t%s\n", errorMessage); exit (1); } /* Exit upon receipt of job finished notice */ return (EXIT_SUCCESS); }