@@ -33,6 +33,7 @@ struct ThreadState_DestroyNoGIL
3333 MarkGreenletDeadAndQueueCleanup (ThreadState* const state)
3434 {
3535#if GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK
36+ // One rare platform.
3637 return ;
3738#endif
3839 // We are *NOT* holding the GIL. Our thread is in the middle
@@ -70,7 +71,11 @@ struct ThreadState_DestroyNoGIL
7071 static bool
7172 MarkGreenletDeadIfNeeded (ThreadState* const state)
7273 {
73- if (state && state->has_main_greenlet ()) {
74+ if (!state) {
75+ return false ;
76+ }
77+ LockGuard cleanup_lock (*mod_globs->thread_states_to_destroy_lock );
78+ if (state->has_main_greenlet ()) {
7479 // mark the thread as dead ASAP.
7580 // this is racy! If we try to throw or switch to a
7681 // greenlet from this thread from some other thread before
@@ -114,7 +119,7 @@ struct ThreadState_DestroyNoGIL
114119 // from the queue; its next iteration will go ahead and delete the item we just added.
115120 // And the pending call we schedule here will have no work to do.
116121 int result = AddPendingCall (
117- PendingCallback_DestroyQueueWithGIL ,
122+ PendingCallback_DestroyQueue ,
118123 nullptr );
119124 if (result < 0 ) {
120125 // Hmm, what can we do here?
@@ -126,10 +131,11 @@ struct ThreadState_DestroyNoGIL
126131 }
127132
128133 static int
129- PendingCallback_DestroyQueueWithGIL (void * UNUSED (arg))
134+ PendingCallback_DestroyQueue (void * UNUSED (arg))
130135 {
131- // We're holding the GIL here, so no Python code should be able to
132- // run to call ``os.fork()``.
136+ // We're may or may not be holding the GIL here (depending on
137+ // Py_GIL_DISABLED), so calls to ``os.fork()`` may or may not
138+ // be possible.
133139 while (1 ) {
134140 ThreadState* to_destroy;
135141 {
@@ -144,15 +150,15 @@ struct ThreadState_DestroyNoGIL
144150 // Drop the lock while we do the actual deletion.
145151 // This allows other calls to MarkGreenletDeadAndQueueCleanup
146152 // to enter and add to our queue.
147- DestroyOneWithGIL (to_destroy);
153+ DestroyOne (to_destroy);
148154 }
149155 return 0 ;
150156 }
151157
152158 static void
153- DestroyOneWithGIL (const ThreadState* const state)
159+ DestroyOne (const ThreadState* const state)
154160 {
155- // Holding the GIL.
161+ // May or may not be holding the GIL (depending on Py_GIL_DISABLED) .
156162 // Passed a non-shared pointer to the actual thread state.
157163 // state -> main greenlet
158164 assert (state->has_main_greenlet ());
0 commit comments