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) {
|
void EmitExit(v8::Handle<v8::Object> process_l) {
|
||||||
// process.emit('exit')
|
// process.emit('exit')
|
||||||
process_l->Set(String::NewSymbol("_exiting"), True());
|
process_l->Set(String::NewSymbol("_exiting"), True());
|
||||||
@ -2850,6 +2881,7 @@ int Start(int argc, char *argv[]) {
|
|||||||
uv_run(uv_default_loop());
|
uv_run(uv_default_loop());
|
||||||
|
|
||||||
EmitExit(process_l);
|
EmitExit(process_l);
|
||||||
|
RunAtExit();
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Clean up.
|
// Clean up.
|
||||||
|
@ -250,6 +250,11 @@ node_module_struct* get_builtin_module(const char *name);
|
|||||||
#define NODE_MODULE_DECL(modname) \
|
#define NODE_MODULE_DECL(modname) \
|
||||||
extern "C" node::node_module_struct modname ## _module;
|
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 void SetErrno(uv_err_t err);
|
||||||
NODE_EXTERN v8::Handle<v8::Value>
|
NODE_EXTERN v8::Handle<v8::Value>
|
||||||
MakeCallback(const v8::Handle<v8::Object> object,
|
MakeCallback(const v8::Handle<v8::Object> object,
|
||||||
|
43
test/addons/at-exit/binding.cc
Normal file
43
test/addons/at-exit/binding.cc
Normal 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);
|
8
test/addons/at-exit/binding.gyp
Normal file
8
test/addons/at-exit/binding.gyp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'binding',
|
||||||
|
'sources': [ 'binding.cc' ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1
test/addons/at-exit/test.js
Normal file
1
test/addons/at-exit/test.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
var binding = require('./build/Release/binding');
|
Loading…
x
Reference in New Issue
Block a user