@@ -412,7 +412,8 @@ Environment::Environment(IsolateData* isolate_data,
412
412
}
413
413
414
414
Environment::~Environment () {
415
- if (interrupt_data_ != nullptr ) *interrupt_data_ = nullptr ;
415
+ if (Environment** interrupt_data = interrupt_data_.load ())
416
+ *interrupt_data = nullptr ;
416
417
417
418
// FreeEnvironment() should have set this.
418
419
CHECK (is_stopping ());
@@ -737,12 +738,23 @@ void Environment::RunAndClearNativeImmediates(bool only_refed) {
737
738
}
738
739
739
740
void Environment::RequestInterruptFromV8 () {
740
- if (interrupt_data_ != nullptr ) return ; // Already scheduled.
741
-
742
741
// The Isolate may outlive the Environment, so some logic to handle the
743
742
// situation in which the Environment is destroyed before the handler runs
744
743
// is required.
745
- interrupt_data_ = new Environment*(this );
744
+
745
+ // We allocate a new pointer to a pointer to this Environment instance, and
746
+ // try to set it as interrupt_data_. If interrupt_data_ was already set, then
747
+ // callbacks are already scheduled to run and we can delete our own pointer
748
+ // and just return. If it was nullptr previously, the Environment** is stored;
749
+ // ~Environment sets the Environment* contained in it to nullptr, so that
750
+ // the callback can check whether ~Environment has already run and it is thus
751
+ // not safe to access the Environment instance itself.
752
+ Environment** interrupt_data = new Environment*(this );
753
+ Environment** dummy = nullptr ;
754
+ if (!interrupt_data_.compare_exchange_strong (dummy, interrupt_data)) {
755
+ delete interrupt_data;
756
+ return ; // Already scheduled.
757
+ }
746
758
747
759
isolate ()->RequestInterrupt ([](Isolate* isolate, void * data) {
748
760
std::unique_ptr<Environment*> env_ptr { static_cast <Environment**>(data) };
@@ -753,9 +765,9 @@ void Environment::RequestInterruptFromV8() {
753
765
// handled during cleanup.
754
766
return ;
755
767
}
756
- env->interrupt_data_ = nullptr ;
768
+ env->interrupt_data_ . store ( nullptr ) ;
757
769
env->RunAndClearInterrupts ();
758
- }, interrupt_data_ );
770
+ }, interrupt_data );
759
771
}
760
772
761
773
void Environment::ScheduleTimer (int64_t duration_ms) {
0 commit comments