Skip to content

Commit

Permalink
addon: add AtExit() function
Browse files Browse the repository at this point in the history
Lets native addons register exit hooks that run after the event loop has quit
but before the VM is killed.

Fixes #3147.
  • Loading branch information
bnoordhuis committed May 3, 2012
1 parent 6f82b9f commit e4a8d26
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2770,6 +2770,37 @@ char** Init(int argc, char *argv[]) {
}


struct AtExitCallback {
AtExitCallback* next_;
void (*cb_)(void* arg);
void* arg_;
};

static AtExitCallback* at_exit_functions_;


void RunAtExit() {
AtExitCallback* p = at_exit_functions_;
at_exit_functions_ = NULL;

while (p) {
AtExitCallback* q = p->next_;
p->cb_(p->arg_);
delete p;
p = q;
}
}


void AtExit(void (*cb)(void* arg), void* arg) {
AtExitCallback* p = new AtExitCallback;
p->cb_ = cb;
p->arg_ = arg;
p->next_ = at_exit_functions_;
at_exit_functions_ = p;
}


void EmitExit(v8::Handle<v8::Object> process_l) {
// process.emit('exit')
process_l->Set(String::NewSymbol("_exiting"), True());
Expand Down Expand Up @@ -2850,6 +2881,7 @@ int Start(int argc, char *argv[]) {
uv_run(uv_default_loop());

EmitExit(process_l);
RunAtExit();

#ifndef NDEBUG
// Clean up.
Expand Down
5 changes: 5 additions & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ node_module_struct* get_builtin_module(const char *name);
#define NODE_MODULE_DECL(modname) \
extern "C" node::node_module_struct modname ## _module;

/* Called after the event loop exits but before the VM is disposed.
* Callbacks are run in reverse order of registration, i.e. newest first.
*/
NODE_EXTERN void AtExit(void (*cb)(void* arg), void* arg = 0);

NODE_EXTERN void SetErrno(uv_err_t err);
NODE_EXTERN v8::Handle<v8::Value>
MakeCallback(const v8::Handle<v8::Object> object,
Expand Down
43 changes: 43 additions & 0 deletions test/addons/at-exit/binding.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#undef NDEBUG
#include <assert.h>
#include <stdlib.h>
#include <node.h>
#include <v8.h>

using node::AtExit;
using v8::Handle;
using v8::HandleScope;
using v8::Local;
using v8::Object;

static char cookie[] = "yum yum";
static int at_exit_cb1_called = 0;
static int at_exit_cb2_called = 0;

static void at_exit_cb1(void* arg) {
HandleScope scope;
assert(arg == 0);
Local<Object> obj = Object::New();
assert(!obj.IsEmpty()); // assert VM is still alive
assert(obj->IsObject());
at_exit_cb1_called++;
}

static void at_exit_cb2(void* arg) {
assert(arg == static_cast<void*>(cookie));
at_exit_cb2_called++;
}

static void sanity_check(void) {
assert(at_exit_cb1_called == 1);
assert(at_exit_cb2_called == 2);
}

void init(Handle<Object> target) {
AtExit(at_exit_cb1);
AtExit(at_exit_cb2, cookie);
AtExit(at_exit_cb2, cookie);
atexit(sanity_check);
}

NODE_MODULE(binding, init);
8 changes: 8 additions & 0 deletions test/addons/at-exit/binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ]
}
]
}
1 change: 1 addition & 0 deletions test/addons/at-exit/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
var binding = require('./build/Release/binding');

0 comments on commit e4a8d26

Please sign in to comment.