diff --git a/src/node.cc b/src/node.cc index 75783c81caa..37e6d84da72 100644 --- a/src/node.cc +++ b/src/node.cc @@ -21,8 +21,6 @@ using namespace v8; using namespace node; using namespace std; -static int exit_code = 0; - ObjectWrap::~ObjectWrap ( ) { handle_->SetInternalField(0, Undefined()); @@ -265,6 +263,20 @@ node::ParseEncoding (Handle encoding_v) } } +static void +ExecuteNativeJS (const char *filename, const char *data) +{ + HandleScope scope; + TryCatch try_catch; + ExecuteString(String::New(data), String::New(filename)); + if (try_catch.HasCaught()) { + puts("There is an error in Node's built-in javascript"); + puts("This should be reported as a bug!"); + ReportException(&try_catch); + exit(1); + } +} + int main (int argc, char *argv[]) { @@ -299,7 +311,7 @@ main (int argc, char *argv[]) NODE_SET_METHOD(node, "compile", compile); // internal NODE_SET_METHOD(node, "debug", debug); - NODE_SET_METHOD(node, "exit", node_exit); + NODE_SET_METHOD(node, "reallyExit", node_exit); Local arguments = Array::New(argc); for (int i = 0; i < argc; i++) { @@ -308,7 +320,6 @@ main (int argc, char *argv[]) } g->Set(String::New("ARGV"), arguments); - // BUILT-IN MODULES Timer::Initialize(node); @@ -330,20 +341,18 @@ main (int argc, char *argv[]) HTTPServer::Initialize(http); HTTPConnection::Initialize(http); - // NATIVE JAVASCRIPT MODULES - TryCatch try_catch; - - ExecuteString(String::New(native_http), String::New("http.js")); - if (try_catch.HasCaught()) goto native_js_error; - - ExecuteString(String::New(native_file), String::New("file.js")); - if (try_catch.HasCaught()) goto native_js_error; - - ExecuteString(String::New(native_node), String::New("node.js")); - if (try_catch.HasCaught()) goto native_js_error; + ExecuteNativeJS("http.js", native_http); + ExecuteNativeJS("file.js", native_file); + ExecuteNativeJS("node.js", native_node); ev_loop(EV_DEFAULT_UC_ 0); + // call node.exit() + Local exit_v = node->Get(String::New("exit")); + assert(exit_v->IsFunction()); + Handle exit_f = Handle::Cast(exit_v); + exit_f->Call(g, 0, NULL); + context.Dispose(); // The following line when uncommented causes an error. // To reproduce do this: @@ -353,9 +362,5 @@ main (int argc, char *argv[]) // //V8::Dispose(); - return exit_code; - -native_js_error: - ReportException(&try_catch); - return 1; + return 0; } diff --git a/src/node.js b/src/node.js index f96eeb719e5..d558f977bf9 100644 --- a/src/node.js +++ b/src/node.js @@ -138,9 +138,41 @@ node.Module.prototype.loadChildren = function (callback) { } }; -node.Module.prototype.exit = function (callback) { - throw "not implemented"; +node.Module.prototype.exitChildren = function (callback) { + var children = this.children; + if (children.length == 0 && callback) callback(); + var nexited = 0; + for (var i = 0; i < children.length; i++) { + children[i].exit(function () { + nexited += 1; + if (nexited == children.length && callback) callback(); + }); + } }; -// Load the root module. I.E. the command line argument. -(new node.Module({ path: ARGV[1], target: this })).load(); +node.Module.prototype.exit = function (callback) { + var self = this; + + if (self.exited) + throw "Module '" + self.filename + "' is already exited."; + + this.exitChildren(function () { + if (self.onExit) { + self.onExit(); + } + self.exited = true; + if (callback) callback() + }); +}; + +(function () { + // Load the root module. I.E. the command line argument. + root_module = new node.Module({ path: ARGV[1], target: this }); + root_module.load(); + + node.exit = function (code) { + root_module.exit(function () { + node.reallyExit(code); + }); + }; +}()) diff --git a/test/fixtures/a.js b/test/fixtures/a.js index d1405e2d16e..2d23232805c 100644 --- a/test/fixtures/a.js +++ b/test/fixtures/a.js @@ -1,10 +1,18 @@ var c = require("b/c.js"); +var string = "A"; + exports.A = function () { - return "A"; + return string; }; + exports.C = function () { return c.C(); }; + exports.D = function () { return c.D(); }; + +function onExit () { + string = "A done"; +} diff --git a/test/fixtures/b/c.js b/test/fixtures/b/c.js index 72b539e7296..e2091fdaa85 100644 --- a/test/fixtures/b/c.js +++ b/test/fixtures/b/c.js @@ -1,9 +1,16 @@ var d = require("d.js"); +var string = "C"; + exports.C = function () { - return "C"; + return string; }; exports.D = function () { return d.D(); }; + +function onExit () { + puts("c.js onExit called"); + string = "C done"; +} diff --git a/test/fixtures/b/d.js b/test/fixtures/b/d.js index e7ae0e8d1a6..7e178e99b3c 100644 --- a/test/fixtures/b/d.js +++ b/test/fixtures/b/d.js @@ -1,4 +1,11 @@ +var string = "D"; + exports.D = function () { - return "D"; + return string; }; +function onExit () { + node.debug("d.js onExit called"); + string = "D done"; +} + diff --git a/test/test-module-loading.js b/test/test-module-loading.js index aa4c28823a9..519c516510e 100644 --- a/test/test-module-loading.js +++ b/test/test-module-loading.js @@ -21,3 +21,22 @@ function onLoad () { assertInstanceof(d2.D, Function); assertEquals("D", d2.D()); } + +function onExit () { + assertInstanceof(a.A, Function); + assertEquals("A done", a.A()); + + assertInstanceof(a.C, Function); + assertEquals("C done", a.C()); + + assertInstanceof(a.D, Function); + assertEquals("D done", a.D()); + + assertInstanceof(d.D, Function); + assertEquals("D done", d.D()); + + assertInstanceof(d2.D, Function); + assertEquals("D done", d2.D()); + + node.debug("test-module-loading.js onExit() called"); +} diff --git a/website/api.html b/website/api.html index d67e67a4e4b..3290ae9d9b1 100644 --- a/website/api.html +++ b/website/api.html @@ -944,6 +944,23 @@ function onLoad () { used after onLoad() is called. So put them at the beginning of your file.

+ +

+ Additionally when node.exit() is called or when + a program exits naturally, the function onExit() will be + called for each module (children first). + The onExit() callback cannot perform I/O as the process is + going to forcably exit in several microseconds, however it is a good + hook to perform some constant time checks of the module's state. + It's useful for unit tests. +

+ +

+ Just to reiterate: onExit(), is not the place to close + files or shutdown servers. The process will exit before they get + performed. +

+