Skip to content

Commit e7466f1

Browse files
committed
Fix race in interp_has_threads.
1 parent 2378c88 commit e7466f1

2 files changed

Lines changed: 15 additions & 6 deletions

File tree

Include/internal/pycore_pystate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ extern int _PyOS_InterruptOccurred(PyThreadState *tstate);
266266
PyMutex_LockFlags(&(runtime)->interpreters.mutex, _Py_LOCK_DONT_DETACH)
267267
#define HEAD_UNLOCK(runtime) \
268268
PyMutex_Unlock(&(runtime)->interpreters.mutex)
269+
#define ASSERT_HEAD_IS_LOCKED(runtime) \
270+
assert(PyMutex_IsLocked(&(runtime)->interpreters.mutex))
269271

270272
#define _Py_FOR_EACH_TSTATE_UNLOCKED(interp, t) \
271273
for (PyThreadState *t = interp->threads.head; t; t = t->next)

Python/pylifecycle.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,30 +2225,37 @@ resolve_final_tstate(_PyRuntimeState *runtime)
22252225
#endif
22262226

22272227
static int
2228-
interp_has_threads(PyInterpreterState *interp)
2228+
interp_has_threads_locked(PyInterpreterState *interp)
22292229
{
22302230
/* This needs to check for non-daemon threads only, otherwise we get stuck
22312231
* in an infinite loop. */
2232-
assert(interp != NULL);
2233-
ASSERT_WORLD_STOPPED(interp);
2232+
ASSERT_HEAD_IS_LOCKED(interp->runtime);
22342233
assert(interp->threads.head != NULL);
22352234
if (interp->threads.head->next == NULL) {
22362235
// No other threads active, easy way out.
22372236
return 0;
22382237
}
22392238

2240-
HEAD_LOCK(interp->runtime);
22412239
_Py_FOR_EACH_TSTATE_UNLOCKED(interp, tstate) {
22422240
if (tstate->_whence == _PyThreadState_WHENCE_THREADING) {
2243-
HEAD_UNLOCK(interp->runtime);
22442241
return 1;
22452242
}
22462243
}
2247-
HEAD_UNLOCK(interp->runtime);
22482244

22492245
return 0;
22502246
}
22512247

2248+
static int
2249+
interp_has_threads(PyInterpreterState *interp)
2250+
{
2251+
assert(interp != NULL);
2252+
ASSERT_WORLD_STOPPED(interp);
2253+
HEAD_LOCK(interp->runtime);
2254+
int res = interp_has_threads_locked(interp);
2255+
HEAD_UNLOCK(interp->runtime);
2256+
return res;
2257+
}
2258+
22522259
static int
22532260
interp_has_pending_calls(PyInterpreterState *interp)
22542261
{

0 commit comments

Comments
 (0)