@@ -435,7 +435,8 @@ Environment::Environment(IsolateData* isolate_data,
435
435
}
436
436
437
437
Environment::~Environment () {
438
- if (interrupt_data_ != nullptr ) *interrupt_data_ = nullptr ;
438
+ if (Environment** interrupt_data = interrupt_data_.load ())
439
+ *interrupt_data = nullptr ;
439
440
440
441
// FreeEnvironment() should have set this.
441
442
CHECK (is_stopping ());
@@ -768,12 +769,23 @@ void Environment::RunAndClearNativeImmediates(bool only_refed) {
768
769
}
769
770
770
771
void Environment::RequestInterruptFromV8 () {
771
- if (interrupt_data_ != nullptr ) return ; // Already scheduled.
772
-
773
772
// The Isolate may outlive the Environment, so some logic to handle the
774
773
// situation in which the Environment is destroyed before the handler runs
775
774
// is required.
776
- interrupt_data_ = new Environment*(this );
775
+
776
+ // We allocate a new pointer to a pointer to this Environment instance, and
777
+ // try to set it as interrupt_data_. If interrupt_data_ was already set, then
778
+ // callbacks are already scheduled to run and we can delete our own pointer
779
+ // and just return. If it was nullptr previously, the Environment** is stored;
780
+ // ~Environment sets the Environment* contained in it to nullptr, so that
781
+ // the callback can check whether ~Environment has already run and it is thus
782
+ // not safe to access the Environment instance itself.
783
+ Environment** interrupt_data = new Environment*(this );
784
+ Environment** dummy = nullptr ;
785
+ if (!interrupt_data_.compare_exchange_strong (dummy, interrupt_data)) {
786
+ delete interrupt_data;
787
+ return ; // Already scheduled.
788
+ }
777
789
778
790
isolate ()->RequestInterrupt ([](Isolate* isolate, void * data) {
779
791
std::unique_ptr<Environment*> env_ptr { static_cast <Environment**>(data) };
@@ -784,9 +796,9 @@ void Environment::RequestInterruptFromV8() {
784
796
// handled during cleanup.
785
797
return ;
786
798
}
787
- env->interrupt_data_ = nullptr ;
799
+ env->interrupt_data_ . store ( nullptr ) ;
788
800
env->RunAndClearInterrupts ();
789
- }, interrupt_data_ );
801
+ }, interrupt_data );
790
802
}
791
803
792
804
void Environment::ScheduleTimer (int64_t duration_ms) {
0 commit comments