Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

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
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
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
@@ -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
@@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ]
}
]
}
1 change: 1 addition & 0 deletions test/addons/at-exit/test.js
@@ -0,0 +1 @@
var binding = require('./build/Release/binding');

0 comments on commit e4a8d26

Please sign in to comment.