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