diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index a3ebaa40b54..c25a5c84f51 100644
--- a/deps/uv/include/uv.h
+++ b/deps/uv/include/uv.h
@@ -267,6 +267,12 @@ UV_EXTERN uv_loop_t* uv_default_loop(void);
  */
 UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
 
+/*
+ * This function checks whether the reference count, the number of active
+ * handles or requests left in the event loop, is non-zero.
+ */
+UV_EXTERN int uv_loop_alive(uv_loop_t* loop);
+
 /*
  * This function will stop the event loop by forcing uv_run to end
  * as soon as possible, but not sooner than the next loop iteration.
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c
index 98b48989a74..a49285514ee 100644
--- a/deps/uv/src/unix/core.c
+++ b/deps/uv/src/unix/core.c
@@ -291,6 +291,11 @@ static int uv__loop_alive(uv_loop_t* loop) {
 }
 
 
+int uv_loop_alive(uv_loop_t* loop) {
+    return uv__loop_alive(loop);
+}
+
+
 int uv_run(uv_loop_t* loop, uv_run_mode mode) {
   int timeout;
   int r;
diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c
index 3ba3203803f..f6c17af9d98 100644
--- a/deps/uv/src/win/core.c
+++ b/deps/uv/src/win/core.c
@@ -265,6 +265,11 @@ static int uv__loop_alive(uv_loop_t* loop) {
 }
 
 
+int uv_loop_alive(uv_loop_t* loop) {
+    return uv__loop_alive(loop);
+}
+
+
 int uv_run(uv_loop_t *loop, uv_run_mode mode) {
   int r;
   void (*poll)(uv_loop_t* loop, int block);
diff --git a/doc/api/process.markdown b/doc/api/process.markdown
index 7add27e96c2..81e48971bc5 100644
--- a/doc/api/process.markdown
+++ b/doc/api/process.markdown
@@ -22,6 +22,18 @@ Example of listening for `exit`:
       console.log('About to exit.');
     });
 
+
+## Event: 'beforeExit'
+
+This event is emitted when node empties its event loop and has nothing else to
+schedule.  Normally, node exits when there is no work scheduled, but a listener
+for 'beforeExit' can make asynchronous calls, and cause node to continue.
+
+'beforeExit' is not emitted for conditions causing explicit termination, such as
+`process.exit()` or uncaught exceptions, and should not be used as an
+alternative to the 'exit' event unless the intention is to schedule more work.
+
+
 ## Event: 'uncaughtException'
 
 Emitted when an exception bubbles all the way back to the event loop. If a
diff --git a/src/node.cc b/src/node.cc
index b681c292afc..5eaf43d6a49 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -3033,6 +3033,14 @@ void EmitExit(v8::Handle<v8::Object> process_l) {
   MakeCallback(process, "emit", ARRAY_SIZE(args), args);
 }
 
+
+void EmitBeforeExit(Handle<Object> process_l) {
+  // process.emit('beforeExit')
+  Local<Value> args[] = { String::New("beforeExit"), Integer::New(0, node_isolate) };
+  MakeCallback(process, "emit", ARRAY_SIZE(args), args);
+}
+
+
 static char **copy_argv(int argc, char **argv) {
   size_t strlen_sum;
   char **argv_copy;
@@ -3093,12 +3101,18 @@ int Start(int argc, char *argv[]) {
     // so your next reading stop should be node::Load()!
     Load(process_l);
 
-    // All our arguments are loaded. We've evaluated all of the scripts. We
-    // might even have created TCP servers. Now we enter the main eventloop. If
-    // 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.
-    uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+    do {
+        // All our arguments are loaded. We've evaluated all of the scripts. We
+        // might even have created TCP servers. Now we enter the main eventloop. If
+        // 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.
+        uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+        EmitBeforeExit(process_l);
+
+        // 'keepalive' event may have brought the loop back to life
+    } while(uv_loop_alive(uv_default_loop()));
 
     EmitExit(process_l);
     RunAtExit();
diff --git a/test/simple/test-beforeexit-event-exit.js b/test/simple/test-beforeexit-event-exit.js
new file mode 100644
index 00000000000..be6f2c607c3
--- /dev/null
+++ b/test/simple/test-beforeexit-event-exit.js
@@ -0,0 +1,28 @@
+// 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 assert = require('assert');
+
+process.on('beforeExit', function() {
+  assert(false, 'exit should not allow this to occur');
+});
+
+process.exit();
diff --git a/test/simple/test-beforeexit-event.js b/test/simple/test-beforeexit-event.js
new file mode 100644
index 00000000000..3d011fdeacb
--- /dev/null
+++ b/test/simple/test-beforeexit-event.js
@@ -0,0 +1,58 @@
+// 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 assert = require('assert');
+var net = require('net');
+var util = require('util');
+var revivals = 0;
+var deaths = 0;
+
+process.on('beforeExit', function() { deaths++; } );
+
+process.once('beforeExit', tryImmediate);
+
+function tryImmediate() {
+  setImmediate(function() {
+    revivals++;
+    process.once('beforeExit', tryTimer);
+  });
+}
+
+function tryTimer() {
+  setTimeout(function () {
+    revivals++;
+    process.once('beforeExit', tryListen);
+  }, 1);
+}
+
+function tryListen() {
+  net.createServer()
+    .listen(0)
+    .on('listening', function() {
+      revivals++;
+      this.close();
+    });
+}
+
+process.on('exit', function() {
+  assert(4 === deaths);
+  assert(3 === revivals);
+});