Skip to content

Commit b36e5d6

Browse files
authored
bpo-36356: Destroy the GIL at exit (GH-12453)
* Add _PyEval_FiniThreads2(). _PyEval_FiniThreads() now only clears the pending lock, whereas _PyEval_FiniThreads2() destroys the GIL. * pymain_free() now calls _PyEval_FiniThreads2(). * Py_FinalizeEx() now calls _PyEval_FiniThreads().
1 parent 7a5a1cf commit b36e5d6

File tree

5 files changed

+26
-18
lines changed

5 files changed

+26
-18
lines changed

Include/ceval.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,6 @@ PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *);
192192

193193
PyAPI_FUNC(int) PyEval_ThreadsInitialized(void);
194194
PyAPI_FUNC(void) PyEval_InitThreads(void);
195-
#ifndef Py_LIMITED_API
196-
PyAPI_FUNC(void) _PyEval_FiniThreads(void);
197-
#endif /* !Py_LIMITED_API */
198195
PyAPI_FUNC(void) PyEval_AcquireLock(void) Py_DEPRECATED(3.2);
199196
PyAPI_FUNC(void) PyEval_ReleaseLock(void) /* Py_DEPRECATED(3.2) */;
200197
PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate);

Include/internal/pycore_ceval.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ struct _ceval_runtime_state {
5454

5555
PyAPI_FUNC(void) _PyEval_Initialize(struct _ceval_runtime_state *);
5656

57+
PyAPI_FUNC(void) _PyEval_FiniThreads(void);
58+
PyAPI_FUNC(void) _PyEval_FiniThreads2(void);
59+
5760
#ifdef __cplusplus
5861
}
5962
#endif

Modules/main.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* Python interpreter main program */
22

33
#include "Python.h"
4+
#include "pycore_ceval.h" /* _PyEval_FiniThreads2() */
45
#include "pycore_coreconfig.h"
56
#include "pycore_pylifecycle.h"
67
#include "pycore_pymem.h"
@@ -525,15 +526,15 @@ pymain_run_python(int *exitcode)
525526

526527
/* --- pymain_main() ---------------------------------------------- */
527528

529+
/* Free global variables which cannot be freed in Py_Finalize():
530+
configuration options set before Py_Initialize() which should
531+
remain valid after Py_Finalize(), since
532+
Py_Initialize()-Py_Finalize() can be called multiple times. */
528533
static void
529534
pymain_free(void)
530535
{
531536
_PyImport_Fini2();
532-
533-
/* Free global variables which cannot be freed in Py_Finalize():
534-
configuration options set before Py_Initialize() which should
535-
remain valid after Py_Finalize(), since
536-
Py_Initialize()-Py_Finalize() can be called multiple times. */
537+
_PyEval_FiniThreads2();
537538
_PyPathConfig_ClearGlobal();
538539
_Py_ClearStandardStreamEncoding();
539540
_Py_ClearArgcArgv();

Python/ceval.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,20 +188,26 @@ PyEval_InitThreads(void)
188188
}
189189
}
190190

191+
191192
void
192193
_PyEval_FiniThreads(void)
194+
{
195+
if (_PyRuntime.ceval.pending.lock != NULL) {
196+
PyThread_free_lock(_PyRuntime.ceval.pending.lock);
197+
_PyRuntime.ceval.pending.lock = NULL;
198+
}
199+
}
200+
201+
202+
void
203+
_PyEval_FiniThreads2(void)
193204
{
194205
if (!gil_created()) {
195206
return;
196207
}
197208

198209
destroy_gil();
199210
assert(!gil_created());
200-
201-
if (_PyRuntime.ceval.pending.lock != NULL) {
202-
PyThread_free_lock(_PyRuntime.ceval.pending.lock);
203-
_PyRuntime.ceval.pending.lock = NULL;
204-
}
205211
}
206212

207213
static inline void

Python/pylifecycle.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
#include "Python-ast.h"
66
#undef Yield /* undefine macro conflicting with <winbase.h> */
7-
#include "pycore_coreconfig.h"
7+
#include "pycore_ceval.h" /* _PyEval_FiniThreads() */
88
#include "pycore_context.h"
9+
#include "pycore_coreconfig.h"
910
#include "pycore_fileutils.h"
1011
#include "pycore_hamt.h"
1112
#include "pycore_pathconfig.h"
@@ -555,12 +556,11 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
555556
return _Py_INIT_ERR("can't make first thread");
556557
(void) PyThreadState_Swap(tstate);
557558

558-
/* We can't call _PyEval_FiniThreads() in Py_FinalizeEx because
559-
destroying the GIL might fail when it is being referenced from
560-
another running thread (see issue #9901).
559+
/* Destroying the GIL in Py_FinalizeEx might fail when it is being
560+
referenced from another running thread (see bpo-9901).
561561
Instead we destroy the previously created GIL here, which ensures
562562
that we can call Py_Initialize / Py_FinalizeEx multiple times. */
563-
_PyEval_FiniThreads();
563+
_PyEval_FiniThreads2();
564564

565565
/* Auto-thread-state API */
566566
_PyGILState_Init(runtime, interp, tstate);
@@ -1357,6 +1357,7 @@ Py_FinalizeEx(void)
13571357

13581358
call_ll_exitfuncs(runtime);
13591359

1360+
_PyEval_FiniThreads();
13601361
_PyRuntime_Finalize();
13611362
return status;
13621363
}

0 commit comments

Comments
 (0)