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.
+
+