diff options
author | Anna Henningsen <anna@addaleax.net> | 2019-07-15 23:17:45 +0300 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2019-08-01 01:51:43 +0300 |
commit | 5207dec0175de92116262e8382d6ac57def3a203 (patch) | |
tree | e90e855f7a8a228e00fe0d49fb311b319de74c3d /src/env.cc | |
parent | 61f3a5c60ad78506e9e0caae061a04ccab878ca1 (diff) |
src: allow generic C++ callables in SetImmediate()
Modify the native `SetImmediate()` functions to take generic C++
callables as arguments. This makes passing arguments to the callback
easier, and in particular, it allows passing `std::unique_ptr`s
directly, which in turn makes sure that the data they point to is
deleted if the `Environment` is torn down before the callback can run.
PR-URL: https://github.com/nodejs/node/pull/28704
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src/env.cc')
-rw-r--r-- | src/env.cc | 66 |
1 files changed, 31 insertions, 35 deletions
diff --git a/src/env.cc b/src/env.cc index f0ac855e3d8..ca5e11ac558 100644 --- a/src/env.cc +++ b/src/env.cc @@ -339,7 +339,7 @@ Environment::Environment(IsolateData* isolate_data, [](void* arg) { Environment* env = static_cast<Environment*>(arg); if (!env->destroy_async_id_list()->empty()) - AsyncWrap::DestroyAsyncIdsCallback(env, nullptr); + AsyncWrap::DestroyAsyncIdsCallback(env); }, this); @@ -642,42 +642,38 @@ void Environment::AtExit(void (*cb)(void* arg), void* arg) { void Environment::RunAndClearNativeImmediates() { TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment), "RunAndClearNativeImmediates", this); - size_t count = native_immediate_callbacks_.size(); - if (count > 0) { - size_t ref_count = 0; - std::vector<NativeImmediateCallback> list; - native_immediate_callbacks_.swap(list); - auto drain_list = [&]() { - TryCatchScope try_catch(this); - for (auto it = list.begin(); it != list.end(); ++it) { - DebugSealHandleScope seal_handle_scope(isolate()); - it->cb_(this, it->data_); - if (it->refed_) - ref_count++; - if (UNLIKELY(try_catch.HasCaught())) { - if (!try_catch.HasTerminated()) - errors::TriggerUncaughtException(isolate(), try_catch); - - // We are done with the current callback. Increase the counter so that - // the steps below make everything *after* the current item part of - // the new list. - it++; - - // Bail out, remove the already executed callbacks from list - // and set up a new TryCatch for the other pending callbacks. - std::move_backward(it, list.end(), list.begin() + (list.end() - it)); - list.resize(list.end() - it); - return true; - } + size_t ref_count = 0; + size_t count = 0; + std::unique_ptr<NativeImmediateCallback> head; + head.swap(native_immediate_callbacks_head_); + native_immediate_callbacks_tail_ = nullptr; + + auto drain_list = [&]() { + TryCatchScope try_catch(this); + for (; head; head = head->get_next()) { + DebugSealHandleScope seal_handle_scope(isolate()); + count++; + if (head->is_refed()) + ref_count++; + + head->Call(this); + if (UNLIKELY(try_catch.HasCaught())) { + if (!try_catch.HasTerminated()) + errors::TriggerUncaughtException(isolate(), try_catch); + + // We are done with the current callback. Move one iteration along, + // as if we had completed successfully. + head = head->get_next(); + return true; } - return false; - }; - while (drain_list()) {} + } + return false; + }; + while (head && drain_list()) {} - DCHECK_GE(immediate_info()->count(), count); - immediate_info()->count_dec(count); - immediate_info()->ref_count_dec(ref_count); - } + DCHECK_GE(immediate_info()->count(), count); + immediate_info()->count_dec(count); + immediate_info()->ref_count_dec(ref_count); } |