diff options
author | Anatoli Papirovski <apapirovski@mac.com> | 2018-01-19 00:52:51 +0300 |
---|---|---|
committer | Anatoli Papirovski <apapirovski@mac.com> | 2018-01-21 20:39:41 +0300 |
commit | 8803b69c724e7b03ec0fc4c82b71575262487624 (patch) | |
tree | 4e7b737d45ada0a40c2d142a9fd44a26270335ba /src/async_wrap.cc | |
parent | d62566e1b1bb4734635d51d53c16f6efa3a7f5b5 (diff) |
async_wrap: schedule destroy hook as unref
Since the `DestroyAsyncIdsCallback` in Node.js can be scheduled as
a result of GC, that means that it can accidentally keep the event
loop open when it shouldn't.
Replace `SetImmediate` with the newly introduced `SetUnrefImmediate`
and in addition introduce RunBeforeExit callbacks, of which
`DestroyAsyncIdsCallback` is now the first. These callbacks will run
before the `beforeExit` event is emitted (which will now only be
emitted if the event loop is still not active).
PR-URL: https://github.com/nodejs/node/pull/18241
Fixes: https://github.com/nodejs/node/issues/18190
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Andreas Madsen <amwebdk@gmail.com>
Diffstat (limited to 'src/async_wrap.cc')
-rw-r--r-- | src/async_wrap.cc | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/src/async_wrap.cc b/src/async_wrap.cc index f770348b9c9..5258674ff33 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -159,6 +159,12 @@ static void DestroyAsyncIdsCallback(Environment* env, void* data) { } while (!env->destroy_async_id_list()->empty()); } +static void DestroyAsyncIdsCallback(void* arg) { + Environment* env = static_cast<Environment*>(arg); + if (!env->destroy_async_id_list()->empty()) + DestroyAsyncIdsCallback(env, nullptr); +} + void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) { AsyncHooks* async_hooks = env->async_hooks(); @@ -502,6 +508,8 @@ void AsyncWrap::Initialize(Local<Object> target, Isolate* isolate = env->isolate(); HandleScope scope(isolate); + env->BeforeExit(DestroyAsyncIdsCallback, env); + env->SetMethod(target, "setupHooks", SetupHooks); env->SetMethod(target, "pushAsyncIds", PushAsyncIds); env->SetMethod(target, "popAsyncIds", PopAsyncIds); @@ -663,7 +671,7 @@ void AsyncWrap::EmitDestroy(Environment* env, double async_id) { return; if (env->destroy_async_id_list()->empty()) { - env->SetImmediate(DestroyAsyncIdsCallback, nullptr); + env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr); } env->destroy_async_id_list()->push_back(async_id); |