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