#include "node.h" #include "uv.h" #include #include #include #ifdef NDEBUG #define CHECK(x) do { if (!(x)) abort(); } while (false) #else #define CHECK assert #endif #define CHECK_EQ(a, b) CHECK((a) == (b)) namespace { struct Callback { inline Callback(v8::Isolate* isolate, v8::Local object, v8::Local function) : object(isolate, object), function(isolate, function) {} v8::Persistent object; v8::Persistent function; }; static uv_async_t async_handle; static std::vector callbacks; inline void Prime() { uv_ref(reinterpret_cast(&async_handle)); CHECK_EQ(0, uv_async_send(&async_handle)); } inline void AsyncCallback(uv_async_t*) { auto isolate = v8::Isolate::GetCurrent(); v8::HandleScope handle_scope(isolate); auto context = isolate->GetCurrentContext(); auto global = context->Global(); while (!callbacks.empty()) { v8::HandleScope handle_scope(isolate); auto callback = callbacks.back(); callbacks.pop_back(); auto function = v8::Local::New(isolate, callback->function); delete callback; if (node::MakeCallback(isolate, global, function, 0, nullptr).IsEmpty()) return Prime(); // Have exception, flush remainder on next loop tick. } uv_unref(reinterpret_cast(&async_handle)); } inline void OnGC(const v8::FunctionCallbackInfo& info) { CHECK(info[0]->IsObject()); CHECK(info[1]->IsFunction()); auto object = info[0].As(); auto function = info[1].As(); auto callback = new Callback(info.GetIsolate(), object, function); auto on_callback = [] (const v8::WeakCallbackInfo& data) { auto callback = data.GetParameter(); callbacks.push_back(callback); callback->object.Reset(); Prime(); }; callback->object.SetWeak(callback, on_callback, v8::WeakCallbackType::kParameter); } inline void Initialize(v8::Local exports, v8::Local module, v8::Local context) { NODE_SET_METHOD(module->ToObject(context).ToLocalChecked(), "exports", OnGC); CHECK_EQ(0, uv_async_init(uv_default_loop(), &async_handle, AsyncCallback)); uv_unref(reinterpret_cast(&async_handle)); } } // anonymous namespace NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize)