Fork out to debugger on debugger statements
authorRyan Dahl <ry@tinyclouds.org>
Thu, 23 Dec 2010 01:17:34 +0000 (17:17 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Thu, 30 Dec 2010 09:35:12 +0000 (01:35 -0800)
Also implement continue in Client.

lib/_debugger.js
lib/readline.js
src/node.cc

index 25f82e7..83bc6c8 100644 (file)
@@ -212,6 +212,13 @@ Client.prototype.reqScripts = function(cb) {
 };
 
 
+Client.prototype.reqContinue = function(cb) {
+  this.req({ command: 'continue' } , function (res) {
+    if (cb) cb(res.body);
+  });
+};
+
+
 var helpMessage = "Commands: scripts, backtrace, version, eval, help, quit";
 
 
@@ -223,18 +230,33 @@ function startInterface() {
     i.write(chunk);
   });
 
-  var prompt = '> ';
+  var prompt = 'debug> ';
 
   i.setPrompt(prompt);
   i.prompt();
 
-  i.on('SIGINT', function() {
+  var quitTried = false;
+
+  function tryQuit() {
+    if (quitTried) return;
+    quitTried = true;
     i.close();
-  });
+    console.log("debug done\n");
+    if (c.writable) {
+      c.reqContinue(function (res) {
+        process.exit(0);
+      });
+    } else {
+      process.exit(0);
+    }
+  }
+
+  i.on('SIGINT', tryQuit);
+  i.on('close', tryQuit);
 
   i.on('line', function(cmd) {
     if (cmd == 'quit') {
-      process.exit(0);
+      tryQuit();
     } else if (/^help/.test(cmd)) {
       console.log(helpMessage);
       i.prompt();
@@ -251,6 +273,12 @@ function startInterface() {
         i.prompt();
       });
 
+    } else if ('continue' == cmd || 'c' == cmd) {
+      c.reqContinue(function (res) {
+        console.log(res);
+        i.prompt();
+      });
+
     } else if (/^scripts/.test(cmd)) {
       c.reqScripts(function (res) {
         var text = res.map(function (x) { return x.text; });
index 341b20b..3ae43f4 100644 (file)
@@ -160,6 +160,8 @@ Interface.prototype._refreshLine = function() {
 
 
 Interface.prototype.close = function(d) {
+  if (this._closing) return;
+  this._closing = true;
   if (this.enabled) {
     tty.setRawMode(false);
   }
index 04a96a4..d81aab8 100644 (file)
 #include <pwd.h> /* getpwnam() */
 #include <grp.h> /* getgrnam() */
 
+// waitpid
+#include <sys/types.h>
+#include <sys/wait.h>
+
+
 #include "platform.h"
 
 #include <node_buffer.h>
@@ -1908,6 +1913,57 @@ static int RegisterSignalHandler(int signal, void (*handler)(int)) {
 }
 
 
+static bool debugger_slave_running = false;
+
+static void HandleDebugEvent(DebugEvent event,
+                             Handle<Object> exec_state,
+                             Handle<Object> event_data,
+                             Handle<Value> data) {
+  HandleScope scope;
+
+  if (debugger_slave_running) return;
+
+  if (event != Break) {
+    return;
+  }
+
+  // Then we take one of two actions
+  // 1. Inspect the environ variable NODE_DEBUG_PROG; if it is not empty //
+  //    then start it. (TODO)
+  // 2. Start the built-in debugger.
+
+
+  size_t size = 2*PATH_MAX;
+  char node_path[size];
+  OS::GetExecutablePath(node_path, &size);
+
+  int pid = vfork();
+
+  if (pid == -1) {
+    perror("vfork()");
+    return;
+  }
+
+  if (pid == 0) {
+    // Child process
+    char *argv[] =  { node_path, "debug", NULL };
+    execvp(node_path, argv);
+    perror("execvp()");
+    _exit(127);
+  }
+
+  debugger_slave_running = true;
+
+  // We've hit some debugger event. First we will enable the debugger agent.
+  EnableDebug(true);
+
+  // TODO probably need to waitpid here or something to avoid zombies.
+  // int status;
+  // waitpid(pid, &status, 0);
+  Debug::DebugBreak();
+}
+
+
 int Start(int argc, char *argv[]) {
   // Hack aroung with the argv pointer. Used for process.title = "blah".
   argv = node::Platform::SetupArgs(argc, argv);
@@ -2022,7 +2078,8 @@ int Start(int argc, char *argv[]) {
 
   // If the --debug flag was specified then initialize the debug thread.
   if (node::use_debug_agent) {
-    EnableDebug(debug_wait_connect);
+    // XXX: only use if debug flag enabled?
+    Debug::SetDebugEventListener(HandleDebugEvent);
   } else {
     RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
     ev_async_init(&enable_debug, EnableDebug2);