@@ -388,6 +388,8 @@ Environment::Environment(IsolateData* isolate_data,
388
388
}
389
389
390
390
Environment::~Environment () {
391
+ if (interrupt_data_ != nullptr ) *interrupt_data_ = nullptr ;
392
+
391
393
isolate ()->GetHeapProfiler ()->RemoveBuildEmbedderGraphCallback (
392
394
BuildEmbedderGraph, this );
393
395
@@ -654,11 +656,29 @@ void Environment::AtExit(void (*cb)(void* arg), void* arg) {
654
656
at_exit_functions_.push_front (ExitCallback{cb, arg});
655
657
}
656
658
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
+
657
673
void Environment::RunAndClearNativeImmediates (bool only_refed) {
658
674
TraceEventScope trace_scope (TRACING_CATEGORY_NODE1 (environment),
659
675
" RunAndClearNativeImmediates" , this );
660
676
size_t ref_count = 0 ;
661
677
678
+ // Handle interrupts first. These functions are not allowed to throw
679
+ // exceptions, so we do not need to handle that.
680
+ RunAndClearInterrupts ();
681
+
662
682
// It is safe to check .size() first, because there is a causal relationship
663
683
// between pushes to the threadsafe and this function being called.
664
684
// For the common case, it's worth checking the size first before establishing
@@ -698,6 +718,27 @@ void Environment::RunAndClearNativeImmediates(bool only_refed) {
698
718
ToggleImmediateRef (false );
699
719
}
700
720
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
+ }
701
742
702
743
void Environment::ScheduleTimer (int64_t duration_ms) {
703
744
if (started_cleanup_) return ;
0 commit comments