mirror of https://github.com/nodejs/node.git
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:
parent
6f82b9f482
commit
e4a8d2617b
32
src/node.cc
32
src/node.cc
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'binding',
|
||||
'sources': [ 'binding.cc' ]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
var binding = require('./build/Release/binding');
|
Loading…
Reference in New Issue