bpo-20891: Py_Initialize() now creates the GIL (#4700)

The GIL is no longer created "on demand" to fix a race condition when
PyGILState_Ensure() is called in a non-Python thread.
This commit is contained in:
Victor Stinner 2018-01-29 11:57:45 +01:00 committed by GitHub
parent 8997f9cd1a
commit 2914bb32e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 52 deletions

View File

@ -687,15 +687,14 @@ This is so common that a pair of macros exists to simplify it::
The :c:macro:`Py_BEGIN_ALLOW_THREADS` macro opens a new block and declares a The :c:macro:`Py_BEGIN_ALLOW_THREADS` macro opens a new block and declares a
hidden local variable; the :c:macro:`Py_END_ALLOW_THREADS` macro closes the hidden local variable; the :c:macro:`Py_END_ALLOW_THREADS` macro closes the
block. These two macros are still available when Python is compiled without block.
thread support (they simply have an empty expansion).
When thread support is enabled, the block above expands to the following code:: The block above expands to the following code::
PyThreadState *_save; PyThreadState *_save;
_save = PyEval_SaveThread(); _save = PyEval_SaveThread();
...Do some blocking I/O operation... ... Do some blocking I/O operation ...
PyEval_RestoreThread(_save); PyEval_RestoreThread(_save);
.. index:: .. index::
@ -818,36 +817,24 @@ code, or when embedding the Python interpreter:
This is a no-op when called for a second time. This is a no-op when called for a second time.
.. versionchanged:: 3.7
This function is now called by :c:func:`Py_Initialize()`, so you don't
have to call it yourself anymore.
.. versionchanged:: 3.2 .. versionchanged:: 3.2
This function cannot be called before :c:func:`Py_Initialize()` anymore. This function cannot be called before :c:func:`Py_Initialize()` anymore.
.. index:: module: _thread .. index:: module: _thread
.. note::
When only the main thread exists, no GIL operations are needed. This is a
common situation (most Python programs do not use threads), and the lock
operations slow the interpreter down a bit. Therefore, the lock is not
created initially. This situation is equivalent to having acquired the lock:
when there is only a single thread, all object accesses are safe. Therefore,
when this function initializes the global interpreter lock, it also acquires
it. Before the Python :mod:`_thread` module creates a new thread, knowing
that either it has the lock or the lock hasn't been created yet, it calls
:c:func:`PyEval_InitThreads`. When this call returns, it is guaranteed that
the lock has been created and that the calling thread has acquired it.
It is **not** safe to call this function when it is unknown which thread (if
any) currently has the global interpreter lock.
This function is not available when thread support is disabled at compile time.
.. c:function:: int PyEval_ThreadsInitialized() .. c:function:: int PyEval_ThreadsInitialized()
Returns a non-zero value if :c:func:`PyEval_InitThreads` has been called. This Returns a non-zero value if :c:func:`PyEval_InitThreads` has been called. This
function can be called without holding the GIL, and therefore can be used to function can be called without holding the GIL, and therefore can be used to
avoid calls to the locking API when running single-threaded. This function is avoid calls to the locking API when running single-threaded.
not available when thread support is disabled at compile time.
.. versionchanged:: 3.7
The :term:`GIL` is now initialized by :c:func:`Py_Initialize()`.
.. c:function:: PyThreadState* PyEval_SaveThread() .. c:function:: PyThreadState* PyEval_SaveThread()
@ -855,8 +842,7 @@ code, or when embedding the Python interpreter:
Release the global interpreter lock (if it has been created and thread Release the global interpreter lock (if it has been created and thread
support is enabled) and reset the thread state to *NULL*, returning the support is enabled) and reset the thread state to *NULL*, returning the
previous thread state (which is not *NULL*). If the lock has been created, previous thread state (which is not *NULL*). If the lock has been created,
the current thread must have acquired it. (This function is available even the current thread must have acquired it.
when thread support is disabled at compile time.)
.. c:function:: void PyEval_RestoreThread(PyThreadState *tstate) .. c:function:: void PyEval_RestoreThread(PyThreadState *tstate)
@ -864,8 +850,7 @@ code, or when embedding the Python interpreter:
Acquire the global interpreter lock (if it has been created and thread Acquire the global interpreter lock (if it has been created and thread
support is enabled) and set the thread state to *tstate*, which must not be support is enabled) and set the thread state to *tstate*, which must not be
*NULL*. If the lock has been created, the current thread must not have *NULL*. If the lock has been created, the current thread must not have
acquired it, otherwise deadlock ensues. (This function is available even acquired it, otherwise deadlock ensues.
when thread support is disabled at compile time.)
.. c:function:: PyThreadState* PyThreadState_Get() .. c:function:: PyThreadState* PyThreadState_Get()
@ -957,7 +942,7 @@ example usage in the Python source distribution.
This macro expands to ``{ PyThreadState *_save; _save = PyEval_SaveThread();``. This macro expands to ``{ PyThreadState *_save; _save = PyEval_SaveThread();``.
Note that it contains an opening brace; it must be matched with a following Note that it contains an opening brace; it must be matched with a following
:c:macro:`Py_END_ALLOW_THREADS` macro. See above for further discussion of this :c:macro:`Py_END_ALLOW_THREADS` macro. See above for further discussion of this
macro. It is a no-op when thread support is disabled at compile time. macro.
.. c:macro:: Py_END_ALLOW_THREADS .. c:macro:: Py_END_ALLOW_THREADS
@ -965,29 +950,29 @@ example usage in the Python source distribution.
This macro expands to ``PyEval_RestoreThread(_save); }``. Note that it contains This macro expands to ``PyEval_RestoreThread(_save); }``. Note that it contains
a closing brace; it must be matched with an earlier a closing brace; it must be matched with an earlier
:c:macro:`Py_BEGIN_ALLOW_THREADS` macro. See above for further discussion of :c:macro:`Py_BEGIN_ALLOW_THREADS` macro. See above for further discussion of
this macro. It is a no-op when thread support is disabled at compile time. this macro.
.. c:macro:: Py_BLOCK_THREADS .. c:macro:: Py_BLOCK_THREADS
This macro expands to ``PyEval_RestoreThread(_save);``: it is equivalent to This macro expands to ``PyEval_RestoreThread(_save);``: it is equivalent to
:c:macro:`Py_END_ALLOW_THREADS` without the closing brace. It is a no-op when :c:macro:`Py_END_ALLOW_THREADS` without the closing brace.
thread support is disabled at compile time.
.. c:macro:: Py_UNBLOCK_THREADS .. c:macro:: Py_UNBLOCK_THREADS
This macro expands to ``_save = PyEval_SaveThread();``: it is equivalent to This macro expands to ``_save = PyEval_SaveThread();``: it is equivalent to
:c:macro:`Py_BEGIN_ALLOW_THREADS` without the opening brace and variable :c:macro:`Py_BEGIN_ALLOW_THREADS` without the opening brace and variable
declaration. It is a no-op when thread support is disabled at compile time. declaration.
Low-level API Low-level API
------------- -------------
All of the following functions are only available when thread support is enabled All of the following functions must be called after :c:func:`Py_Initialize`.
at compile time, and must be called only when the global interpreter lock has
been created. .. versionchanged:: 3.7
:c:func:`Py_Initialize()` now initializes the :term:`GIL`.
.. c:function:: PyInterpreterState* PyInterpreterState_New() .. c:function:: PyInterpreterState* PyInterpreterState_New()
@ -1068,8 +1053,7 @@ been created.
If this thread already has the lock, deadlock ensues. If this thread already has the lock, deadlock ensues.
:c:func:`PyEval_RestoreThread` is a higher-level function which is always :c:func:`PyEval_RestoreThread` is a higher-level function which is always
available (even when thread support isn't enabled or when threads have available (even when threads have not been initialized).
not been initialized).
.. c:function:: void PyEval_ReleaseThread(PyThreadState *tstate) .. c:function:: void PyEval_ReleaseThread(PyThreadState *tstate)
@ -1081,8 +1065,7 @@ been created.
reported. reported.
:c:func:`PyEval_SaveThread` is a higher-level function which is always :c:func:`PyEval_SaveThread` is a higher-level function which is always
available (even when thread support isn't enabled or when threads have available (even when threads have not been initialized).
not been initialized).
.. c:function:: void PyEval_AcquireLock() .. c:function:: void PyEval_AcquireLock()

View File

@ -0,0 +1,3 @@
Py_Initialize() now creates the GIL. The GIL is no longer created "on demand"
to fix a race condition when PyGILState_Ensure() is called in a non-Python
thread.

View File

@ -254,8 +254,8 @@ PyEval_SaveThread(void)
PyThreadState *tstate = PyThreadState_Swap(NULL); PyThreadState *tstate = PyThreadState_Swap(NULL);
if (tstate == NULL) if (tstate == NULL)
Py_FatalError("PyEval_SaveThread: NULL tstate"); Py_FatalError("PyEval_SaveThread: NULL tstate");
if (gil_created()) assert(gil_created());
drop_gil(tstate); drop_gil(tstate);
return tstate; return tstate;
} }
@ -264,17 +264,18 @@ PyEval_RestoreThread(PyThreadState *tstate)
{ {
if (tstate == NULL) if (tstate == NULL)
Py_FatalError("PyEval_RestoreThread: NULL tstate"); Py_FatalError("PyEval_RestoreThread: NULL tstate");
if (gil_created()) { assert(gil_created());
int err = errno;
take_gil(tstate); int err = errno;
/* _Py_Finalizing is protected by the GIL */ take_gil(tstate);
if (_Py_IsFinalizing() && !_Py_CURRENTLY_FINALIZING(tstate)) { /* _Py_Finalizing is protected by the GIL */
drop_gil(tstate); if (_Py_IsFinalizing() && !_Py_CURRENTLY_FINALIZING(tstate)) {
PyThread_exit_thread(); drop_gil(tstate);
Py_UNREACHABLE(); PyThread_exit_thread();
} Py_UNREACHABLE();
errno = err;
} }
errno = err;
PyThreadState_Swap(tstate); PyThreadState_Swap(tstate);
} }

View File

@ -681,9 +681,13 @@ _Py_InitializeCore(const _PyCoreConfig *core_config)
Instead we destroy the previously created GIL here, which ensures Instead we destroy the previously created GIL here, which ensures
that we can call Py_Initialize / Py_FinalizeEx multiple times. */ that we can call Py_Initialize / Py_FinalizeEx multiple times. */
_PyEval_FiniThreads(); _PyEval_FiniThreads();
/* Auto-thread-state API */ /* Auto-thread-state API */
_PyGILState_Init(interp, tstate); _PyGILState_Init(interp, tstate);
/* Create the GIL */
PyEval_InitThreads();
_Py_ReadyTypes(); _Py_ReadyTypes();
if (!_PyFrame_Init()) if (!_PyFrame_Init())