Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src,napi: add helper for addons to get the event loop #17109

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
src: add helper for addons to get the event loop
Add a utility functions for addons to use when they need
a reference to the current event loop.

Currently, `uv_default_loop()` works if the embedder is the
single-threaded default node executable, but even without
the presence of e.g. workers that might not really an API
guarantee for when Node is embedded.
  • Loading branch information
addaleax committed Nov 17, 2017
commit 0870c4a1410b50d20b62e1621e2240eefebde94c
5 changes: 5 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4419,6 +4419,11 @@ void RunAtExit(Environment* env) {
}


uv_loop_t* GetCurrentEventLoop(v8::Isolate* isolate) {
return Environment::GetCurrent(isolate)->event_loop();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaks a handle into the caller's scope.

The overload that takes a v8::Isolate* calls Environment::GetCurrent(isolate->GetCurrentContext()) but that won't work when there is no current context or it doesn't have an associated Environment (i.e, non-node context.)

That should be documented because it's the kind of thing that add-ons will run into. You could robustify (def a word) this function by doing:

uv_loop_t* GetCurrentEventLoop(v8::Isolate* isolate) {
  HandleScope handle_scope(isolate);
  auto context = isolate->GetCurrentContext();
  if (context.IsEmpty()) return nullptr;
  return Environment::GetCurrent(context);
}

That can still crash with a non-node context, though. Maybe we should file a CL with V8 to expose
v8::Context::SlowGetAlignedPointerFromEmbedderData() in order to safely retrieve the Environment pointer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, thanks for catching those. Updated with your suggestion!

}


static uv_key_t thread_local_env;


Expand Down
2 changes: 2 additions & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ NODE_EXTERN void EmitBeforeExit(Environment* env);
NODE_EXTERN int EmitExit(Environment* env);
NODE_EXTERN void RunAtExit(Environment* env);

NODE_EXTERN struct uv_loop_s* GetCurrentEventLoop(v8::Isolate* isolate);

/* Converts a unixtime to V8 Date */
#define NODE_UNIXTIME_V8(t) v8::Date::New(v8::Isolate::GetCurrent(), \
1000 * static_cast<double>(t))
Expand Down
2 changes: 1 addition & 1 deletion test/addons/async-hello-world/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void Method(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(args[1]);
req->callback.Reset(isolate, callback);

uv_queue_work(uv_default_loop(),
uv_queue_work(node::GetCurrentEventLoop(isolate),
&req->req,
DoAsync,
(uv_after_work_cb)AfterAsync<use_makecallback>);
Expand Down
5 changes: 4 additions & 1 deletion test/addons/callback-scope/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ static void TestResolveAsync(const v8::FunctionCallbackInfo<v8::Value>& args) {

uv_work_t* req = new uv_work_t;

uv_queue_work(uv_default_loop(), req, [](uv_work_t*) {}, Callback);
uv_queue_work(node::GetCurrentEventLoop(isolate),
req,
[](uv_work_t*) {},
Callback);
}

v8::Local<v8::Promise::Resolver> local =
Expand Down