addon: add AtExit() function

Lets native addons register exit hooks that run after the event loop has quit
but before the VM is killed.

Fixes #3147.
This commit is contained in:
Ben Noordhuis 2012-04-21 07:13:25 +02:00
parent 6f82b9f482
commit e4a8d2617b
5 changed files with 89 additions and 0 deletions

View File

@ -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());
@ -2850,6 +2881,7 @@ int Start(int argc, char *argv[]) {
uv_run(uv_default_loop());
EmitExit(process_l);
RunAtExit();
#ifndef NDEBUG
// Clean up.

View File

@ -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,

View File

@ -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);

View File

@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ]
}
]
}

View File

@ -0,0 +1 @@
var binding = require('./build/Release/binding');