@@ -388,6 +388,8 @@ Environment::Environment(IsolateData* isolate_data,
388388}
389389
390390Environment::~Environment () {
391+ if (interrupt_data_ != nullptr ) *interrupt_data_ = nullptr ;
392+
391393 isolate ()->GetHeapProfiler ()->RemoveBuildEmbedderGraphCallback (
392394 BuildEmbedderGraph, this );
393395
@@ -654,11 +656,29 @@ void Environment::AtExit(void (*cb)(void* arg), void* arg) {
654656 at_exit_functions_.push_front (ExitCallback{cb, arg});
655657}
656658
659+ void Environment::RunAndClearInterrupts () {
660+ while (native_immediates_interrupts_.size () > 0 ) {
661+ NativeImmediateQueue queue;
662+ {
663+ Mutex::ScopedLock lock (native_immediates_threadsafe_mutex_);
664+ queue.ConcatMove (std::move (native_immediates_interrupts_));
665+ }
666+ DebugSealHandleScope seal_handle_scope (isolate ());
667+
668+ while (std::unique_ptr<NativeImmediateCallback> head = queue.Shift ())
669+ head->Call (this );
670+ }
671+ }
672+
657673void Environment::RunAndClearNativeImmediates (bool only_refed) {
658674 TraceEventScope trace_scope (TRACING_CATEGORY_NODE1 (environment),
659675 " RunAndClearNativeImmediates" , this );
660676 size_t ref_count = 0 ;
661677
678+ // Handle interrupts first. These functions are not allowed to throw
679+ // exceptions, so we do not need to handle that.
680+ RunAndClearInterrupts ();
681+
662682 // It is safe to check .size() first, because there is a causal relationship
663683 // between pushes to the threadsafe and this function being called.
664684 // For the common case, it's worth checking the size first before establishing
@@ -698,6 +718,27 @@ void Environment::RunAndClearNativeImmediates(bool only_refed) {
698718 ToggleImmediateRef (false );
699719}
700720
721+ void Environment::RequestInterruptFromV8 () {
722+ if (interrupt_data_ != nullptr ) return ; // Already scheduled.
723+
724+ // The Isolate may outlive the Environment, so some logic to handle the
725+ // situation in which the Environment is destroyed before the handler runs
726+ // is required.
727+ interrupt_data_ = new Environment*(this );
728+
729+ isolate ()->RequestInterrupt ([](Isolate* isolate, void * data) {
730+ std::unique_ptr<Environment*> env_ptr { static_cast <Environment**>(data) };
731+ Environment* env = *env_ptr;
732+ if (env == nullptr ) {
733+ // The Environment has already been destroyed. That should be okay; any
734+ // callback added before the Environment shuts down would have been
735+ // handled during cleanup.
736+ return ;
737+ }
738+ env->interrupt_data_ = nullptr ;
739+ env->RunAndClearInterrupts ();
740+ }, interrupt_data_);
741+ }
701742
702743void Environment::ScheduleTimer (int64_t duration_ms) {
703744 if (started_cleanup_) return ;
0 commit comments