// Declared in node_internals.h
Isolate* node_isolate = NULL;
+enum ProcessState {
+ INITIALIZING,
+ RUNNING,
+ SHUTTING_DOWN
+};
+
+static ProcessState process_state = INITIALIZING;
+
class ArrayBufferAllocator : public ArrayBuffer::Allocator {
public:
const Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
+ if (process_state == SHUTTING_DOWN)
+ return Undefined(node_isolate);
+
// TODO(trevnorris) Hook for long stack traces to be made here.
Local<Object> process = PersistentToLocal(node_isolate, process_p);
#endif // __POSIX__ && !defined(__ANDROID__)
+void MaybeCloseNamedPipe(uv_shutdown_t* req, int status) {
+ uv_handle_t* handle = reinterpret_cast<uv_handle_t*>(req->handle);
+ delete req;
+
+ if (status == UV_ECANCELED) {
+ return; // Already closing.
+ }
+ if (status == UV_EPIPE) {
+ return; // Read end went away before shutdown completed.
+ }
+ assert(status == 0);
+
+ if (uv_is_closing(handle)) {
+ return;
+ }
+
+ uv_close(handle, NULL);
+}
+
+
+void MaybeCloseHandle(uv_handle_t* handle, void* unused) {
+ if (uv_is_closing(handle)) {
+ return;
+ }
+
+ // Named pipes get special treatment: we do a shutdown first to flush
+ // pending writes. Avoids truncated stdout/stderr output on Windows.
+ bool do_shutdown = handle->type == UV_NAMED_PIPE &&
+ uv_is_writable(reinterpret_cast<uv_stream_t*>(handle));
+
+ if (do_shutdown == false) {
+ uv_close(handle, NULL);
+ return;
+ }
+
+ uv_shutdown_t* req = new uv_shutdown_t;
+ uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(handle);
+ int err = uv_shutdown(req, stream, MaybeCloseNamedPipe);
+ if (err) {
+ assert(err == UV_ENOTCONN);
+ delete req;
+ }
+}
+
+
+void DisposeEventLoop(uv_loop_t* loop) {
+ // Don't call into JS land from now on.
+ process_state = SHUTTING_DOWN;
+ // Force-close open handles.
+ uv_walk(loop, MaybeCloseHandle, NULL);
+ uv_run(loop, UV_RUN_DEFAULT);
+ uv_loop_delete(loop);
+}
+
+
void Exit(const FunctionCallbackInfo<Value>& args) {
HandleScope scope(node_isolate);
- exit(args[0]->IntegerValue());
+ int32_t exit_code = args[0]->Int32Value();
+ DisposeEventLoop(uv_default_loop());
+ exit(exit_code);
}
// there are no watchers on the loop (except for the ones that were
// uv_unref'd) then this function exits. As long as there are active
// watchers, it blocks.
+ process_state = RUNNING;
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
EmitExit(process_l);
RunAtExit();
}
-#ifndef NDEBUG
- // Clean up. Not strictly necessary.
+ DisposeEventLoop(uv_default_loop());
V8::Dispose();
- uv_loop_delete(uv_default_loop());
-#endif // NDEBUG
// Clean up the copy:
free(argv_copy);
--- /dev/null
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+
+process.on('exit', function() {
+ console.log(''); // Should not assert, see joyent/libuv#911.
+});