var result = addon.add(obj1, obj2);
console.log(result); // 30
+
+### AtExit hooks
+#### void AtExit(callback, args)
+
+* `callback`: `void (*)(void*)` - A pointer to the function to call at exit.
+* `args`: `void*` - A pointer to pass to the callback at exit.
+
+Registers exit hooks that run after the event loop has ended, but before the VM
+is killed.
+
+Callbacks are run in last-in, first-out order. AtExit takes two parameters:
+a pointer to a callback function to run at exit, and a pointer to untyped
+context data to be passed to that callback.
+
+The file `addon.cc` implements AtExit below:
+
+ // addon.cc
+ #undef NDEBUG
+ #include <assert.h>
+ #include <stdlib.h>
+ #include <node.h>
+
+ namespace demo {
+
+ using node::AtExit;
+ using v8::HandleScope;
+ using v8::Isolate;
+ 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) {
+ Isolate* isolate = static_cast<Isolate*>(arg);
+ HandleScope scope(isolate);
+ Local<Object> obj = Object::New(isolate);
+ 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(Local<Object> exports) {
+ AtExit(sanity_check);
+ AtExit(at_exit_cb2, cookie);
+ AtExit(at_exit_cb2, cookie);
+ AtExit(at_exit_cb1, exports->GetIsolate());
+ }
+
+ NODE_MODULE(addon, init);
+
+ } // namespace demo
+
+Test in JavaScript by running:
+
+ // test.js
+ var addon = require('./build/Release/addon');