pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/23ef89db7ae46d160650263cc80479c2ed6693fb

48faa60c69660fa.css" /> bpo-39984: _PyThreadState_DeleteCurrent() takes tstate (GH-19051) · python/cpython@23ef89d · GitHub
Skip to content

Commit 23ef89d

Browse files
authored
bpo-39984: _PyThreadState_DeleteCurrent() takes tstate (GH-19051)
* _PyThreadState_DeleteCurrent() now takes tstate rather than runtime. * Add ensure_tstate_not_null() helper to pystate.c. * Add _PyEval_ReleaseLock() function. * _PyThreadState_DeleteCurrent() now calls _PyEval_ReleaseLock(tstate) and frees PyThreadState memory after this call, not before. * PyGILState_Release(): rename "tcur" variable to "tstate".
1 parent d7fabc1 commit 23ef89d

6 files changed

Lines changed: 47 additions & 32 deletions

File tree

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ extern PyObject *_PyEval_EvalCode(
5757
extern int _PyEval_ThreadsInitialized(_PyRuntimeState *runtime);
5858
extern PyStatus _PyEval_InitThreads(PyThreadState *tstate);
5959

60+
extern void _PyEval_ReleaseLock(PyThreadState *tstate);
61+
6062

6163
/* --- _Py_EnterRecursiveCall() ----------------------------------------- */
6264

Include/internal/pycore_pylifecycle.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate);
104104
PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception,
105105
PyObject *value, PyObject *tb);
106106

107-
PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(struct pyruntimestate *runtime);
107+
PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(PyThreadState *tstate);
108108

109109
#ifdef __cplusplus
110110
}

Lib/test/test_capi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ def test_no_FatalError_infinite_loop(self):
6262
# This used to cause an infinite loop.
6363
self.assertTrue(err.rstrip().startswith(
6464
b'Fatal Python error: '
65-
b'PyThreadState_Get: no current thread'))
65+
b'PyThreadState_Get: '
66+
b'current thread state is NULL (released GIL?)'))
6667

6768
def test_memoryview_from_NULL_pointer(self):
6869
self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer)

Modules/_threadmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ t_bootstrap(void *boot_raw)
10281028
PyMem_DEL(boot_raw);
10291029
tstate->interp->num_threads--;
10301030
PyThreadState_Clear(tstate);
1031-
_PyThreadState_DeleteCurrent(runtime);
1031+
_PyThreadState_DeleteCurrent(tstate);
10321032
PyThread_exit_thread();
10331033
}
10341034

Python/ceval.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ static void
193193
ensure_tstate_not_null(const char *func, PyThreadState *tstate)
194194
{
195195
if (tstate == NULL) {
196-
_Py_FatalErrorFunc(func, "current thread state is NULL");
196+
_Py_FatalErrorFunc(func,
197+
"current thread state is NULL (released GIL?)");
197198
}
198199
}
199200

@@ -313,6 +314,13 @@ PyEval_ReleaseLock(void)
313314
drop_gil(&runtime->ceval, tstate);
314315
}
315316

