bpo-39877: 4th take_gil() fix for daemon threads (GH-19080) · python/cpython@a36adfa

@@ -196,8 +196,7 @@ tstate_must_exit(PyThreadState *tstate)

196196

tstate->interp->runtime to support calls from Python daemon threads.

197197

After Py_Finalize() has been called, tstate can be a dangling pointer:

198198

point to PyThreadState freed memory. */

199-

_PyRuntimeState *runtime = &_PyRuntime;

200-

PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime);

199+

PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime);

201200

return (finalizing != NULL && finalizing != tstate);

202201

}

203202

@@ -243,20 +242,23 @@ take_gil(PyThreadState *tstate)

243242

}

244243245244

while (_Py_atomic_load_relaxed(&gil->locked)) {

246-

int timed_out = 0;

247-

unsigned long saved_switchnum;

248-249-

saved_switchnum = gil->switch_number;

250-245+

unsigned long saved_switchnum = gil->switch_number;

251246252247

unsigned long interval = (gil->interval >= 1 ? gil->interval : 1);

248+

int timed_out = 0;

253249

COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out);

250+254251

/* If we timed out and no switch occurred in the meantime, it is time

255252

to ask the GIL-holding thread to drop it. */

256253

if (timed_out &&

257254

_Py_atomic_load_relaxed(&gil->locked) &&

258255

gil->switch_number == saved_switchnum)

259256

{

257+

if (tstate_must_exit(tstate)) {

258+

MUTEX_UNLOCK(gil->mutex);

259+

PyThread_exit_thread();

260+

}

261+260262

SET_GIL_DROP_REQUEST(ceval);

261263

}

262264

}

@@ -281,6 +283,19 @@ take_gil(PyThreadState *tstate)

281283

MUTEX_UNLOCK(gil->switch_mutex);

282284

#endif

283285286+

if (tstate_must_exit(tstate)) {

287+

/* bpo-36475: If Py_Finalize() has been called and tstate is not

288+

the thread which called Py_Finalize(), exit immediately the

289+

thread.

290+291+

This code path can be reached by a daemon thread which was waiting

292+

in take_gil() while the main thread called

293+

wait_for_thread_shutdown() from Py_Finalize(). */

294+

MUTEX_UNLOCK(gil->mutex);

295+

drop_gil(ceval, ceval2, tstate);

296+

PyThread_exit_thread();

297+

}

298+284299

if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {

285300

RESET_GIL_DROP_REQUEST(ceval, ceval2);

286301

}

@@ -293,27 +308,13 @@ take_gil(PyThreadState *tstate)

293308

COMPUTE_EVAL_BREAKER(ceval, ceval2);

294309

}

295310296-

int must_exit = tstate_must_exit(tstate);

297-298311

/* Don't access tstate if the thread must exit */

299-

if (!must_exit && tstate->async_exc != NULL) {

312+

if (tstate->async_exc != NULL) {

300313

_PyEval_SignalAsyncExc(tstate);

301314

}

302315303316

MUTEX_UNLOCK(gil->mutex);

304317305-

if (must_exit) {

306-

/* bpo-36475: If Py_Finalize() has been called and tstate is not

307-

the thread which called Py_Finalize(), exit immediately the

308-

thread.

309-310-

This code path can be reached by a daemon thread which was waiting

311-

in take_gil() while the main thread called

312-

wait_for_thread_shutdown() from Py_Finalize(). */

313-

drop_gil(ceval, ceval2, tstate);

314-

PyThread_exit_thread();

315-

}

316-317318

errno = err;

318319

}

319320