diff options
author | Anna Henningsen <anna@addaleax.net> | 2020-01-16 19:54:27 +0300 |
---|---|---|
committer | Shelley Vohr <shelley.vohr@gmail.com> | 2020-02-17 21:54:19 +0300 |
commit | 0cacc1facf77e91affdf69d6c3249aab9838838f (patch) | |
tree | dbc5d31ff3a91755fc5526c52221b6acb3b19c04 /src/env.cc | |
parent | f8c45b277fbb59857355d35223c3429005bac6cd (diff) |
src: add interrupts to Environments/Workers
Allow doing what V8’s `v8::Isolate::RequestInterrupt()` does for V8.
This also works when there is no JS code currently executing.
PR-URL: https://github.com/nodejs/node/pull/31386
Refs: https://github.com/openjs-foundation/summit/pull/240
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'src/env.cc')
-rw-r--r-- | src/env.cc | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/src/env.cc b/src/env.cc index 35ac40a3d99..f298a7b1a61 100644 --- a/src/env.cc +++ b/src/env.cc @@ -388,6 +388,8 @@ Environment::Environment(IsolateData* isolate_data, } Environment::~Environment() { + if (interrupt_data_ != nullptr) *interrupt_data_ = nullptr; + isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback( BuildEmbedderGraph, this); @@ -654,11 +656,29 @@ void Environment::AtExit(void (*cb)(void* arg), void* arg) { at_exit_functions_.push_front(ExitCallback{cb, arg}); } +void Environment::RunAndClearInterrupts() { + while (native_immediates_interrupts_.size() > 0) { + NativeImmediateQueue queue; + { + Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_); + queue.ConcatMove(std::move(native_immediates_interrupts_)); + } + DebugSealHandleScope seal_handle_scope(isolate()); + + while (std::unique_ptr<NativeImmediateCallback> head = queue.Shift()) + head->Call(this); + } +} + void Environment::RunAndClearNativeImmediates(bool only_refed) { TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment), "RunAndClearNativeImmediates", this); size_t ref_count = 0; + // Handle interrupts first. These functions are not allowed to throw + // exceptions, so we do not need to handle that. + RunAndClearInterrupts(); + // It is safe to check .size() first, because there is a causal relationship // between pushes to the threadsafe and this function being called. // For the common case, it's worth checking the size first before establishing @@ -698,6 +718,27 @@ void Environment::RunAndClearNativeImmediates(bool only_refed) { ToggleImmediateRef(false); } +void Environment::RequestInterruptFromV8() { + if (interrupt_data_ != nullptr) return; // Already scheduled. + + // The Isolate may outlive the Environment, so some logic to handle the + // situation in which the Environment is destroyed before the handler runs + // is required. + interrupt_data_ = new Environment*(this); + + isolate()->RequestInterrupt([](Isolate* isolate, void* data) { + std::unique_ptr<Environment*> env_ptr { static_cast<Environment**>(data) }; + Environment* env = *env_ptr; + if (env == nullptr) { + // The Environment has already been destroyed. That should be okay; any + // callback added before the Environment shuts down would have been + // handled during cleanup. + return; + } + env->interrupt_data_ = nullptr; + env->RunAndClearInterrupts(); + }, interrupt_data_); +} void Environment::ScheduleTimer(int64_t duration_ms) { if (started_cleanup_) return; |