317+
void
318+
_PyEval_ReleaseLock(PyThreadState *tstate)
319+
{
320+
struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
321+
drop_gil(ceval, tstate);
322+
}
323+
316324
void
317325
PyEval_AcquireThread(PyThreadState *tstate)
318326
{

Python/pystate.c

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ extern "C" {
3737
_Py_atomic_store_relaxed(&(gilstate)->tstate_current, \
3838
(uintptr_t)(value))
3939

40+
static void
41+
ensure_tstate_not_null(const char *func, PyThreadState *tstate)
42+
{
43+
if (tstate == NULL) {
44+
_Py_FatalErrorFunc(func,
45+
"current thread state is NULL (released GIL?)");
46+
}
47+
}
48+
49+
4050
/* Forward declarations */
4151
static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate);
4252
static void _PyThreadState_Delete(PyThreadState *tstate, int check_current);
@@ -400,9 +410,7 @@ PyInterpreterState *
400410
PyInterpreterState_Get(void)
401411
{
402412
PyThreadState *tstate = _PyThreadState_GET();
403-
if (tstate == NULL) {
404-
Py_FatalError("no current thread state");
405-
}
413+
ensure_tstate_not_null(__func__, tstate);
406414
PyInterpreterState *interp = tstate->interp;
407415
if (interp == NULL) {
408416
Py_FatalError("no current interpreter");
@@ -819,9 +827,7 @@ tstate_delete_common(PyThreadState *tstate,
819827
struct _gilstate_runtime_state *gilstate)
820828
{
821829
_PyRuntimeState *runtime = tstate->interp->runtime;
822-
if (tstate == NULL) {
823-
Py_FatalError("NULL tstate");
824-
}
830+
ensure_tstate_not_null(__func__, tstate);
825831
PyInterpreterState *interp = tstate->interp;
826832
if (interp == NULL) {
827833
Py_FatalError("NULL interp");
@@ -835,8 +841,6 @@ tstate_delete_common(PyThreadState *tstate,
835841
tstate->next->prev = tstate->prev;
836842
HEAD_UNLOCK(runtime);
837843

838-
PyMem_RawFree(tstate);
839-
840844
if (gilstate->autoInterpreterState &&
841845
PyThread_tss_get(&gilstate->autoTSSkey) == tstate)
842846
{
@@ -855,6 +859,7 @@ _PyThreadState_Delete(PyThreadState *tstate, int check_current)
855859
}
856860
}
857861
tstate_delete_common(tstate, gilstate);
862+
PyMem_RawFree(tstate);
858863
}
859864

860865

@@ -866,22 +871,22 @@ PyThreadState_Delete(PyThreadState *tstate)
866871

867872

868873
void
869-
_PyThreadState_DeleteCurrent(_PyRuntimeState *runtime)
874+
_PyThreadState_DeleteCurrent(PyThreadState *tstate)
870875
{
871-
struct _gilstate_runtime_state *gilstate = &runtime->gilstate;
872-
PyThreadState *tstate = _PyRuntimeGILState_GetThreadState(gilstate);
873-
if (tstate == NULL) {
874-
Py_FatalError("no current tstate");
875-
}
876+
ensure_tstate_not_null(__func__, tstate);
877+
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
876878
tstate_delete_common(tstate, gilstate);
877879
_PyRuntimeGILState_SetThreadState(gilstate, NULL);
878-
PyEval_ReleaseLock();
880+
_PyEval_ReleaseLock(tstate);
881+
PyMem_RawFree(tstate);
879882
}
880883

881884
void
882885
PyThreadState_DeleteCurrent(void)
883886
{
884-
_PyThreadState_DeleteCurrent(&_PyRuntime);
887+
struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;
888+
PyThreadState *tstate = _PyRuntimeGILState_GetThreadState(gilstate);
889+
_PyThreadState_DeleteCurrent(tstate);
885890
}
886891

887892

@@ -938,9 +943,7 @@ PyThreadState *
938943
PyThreadState_Get(void)
939944
{
940945
PyThreadState *tstate = _PyThreadState_GET();
941-
if (tstate == NULL) {
942-
Py_FatalError("no current thread");
943-
}
946+
ensure_tstate_not_null(__func__, tstate);
944947
return tstate;
945948
}
946949

@@ -1342,8 +1345,8 @@ void
13421345
PyGILState_Release(PyGILState_STATE oldstate)
13431346
{
13441347
_PyRuntimeState *runtime = &_PyRuntime;
1345-
PyThreadState *tcur = PyThread_tss_get(&runtime->gilstate.autoTSSkey);
1346-
if (tcur == NULL) {
1348+
PyThreadState *tstate = PyThread_tss_get(&runtime->gilstate.autoTSSkey);
1349+
if (tstate == NULL) {
13471350
Py_FatalError("auto-releasing thread-state, "
13481351
"but no thread-state for this thread");
13491352
}
@@ -1353,26 +1356,27 @@ PyGILState_Release(PyGILState_STATE oldstate)
13531356
but while this is very new (April 2003), the extra check
13541357
by release-only users can't hurt.
13551358
*/
1356-
if (!PyThreadState_IsCurrent(tcur)) {
1359+
if (!PyThreadState_IsCurrent(tstate)) {
13571360
Py_FatalError("This thread state must be current when releasing");
13581361
}
1359-
assert(PyThreadState_IsCurrent(tcur));
1360-
--tcur->gilstate_counter;
1361-
assert(tcur->gilstate_counter >= 0); /* illegal counter value */
1362+
assert(PyThreadState_IsCurrent(tstate));
1363+
--tstate->gilstate_counter;
1364+
assert(tstate->gilstate_counter >= 0); /* illegal counter value */
13621365

13631366
/* If we're going to destroy this thread-state, we must
13641367
* clear it while the GIL is held, as destructors may run.
13651368
*/
1366-
if (tcur->gilstate_counter == 0) {
1369+
if (tstate->gilstate_counter == 0) {
13671370
/* can't have been locked when we created it */
13681371
assert(oldstate == PyGILState_UNLOCKED);
1369-
PyThreadState_Clear(tcur);
1372+
PyThreadState_Clear(tstate);
13701373
/* Delete the thread-state. Note this releases the GIL too!
13711374
* It's vital that the GIL be held here, to avoid shutdown
13721375
* races; see bugs 225673 and 1061968 (that nasty bug has a
13731376
* habit of coming back).
13741377
*/
1375-
_PyThreadState_DeleteCurrent(runtime);
1378+
assert(_PyRuntimeGILState_GetThreadState(&runtime->gilstate) == tstate);
1379+
_PyThreadState_DeleteCurrent(tstate);
13761380
}
13771381
/* Release the lock if necessary */
13781382
else if (oldstate == PyGILState_UNLOCKED)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy