@@ -60,6 +60,8 @@ static uv_async_t start_io_thread_async;
60
60
// This is just an additional check to make sure start_io_thread_async
61
61
// is not accidentally re-used or used when uninitialized.
62
62
static std::atomic_bool start_io_thread_async_initialized { false };
63
+ // Protects the Agent* stored in start_io_thread_async.data.
64
+ static Mutex start_io_thread_async_mutex;
63
65
64
66
class StartIoTask : public Task {
65
67
public:
@@ -97,6 +99,8 @@ static void StartIoThreadWakeup(int signo) {
97
99
inline void * StartIoThreadMain (void * unused) {
98
100
for (;;) {
99
101
uv_sem_wait (&start_io_thread_semaphore);
102
+ Mutex::ScopedLock lock (start_io_thread_async_mutex);
103
+
100
104
CHECK (start_io_thread_async_initialized);
101
105
Agent* agent = static_cast <Agent*>(start_io_thread_async.data );
102
106
if (agent != nullptr )
@@ -157,6 +161,7 @@ static int StartDebugSignalHandler() {
157
161
158
162
#ifdef _WIN32
159
163
DWORD WINAPI StartIoThreadProc (void * arg) {
164
+ Mutex::ScopedLock lock (start_io_thread_async_mutex);
160
165
CHECK (start_io_thread_async_initialized);
161
166
Agent* agent = static_cast <Agent*>(start_io_thread_async.data );
162
167
if (agent != nullptr )
@@ -748,14 +753,7 @@ Agent::Agent(Environment* env)
748
753
debug_options_(env->options ()->debug_options()),
749
754
host_port_(env->inspector_host_port ()) {}
750
755
751
- Agent::~Agent () {
752
- if (start_io_thread_async.data == this ) {
753
- CHECK (start_io_thread_async_initialized.exchange (false ));
754
- start_io_thread_async.data = nullptr ;
755
- // This is global, will never get freed
756
- uv_close (reinterpret_cast <uv_handle_t *>(&start_io_thread_async), nullptr );
757
- }
758
- }
756
+ Agent::~Agent () {}
759
757
760
758
bool Agent::Start (const std::string& path,
761
759
const DebugOptions& options,
@@ -768,6 +766,7 @@ bool Agent::Start(const std::string& path,
768
766
769
767
client_ = std::make_shared<NodeInspectorClient>(parent_env_, is_main);
770
768
if (parent_env_->owns_inspector ()) {
769
+ Mutex::ScopedLock lock (start_io_thread_async_mutex);
771
770
CHECK_EQ (start_io_thread_async_initialized.exchange (true ), false );
772
771
CHECK_EQ (0 , uv_async_init (parent_env_->event_loop (),
773
772
&start_io_thread_async,
@@ -776,6 +775,20 @@ bool Agent::Start(const std::string& path,
776
775
start_io_thread_async.data = this ;
777
776
// Ignore failure, SIGUSR1 won't work, but that should not block node start.
778
777
StartDebugSignalHandler ();
778
+
779
+ parent_env_->AddCleanupHook ([](void * data) {
780
+ Environment* env = static_cast <Environment*>(data);
781
+
782
+ {
783
+ Mutex::ScopedLock lock (start_io_thread_async_mutex);
784
+ start_io_thread_async.data = nullptr ;
785
+ }
786
+
787
+ // This is global, will never get freed
788
+ env->CloseHandle (&start_io_thread_async, [](uv_async_t *) {
789
+ CHECK (start_io_thread_async_initialized.exchange (false ));
790
+ });
791
+ }, parent_env_);
779
792
}
780
793
781
794
AtExit (parent_env_, [](void * env) {
0 commit comments