Skip to content

Commit 0130b20

Browse files
committed
Change terms for 'cautions regarding runtime finalization'
1 parent c15f5c4 commit 0130b20

File tree

1 file changed

+32
-25
lines changed

1 file changed

+32
-25
lines changed

Doc/c-api/init.rst

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,13 +1018,23 @@ The block above expands to the following code::
10181018
single: PyEval_RestoreThread (C function)
10191019
single: PyEval_SaveThread (C function)
10201020
1021-
Here is how these functions work: the global interpreter lock is used to protect the pointer to the
1022-
current :term:`thread state`. When releasing the lock and saving the :term:`thread state`,
1023-
the current thread state pointer must be retrieved before the lock is released
1024-
(since another thread could immediately acquire the lock and store its own :term:`thread
1025-
state` in the global variable). Conversely, when acquiring the lock and restoring
1026-
the :term:`thread state`, the lock must be acquired before storing the :term:`thread state``
1027-
pointer.
1021+
Here is how these functions work:
1022+
1023+
The :term:`thread state` holds the :term:`GIL` for the entire interpreter. When detaching
1024+
the :term:`thread state`, the :term:`GIL` is released, allowing other threads to attach
1025+
their own :term:`thread state`, thus getting the :term:`GIL` and can start executing.
1026+
The pointer to the now-detached :term:`thread state`` is stored as a local variable.
1027+
Upon reaching :c:macro:`Py_END_ALLOW_THREADS`, the :term:`thread state` that was
1028+
previously attached is given to :c:func:`PyEval_RestoreThread`. This function will
1029+
block until another thread that the :term:`GIL` can be re-acquired, thus allowing
1030+
the :term:`thread state` to get re-attached and the C API can be called again.
1031+
1032+
For :term:`free-threaded <free-threading>` builds, the :term:`GIL` is normally
1033+
out of the question, but detaching the thread state is still required for blocking I/O
1034+
and long operations. The difference is that threads don't have to wait for the :term:`GIL`
1035+
to be released to attach their thread state, allowing true multi-core parallelism.
1036+
1037+
:c:func:`PyEval_SaveThread`
10281038
10291039
.. note::
10301040
Calling system I/O functions is the most common use case for detaching
@@ -1044,16 +1054,15 @@ When threads are created using the dedicated Python APIs (such as the
10441054
:mod:`threading` module), a thread state is automatically associated to them
10451055
and the code showed above is therefore correct. However, when threads are
10461056
created from C (for example by a third-party library with its own thread
1047-
management), they don't hold the GIL, nor is there a thread state structure
1048-
for them.
1057+
management), they don't hold the :term:`GIL`, because they don't have a
1058+
:term:`thread state`.
10491059
10501060
If you need to call Python code from these threads (often this will be part
10511061
of a callback API provided by the aforementioned third-party library),
10521062
you must first register these threads with the interpreter by
1053-
creating a thread state data structure, then acquiring the GIL, and finally
1054-
storing their thread state pointer, before you can start using the Python/C
1055-
API. When you are done, you should reset the thread state pointer, release
1056-
the GIL, and finally free the thread state data structure.
1063+
creating a :term:`thread state` before you can start using the Python/C
1064+
API. When you are done, you should detach the :term:`thread state`, and
1065+
finally free it.
10571066
10581067
The :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release` functions do
10591068
all of the above automatically. The typical idiom for calling into Python
@@ -1126,21 +1135,19 @@ is marked as *finalizing*: :c:func:`_Py_IsFinalizing` and
11261135
thread* that initiated finalization (typically the main thread) is allowed to
11271136
acquire the :term:`GIL`.
11281137
1129-
If any thread, other than the finalization thread, attempts to acquire the GIL
1130-
during finalization, either explicitly via :c:func:`PyGILState_Ensure`,
1131-
:c:macro:`Py_END_ALLOW_THREADS`, :c:func:`PyEval_AcquireThread`, or
1132-
:c:func:`PyEval_AcquireLock`, or implicitly when the interpreter attempts to
1133-
reacquire it after having yielded it, the thread enters **a permanently blocked
1134-
state** where it remains until the program exits. In most cases this is
1135-
harmless, but this can result in deadlock if a later stage of finalization
1136-
attempts to acquire a lock owned by the blocked thread, or otherwise waits on
1137-
the blocked thread.
1138+
If any thread, other than the finalization thread, attempts to attach a :term:`thread state`
1139+
during finalization, either explicitly via a :term:`thread state` function, or
1140+
implicitly when the interpreter attempts yields the :term:`GIL` by detaching the
1141+
:term:`thread state`, the thread enters **a permanently blocked state** where it
1142+
remains until the program exits. In most cases this is harmless, but this can result
1143+
in deadlock if a later stage of finalization attempts to acquire a lock owned by the
1144+
blocked thread, or otherwise waits on the blocked thread.
11381145
11391146
Gross? Yes. This prevents random crashes and/or unexpectedly skipped C++
11401147
finalizations further up the call stack when such threads were forcibly exited
1141-
here in CPython 3.13 and earlier. The CPython runtime GIL acquiring C APIs
1142-
have never had any error reporting or handling expectations at GIL acquisition
1143-
time that would've allowed for graceful exit from this situation. Changing that
1148+
here in CPython 3.13 and earlier. The CPython runtime :term:`thread state` C APIs
1149+
have never had any error reporting or handling expectations at :term:`thread state`
1150+
attachment time that would've allowed for graceful exit from this situation. Changing that
11441151
would require new stable C APIs and rewriting the majority of C code in the
11451152
CPython ecosystem to use those with error handling.
11461153

0 commit comments

Comments
 (0)