https://github.com/python/cpython/commit/86d5fa95cf9edf6c6fbc2a72080ac1ee87c4e941
commit: 86d5fa95cf9edf6c6fbc2a72080ac1ee87c4e941
branch: main
author: Peter Bierma <zintensity...@gmail.com>
committer: encukou <encu...@gmail.com>
date: 2025-03-20T13:06:59+01:00
summary:

gh-127989: C API: Refer to "attached thread states" instead of the GIL 
(GH-127990)


Co-authored-by: Victor Stinner <vstin...@python.org>

files:
M Doc/c-api/dict.rst
M Doc/c-api/exceptions.rst
M Doc/c-api/init.rst
M Doc/c-api/init_config.rst
M Doc/c-api/memory.rst
M Doc/c-api/module.rst
M Doc/c-api/perfmaps.rst
M Doc/c-api/reflection.rst
M Doc/c-api/sys.rst
M Doc/c-api/time.rst
M Doc/c-api/typeobj.rst
M Doc/extending/newtypes_tutorial.rst
M Doc/glossary.rst

diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
index ce73fa0cc60ebb..e55c5c80cb83c0 100644
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -127,7 +127,7 @@ Dictionary Objects
       Prefer the :c:func:`PyDict_GetItemWithError` function instead.
 
    .. versionchanged:: 3.10
-      Calling this API without :term:`GIL` held had been allowed for historical
+      Calling this API without an :term:`attached thread state` had been 
allowed for historical
       reason. It is no longer allowed.
 
 
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 19f6baf9b3dc90..c8e1b5c2461738 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -413,7 +413,7 @@ Querying the error indicator
    own a reference to the return value, so you do not need to 
:c:func:`Py_DECREF`
    it.
 
-   The caller must hold the GIL.
+   The caller must have an :term:`attached thread state`.
 
    .. note::
 
@@ -675,7 +675,7 @@ Signal Handling
 
    .. note::
       This function is async-signal-safe.  It can be called without
-      the :term:`GIL` and from a C signal handler.
+      an :term:`attached thread state` and from a C signal handler.
 
 
 .. c:function:: int PyErr_SetInterruptEx(int signum)
@@ -702,7 +702,7 @@ Signal Handling
 
    .. note::
       This function is async-signal-safe.  It can be called without
-      the :term:`GIL` and from a C signal handler.
+      an :term:`attached thread state` and from a C signal handler.
 
    .. versionadded:: 3.10
 
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 9197f704fab344..3597f35e0a2656 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -573,7 +573,7 @@ Initializing and finalizing the interpreter
    This is similar to :c:func:`Py_AtExit`, but takes an explicit interpreter 
and
    data pointer for the callback.
 
-   The :term:`GIL` must be held for *interp*.
+   There must be an :term:`attached thread state` for *interp*.
 
    .. versionadded:: 3.13
 
@@ -946,7 +946,8 @@ Thread State and the Global Interpreter Lock
    single: interpreter lock
    single: lock, interpreter
 
-The Python interpreter is not fully thread-safe.  In order to support
+Unless on a :term:`free-threaded <free threading>` build of :term:`CPython`,
+the Python interpreter is not fully thread-safe.  In order to support
 multi-threaded Python programs, there's a global lock, called the :term:`global
 interpreter lock` or :term:`GIL`, that must be held by the current thread 
before
 it can safely access Python objects. Without the lock, even the simplest
@@ -967,20 +968,30 @@ a file, so that other Python threads can run in the 
meantime.
    single: PyThreadState (C type)
 
 The Python interpreter keeps some thread-specific bookkeeping information
-inside a data structure called :c:type:`PyThreadState`.  There's also one
-global variable pointing to the current :c:type:`PyThreadState`: it can
-be retrieved using :c:func:`PyThreadState_Get`.
-
-Releasing the GIL from extension code
--------------------------------------
-
-Most extension code manipulating the :term:`GIL` has the following simple
+inside a data structure called :c:type:`PyThreadState`, known as a 
:term:`thread state`.
+Each OS thread has a thread-local pointer to a :c:type:`PyThreadState`; a 
thread state
+referenced by this pointer is considered to be :term:`attached <attached 
thread state>`.
+
+A thread can only have one :term:`attached thread state` at a time. An attached
+thread state is typically analogous with holding the :term:`GIL`, except on
+:term:`free-threaded <free threading>` builds.  On builds with the :term:`GIL` 
enabled,
+:term:`attaching <attached thread state>` a thread state will block until the 
:term:`GIL`
+can be acquired. However,  even on builds with the :term:`GIL` disabled, it is 
still required
+to have an attached thread state to call most of the C API.
+
+In general, there will always be an :term:`attached thread state` when using 
Python's C API.
+Only in some specific cases (such as in a :c:macro:`Py_BEGIN_ALLOW_THREADS` 
block) will the
+thread not have an attached thread state. If uncertain, check if 
:c:func:`PyThreadState_GetUnchecked` returns
+``NULL``.
+
+Detaching the thread state from extension code
+----------------------------------------------
+
+Most extension code manipulating the :term:`thread state` has the following 
simple
 structure::
 
    Save the thread state in a local variable.
-   Release the global interpreter lock.
    ... Do some blocking I/O operation ...
-   Reacquire the global interpreter lock.
    Restore the thread state from the local variable.
 
 This is so common that a pair of macros exists to simplify it::
@@ -1009,21 +1020,30 @@ The block above expands to the following code::
    single: PyEval_RestoreThread (C function)
    single: PyEval_SaveThread (C function)
 
-Here is how these functions work: the global interpreter lock is used to 
protect the pointer to the
-current thread state.  When releasing the lock and saving the thread state,
-the current thread state pointer must be retrieved before the lock is released
-(since another thread could immediately acquire the lock and store its own 
thread
-state in the global variable). Conversely, when acquiring the lock and 
restoring
-the thread state, the lock must be acquired before storing the thread state
-pointer.
+Here is how these functions work:
+
+The :term:`attached thread state` holds the :term:`GIL` for the entire 
interpreter. When detaching
+the :term:`attached thread state`, the :term:`GIL` is released, allowing other 
threads to attach
+a thread state to their own thread, thus getting the :term:`GIL` and can start 
executing.
+The pointer to the prior :term:`attached thread state` is stored as a local 
variable.
+Upon reaching :c:macro:`Py_END_ALLOW_THREADS`, the thread state that was
+previously :term:`attached <attached thread state>` is passed to 
:c:func:`PyEval_RestoreThread`.
+This function will block until another releases its :term:`thread state 
<attached thread state>`,
+thus allowing the old :term:`thread state <attached thread state>` to get 
re-attached and the
+C API can be called again.
+
+For :term:`free-threaded <free threading>` builds, the :term:`GIL` is normally
+out of the question, but detaching the :term:`thread state <attached thread 
state>` is still required
+for blocking I/O and long operations. The difference is that threads don't 
have to wait for the :term:`GIL`
+to be released to attach their thread state, allowing true multi-core 
parallelism.
 
 .. note::
-   Calling system I/O functions is the most common use case for releasing
-   the GIL, but it can also be useful before calling long-running computations
-   which don't need access to Python objects, such as compression or
-   cryptographic functions operating over memory buffers.  For example, the
-   standard :mod:`zlib` and :mod:`hashlib` modules release the GIL when
-   compressing or hashing data.
+   Calling system I/O functions is the most common use case for detaching
+   the :term:`thread state <attached thread state>`, but it can also be useful 
before calling
+   long-running computations which don't need access to Python objects, such
+   as compression or cryptographic functions operating over memory buffers.
+   For example, the standard :mod:`zlib` and :mod:`hashlib` modules detach the
+   :term:`thread state <attached thread state>` when compressing or hashing 
data.
 
 
 .. _gilstate:
@@ -1035,16 +1055,15 @@ When threads are created using the dedicated Python 
APIs (such as the
 :mod:`threading` module), a thread state is automatically associated to them
 and the code showed above is therefore correct.  However, when threads are
 created from C (for example by a third-party library with its own thread
-management), they don't hold the GIL, nor is there a thread state structure
-for them.
+management), they don't hold the :term:`GIL`, because they don't have an
+:term:`attached thread state`.
 
 If you need to call Python code from these threads (often this will be part
 of a callback API provided by the aforementioned third-party library),
 you must first register these threads with the interpreter by
-creating a thread state data structure, then acquiring the GIL, and finally
-storing their thread state pointer, before you can start using the Python/C
-API.  When you are done, you should reset the thread state pointer, release
-the GIL, and finally free the thread state data structure.
+creating an :term:`attached thread state` before you can start using the 
Python/C
+API.  When you are done, you should detach the :term:`thread state <attached 
thread state>`, and
+finally free it.
 
 The :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release` functions do
 all of the above automatically.  The typical idiom for calling into Python
@@ -1117,21 +1136,18 @@ is marked as *finalizing*: :c:func:`_Py_IsFinalizing` 
and
 thread* that initiated finalization (typically the main thread) is allowed to
 acquire the :term:`GIL`.
 
-If any thread, other than the finalization thread, attempts to acquire the GIL
-during finalization, either explicitly via :c:func:`PyGILState_Ensure`,
-:c:macro:`Py_END_ALLOW_THREADS`, :c:func:`PyEval_AcquireThread`, or
-:c:func:`PyEval_AcquireLock`, or implicitly when the interpreter attempts to
-reacquire it after having yielded it, the thread enters **a permanently blocked
-state** where it remains until the program exits.  In most cases this is
-harmless, but this can result in deadlock if a later stage of finalization
-attempts to acquire a lock owned by the blocked thread, or otherwise waits on
-the blocked thread.
+If any thread, other than the finalization thread, attempts to attach a 
:term:`thread state`
+during finalization, either explicitly or
+implicitly, the thread enters **a permanently blocked state**
+where it remains until the program exits.  In most cases this is harmless, but 
this can result
+in deadlock if a later stage of finalization attempts to acquire a lock owned 
by the
+blocked thread, or otherwise waits on the blocked thread.
 
 Gross? Yes. This prevents random crashes and/or unexpectedly skipped C++
 finalizations further up the call stack when such threads were forcibly exited
-here in CPython 3.13 and earlier. The CPython runtime GIL acquiring C APIs
-have never had any error reporting or handling expectations at GIL acquisition
-time that would've allowed for graceful exit from this situation. Changing that
+here in CPython 3.13 and earlier. The CPython runtime :term:`thread state` C 
APIs
+have never had any error reporting or handling expectations at :term:`thread 
state`
+attachment time that would've allowed for graceful exit from this situation. 
Changing that
 would require new stable C APIs and rewriting the majority of C code in the
 CPython ecosystem to use those with error handling.
 
@@ -1194,18 +1210,15 @@ code, or when embedding the Python interpreter:
 
 .. c:function:: PyThreadState* PyEval_SaveThread()
 
-   Release the global interpreter lock (if it has been created) and reset the
-   thread state to ``NULL``, returning the previous thread state (which is not
-   ``NULL``).  If the lock has been created, the current thread must have
-   acquired it.
+   Detach the :term:`attached thread state` and return it.
+   The thread will have no :term:`thread state` upon returning.
 
 
 .. c:function:: void PyEval_RestoreThread(PyThreadState *tstate)
 
-   Acquire the global interpreter lock (if it has been created) and set the
-   thread state to *tstate*, which must not be ``NULL``.  If the lock has been
-   created, the current thread must not have acquired it, otherwise deadlock
-   ensues.
+   Set the :term:`attached thread state` to *tstate*.
+   The passed :term:`thread state` **should not** be :term:`attached <attached 
thread state>`,
+   otherwise deadlock ensues. *tstate* will be attached upon returning.
 
    .. note::
       Calling this function from a thread when the runtime is finalizing will
@@ -1219,13 +1232,13 @@ code, or when embedding the Python interpreter:
 
 .. c:function:: PyThreadState* PyThreadState_Get()
 
-   Return the current thread state.  The global interpreter lock must be held.
-   When the current thread state is ``NULL``, this issues a fatal error (so 
that
-   the caller needn't check for ``NULL``).
+   Return the :term:`attached thread state`. If the thread has no attached
+   thread state, (such as when inside of :c:macro:`Py_BEGIN_ALLOW_THREADS`
+   block), then this issues a fatal error (so that the caller needn't check
+   for ``NULL``).
 
    See also :c:func:`PyThreadState_GetUnchecked`.
 
-
 .. c:function:: PyThreadState* PyThreadState_GetUnchecked()
 
    Similar to :c:func:`PyThreadState_Get`, but don't kill the process with a
@@ -1239,9 +1252,14 @@ code, or when embedding the Python interpreter:
 
 .. c:function:: PyThreadState* PyThreadState_Swap(PyThreadState *tstate)
 
-   Swap the current thread state with the thread state given by the argument
-   *tstate*, which may be ``NULL``.  The global interpreter lock must be held
-   and is not released.
+   Set the :term:`attached thread state` to *tstate*, and return the
+   :term:`thread state` that was attached prior to calling.
+
+   This function is safe to call without an :term:`attached thread state`; it
+   will simply return ``NULL`` indicating that there was no prior thread state.
+
+   .. seealso:
+      :c:func:`PyEval_ReleaseThread`
 
 
 The following functions use thread-local storage, and are not compatible
@@ -1250,7 +1268,7 @@ with sub-interpreters:
 .. c:function:: PyGILState_STATE PyGILState_Ensure()
 
    Ensure that the current thread is ready to call the Python C API regardless
-   of the current state of Python, or of the global interpreter lock. This may
+   of the current state of Python, or of the :term:`attached thread state`. 
This may
    be called as many times as desired by a thread as long as each call is
    matched with a call to :c:func:`PyGILState_Release`. In general, other
    thread-related APIs may be used between :c:func:`PyGILState_Ensure` and
@@ -1259,15 +1277,15 @@ with sub-interpreters:
    :c:macro:`Py_BEGIN_ALLOW_THREADS` and :c:macro:`Py_END_ALLOW_THREADS` 
macros is
    acceptable.
 
-   The return value is an opaque "handle" to the thread state when
+   The return value is an opaque "handle" to the :term:`attached thread state` 
when
    :c:func:`PyGILState_Ensure` was called, and must be passed to
    :c:func:`PyGILState_Release` to ensure Python is left in the same state. 
Even
    though recursive calls are allowed, these handles *cannot* be shared - each
    unique call to :c:func:`PyGILState_Ensure` must save the handle for its call
    to :c:func:`PyGILState_Release`.
 
-   When the function returns, the current thread will hold the GIL and be able
-   to call arbitrary Python code.  Failure is a fatal error.
+   When the function returns, there will be an :term:`attached thread state`
+   and the thread will be able to call arbitrary Python code.  Failure is a 
fatal error.
 
    .. note::
       Calling this function from a thread when the runtime is finalizing will
@@ -1292,21 +1310,23 @@ with sub-interpreters:
 
 .. c:function:: PyThreadState* PyGILState_GetThisThreadState()
 
-   Get the current thread state for this thread.  May return ``NULL`` if no
+   Get the :term:`attached thread state` for this thread.  May return ``NULL`` 
if no
    GILState API has been used on the current thread.  Note that the main thread
    always has such a thread-state, even if no auto-thread-state call has been
    made on the main thread.  This is mainly a helper/diagnostic function.
 
+   .. seealso: :c:func:`PyThreadState_Get``
+
 
 .. c:function:: int PyGILState_Check()
 
-   Return ``1`` if the current thread is holding the GIL and ``0`` otherwise.
+   Return ``1`` if the current thread is holding the :term:`GIL` and ``0`` 
otherwise.
    This function can be called from any thread at any time.
    Only if it has had its Python thread state initialized and currently is
-   holding the GIL will it return ``1``.
+   holding the :term:`GIL` will it return ``1``.
    This is mainly a helper/diagnostic function.  It can be useful
    for example in callback contexts or memory allocation functions when
-   knowing that the GIL is locked can allow the caller to perform sensitive
+   knowing that the :term:`GIL` is locked can allow the caller to perform 
sensitive
    actions or otherwise behave differently.
 
    .. versionadded:: 3.4
@@ -1351,13 +1371,14 @@ Low-level API
 All of the following functions must be called after :c:func:`Py_Initialize`.
 
 .. versionchanged:: 3.7
-   :c:func:`Py_Initialize()` now initializes the :term:`GIL`.
+   :c:func:`Py_Initialize()` now initializes the :term:`GIL`
+   and sets an :term:`attached thread state`.
 
 
 .. c:function:: PyInterpreterState* PyInterpreterState_New()
 
-   Create a new interpreter state object.  The global interpreter lock need not
-   be held, but may be held if it is necessary to serialize calls to this
+   Create a new interpreter state object.  An :term:`attached thread state` is 
not needed,
+   but may optionally exist if it is necessary to serialize calls to this
    function.
 
    .. audit-event:: cpython.PyInterpreterState_New "" c.PyInterpreterState_New
@@ -1365,30 +1386,28 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
 .. c:function:: void PyInterpreterState_Clear(PyInterpreterState *interp)
 
-   Reset all information in an interpreter state object.  The global 
interpreter
-   lock must be held.
+   Reset all information in an interpreter state object.  There must be
+   an :term:`attached thread state` for the the interpreter.
 
    .. audit-event:: cpython.PyInterpreterState_Clear "" 
c.PyInterpreterState_Clear
 
 
 .. c:function:: void PyInterpreterState_Delete(PyInterpreterState *interp)
 
-   Destroy an interpreter state object.  The global interpreter lock need not 
be
-   held.  The interpreter state must have been reset with a previous call to
-   :c:func:`PyInterpreterState_Clear`.
+   Destroy an interpreter state object.  There **should not** be an
+   :term:`attached thread state` for the target interpreter. The interpreter
+   state must have been reset with a previous call to 
:c:func:`PyInterpreterState_Clear`.
 
 
 .. c:function:: PyThreadState* PyThreadState_New(PyInterpreterState *interp)
 
    Create a new thread state object belonging to the given interpreter object.
-   The global interpreter lock need not be held, but may be held if it is
-   necessary to serialize calls to this function.
-
+   An :term:`attached thread state` is not needed.
 
 .. c:function:: void PyThreadState_Clear(PyThreadState *tstate)
 
-   Reset all information in a thread state object.  The global interpreter lock
-   must be held.
+   Reset all information in a :term:`thread state` object.  *tstate*
+   must be :term:`attached <attached thread state>`
 
    .. versionchanged:: 3.9
       This function now calls the :c:member:`PyThreadState.on_delete` callback.
@@ -1400,18 +1419,19 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
 .. c:function:: void PyThreadState_Delete(PyThreadState *tstate)
 
-   Destroy a thread state object.  The global interpreter lock need not be 
held.
-   The thread state must have been reset with a previous call to
+   Destroy a :term:`thread state` object.  *tstate* should not
+   be :term:`attached <attached thread state>` to any thread.
+   *tstate* must have been reset with a previous call to
    :c:func:`PyThreadState_Clear`.
 
 
 .. c:function:: void PyThreadState_DeleteCurrent(void)
 
-   Destroy the current thread state and release the global interpreter lock.
-   Like :c:func:`PyThreadState_Delete`, the global interpreter lock must
-   be held. The thread state must have been reset with a previous call
-   to :c:func:`PyThreadState_Clear`.
+   Detach the :term:`attached thread state` (which must have been reset
+   with a previous call to :c:func:`PyThreadState_Clear`) and then destroy it.
 
+   No :term:`thread state` will be :term:`attached <attached thread state>` 
upon
+   returning.
 
 .. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
 
@@ -1422,16 +1442,16 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
    See also :c:func:`PyEval_GetFrame`.
 
-   *tstate* must not be ``NULL``.
+   *tstate* must not be ``NULL``, and must be :term:`attached <attached thread 
state>`.
 
    .. versionadded:: 3.9
 
 
 .. c:function:: uint64_t PyThreadState_GetID(PyThreadState *tstate)
 
-   Get the unique thread state identifier of the Python thread state *tstate*.
+   Get the unique :term:`thread state` identifier of the Python thread state 
*tstate*.
 
-   *tstate* must not be ``NULL``.
+   *tstate* must not be ``NULL``, and must be :term:`attached <attached thread 
state>`.
 
    .. versionadded:: 3.9
 
@@ -1440,7 +1460,7 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
    Get the interpreter of the Python thread state *tstate*.
 
-   *tstate* must not be ``NULL``.
+   *tstate* must not be ``NULL``, and must be :term:`attached <attached thread 
state>`.
 
    .. versionadded:: 3.9
 
@@ -1469,10 +1489,8 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
    Get the current interpreter.
 
-   Issue a fatal error if there no current Python thread state or no current
-   interpreter. It cannot return NULL.
-
-   The caller must hold the GIL.
+   Issue a fatal error if there no :term:`attached thread state`.
+   It cannot return NULL.
 
    .. versionadded:: 3.9
 
@@ -1482,7 +1500,7 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
    Return the interpreter's unique ID.  If there was any error in doing
    so then ``-1`` is returned and an error is set.
 
-   The caller must hold the GIL.
+   The caller must have an :term:`attached thread state`.
 
    .. versionadded:: 3.7
 
@@ -1504,7 +1522,7 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
    Return a :term:`strong reference` to the ``__main__`` :ref:`module object 
<moduleobjects>`
    for the given interpreter.
 
-   The caller must hold the GIL.
+   The caller must have an :term:`attached thread state`.
 
    .. versionadded:: 3.13
 
@@ -1543,9 +1561,10 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
    Return a dictionary in which extensions can store thread-specific state
    information.  Each extension should use a unique key to use to store state 
in
-   the dictionary.  It is okay to call this function when no current thread 
state
-   is available. If this function returns ``NULL``, no exception has been 
raised and
-   the caller should assume no current thread state is available.
+   the dictionary.  It is okay to call this function when no :term:`thread 
state`
+   is :term:`attached <attached thread state>`. If this function returns
+   ``NULL``, no exception has been raised and the caller should assume no
+   thread state is attached.
 
 
 .. c:function:: int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
@@ -1553,7 +1572,7 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
    Asynchronously raise an exception in a thread. The *id* argument is the 
thread
    id of the target thread; *exc* is the exception object to be raised. This
    function does not steal any references to *exc*. To prevent naive misuse, 
you
-   must write your own C extension to call this.  Must be called with the GIL 
held.
+   must write your own C extension to call this.  Must be called with an 
:term:`attached thread state`.
    Returns the number of thread states modified; this is normally one, but 
will be
    zero if the thread id isn't found.  If *exc* is ``NULL``, the pending
    exception (if any) for the thread is cleared. This raises no exceptions.
@@ -1564,9 +1583,10 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
 .. c:function:: void PyEval_AcquireThread(PyThreadState *tstate)
 
-   Acquire the global interpreter lock and set the current thread state to
-   *tstate*, which must not be ``NULL``.  The lock must have been created 
earlier.
-   If this thread already has the lock, deadlock ensues.
+   :term:`Attach <attached thread state>` *tstate* to the current thread,
+   which must not be ``NULL`` or already :term:`attached <attached thread 
state>`.
+
+   The calling thread must not already have an :term:`attached thread state`.
 
    .. note::
       Calling this function from a thread when the runtime is finalizing will
@@ -1589,10 +1609,9 @@ All of the following functions must be called after 
:c:func:`Py_Initialize`.
 
 .. c:function:: void PyEval_ReleaseThread(PyThreadState *tstate)
 
-   Reset the current thread state to ``NULL`` and release the global 
interpreter
-   lock.  The lock must have been created earlier and must be held by the 
current
-   thread.  The *tstate* argument, which must not be ``NULL``, is only used to 
check
-   that it represents the current thread state --- if it isn't, a fatal error 
is
+   Detach the :term:`attached thread state`.
+   The *tstate* argument, which must not be ``NULL``, is only used to check
+   that it represents the :term:`attached thread state` --- if it isn't, a 
fatal error is
    reported.
 
    :c:func:`PyEval_SaveThread` is a higher-level function which is always
@@ -1732,23 +1751,23 @@ function. You can create and destroy them using the 
following functions:
    The given *config* controls the options with which the interpreter
    is initialized.
 
-   Upon success, *tstate_p* will be set to the first thread state
-   created in the new
-   sub-interpreter.  This thread state is made in the current thread state.
+   Upon success, *tstate_p* will be set to the first :term:`thread state`
+   created in the new sub-interpreter.  This thread state is
+   :term:`attached <attached thread state>`.
    Note that no actual thread is created; see the discussion of thread states
    below.  If creation of the new interpreter is unsuccessful,
    *tstate_p* is set to ``NULL``;
    no exception is set since the exception state is stored in the
-   current thread state and there may not be a current thread state.
+   :term:`attached thread state`, which might not exist.
 
-   Like all other Python/C API functions, the global interpreter lock
-   must be held before calling this function and is still held when it
-   returns.  Likewise a current thread state must be set on entry.  On
-   success, the returned thread state will be set as current.  If the
-   sub-interpreter is created with its own GIL then the GIL of the
-   calling interpreter will be released.  When the function returns,
-   the new interpreter's GIL will be held by the current thread and
-   the previously interpreter's GIL will remain released here.
+   Like all other Python/C API functions, an :term:`attached thread state`
+   must be present before calling this function, but it might be detached upon
+   returning. On success, the returned thread state will be :term:`attached 
<attached thread state>`.
+   If the sub-interpreter is created with its own :term:`GIL` then the
+   :term:`attached thread state` of the calling interpreter will be detached.
+   When the function returns, the new interpreter's :term:`thread state`
+   will be :term:`attached <attached thread state>` to the current thread and
+   the previous interpreter's :term:`attached thread state` will remain 
detached.
 
    .. versionadded:: 3.12
 
@@ -1830,13 +1849,10 @@ function. You can create and destroy them using the 
following functions:
 
    .. index:: single: Py_FinalizeEx (C function)
 
-   Destroy the (sub-)interpreter represented by the given thread state.
-   The given thread state must be the current thread state.  See the
-   discussion of thread states below.  When the call returns,
-   the current thread state is ``NULL``.  All thread states associated
-   with this interpreter are destroyed.  The global interpreter lock
-   used by the target interpreter must be held before calling this
-   function.  No GIL is held when it returns.
+   Destroy the (sub-)interpreter represented by the given :term:`thread state`.
+   The given thread state must be :term:`attached <attached thread state>`.
+   When the call returns, there will be no :term:`attached thread state`.
+   All thread states associated with this interpreter are destroyed.
 
    :c:func:`Py_FinalizeEx` will destroy all sub-interpreters that
    haven't been explicitly destroyed at that point.
@@ -1930,20 +1946,17 @@ pointer and a void pointer argument.
    both these conditions met:
 
    * on a :term:`bytecode` boundary;
-   * with the main thread holding the :term:`global interpreter lock`
+   * with the main thread holding an :term:`attached thread state`
      (*func* can therefore use the full C API).
 
    *func* must return ``0`` on success, or ``-1`` on failure with an exception
    set.  *func* won't be interrupted to perform another asynchronous
    notification recursively, but it can still be interrupted to switch
-   threads if the global interpreter lock is released.
-
-   This function doesn't need a current thread state to run, and it doesn't
-   need the global interpreter lock.
+   threads if the :term:`thread state <attached thread state>` is detached.
 
-   To call this function in a subinterpreter, the caller must hold the GIL.
-   Otherwise, the function *func* can be scheduled to be called from the wrong
-   interpreter.
+   This function doesn't need an :term:`attached thread state`. However, to 
call this
+   function in a subinterpreter, the caller must have an :term:`attached 
thread state`.
+   Otherwise, the function *func* can be scheduled to be called from the wrong 
interpreter.
 
    .. warning::
       This is a low-level function, only useful for very special cases.
@@ -2084,14 +2097,14 @@ Python-level trace functions in previous versions.
 
    See also the :func:`sys.setprofile` function.
 
-   The caller must hold the :term:`GIL`.
+   The caller must have an :term:`attached thread state`.
 
 .. c:function:: void PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject 
*obj)
 
    Like :c:func:`PyEval_SetProfile` but sets the profile function in all 
running threads
    belonging to the current interpreter instead of the setting it only on the 
current thread.
 
-   The caller must hold the :term:`GIL`.
+   The caller must have an :term:`attached thread state`.
 
    As :c:func:`PyEval_SetProfile`, this function ignores any exceptions raised 
while
    setting the profile functions in all threads.
@@ -2110,14 +2123,14 @@ Python-level trace functions in previous versions.
 
    See also the :func:`sys.settrace` function.
 
-   The caller must hold the :term:`GIL`.
+   The caller must have an :term:`attached thread state`.
 
 .. c:function:: void PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject 
*obj)
 
    Like :c:func:`PyEval_SetTrace` but sets the tracing function in all running 
threads
    belonging to the current interpreter instead of the setting it only on the 
current thread.
 
-   The caller must hold the :term:`GIL`.
+   The caller must have an :term:`attached thread state`.
 
    As :c:func:`PyEval_SetTrace`, this function ignores any exceptions raised 
while
    setting the trace functions in all threads.
@@ -2159,10 +2172,10 @@ Reference tracing
 
    Not that tracer functions **must not** create Python objects inside or
    otherwise the call will be re-entrant. The tracer also **must not** clear
-   any existing exception or set an exception.  The GIL will be held every time
-   the tracer function is called.
+   any existing exception or set an exception.  A :term:`thread state` will be 
active
+   every time the tracer function is called.
 
-   The GIL must be held when calling this function.
+   There must be an :term:`attached thread state` when calling this function.
 
 .. versionadded:: 3.13
 
@@ -2173,7 +2186,7 @@ Reference tracing
    If no tracer was registered this function will return NULL and will set the
    **data** pointer to NULL.
 
-   The GIL must be held when calling this function.
+   There must be an :term:`attached thread state` when calling this function.
 
 .. versionadded:: 3.13
 
@@ -2230,8 +2243,8 @@ CPython C level APIs are similar to those offered by 
pthreads and Windows:
 use a thread key and functions to associate a :c:expr:`void*` value per
 thread.
 
-The GIL does *not* need to be held when calling these functions; they supply
-their own locking.
+A :term:`thread state` does *not* need to be :term:`attached <attached thread 
state>`
+when calling these functions; they suppl their own locking.
 
 Note that :file:`Python.h` does not include the declaration of the TLS APIs,
 you need to include :file:`pythread.h` to use thread-local storage.
@@ -2400,7 +2413,7 @@ The C-API provides a basic mutual exclusion lock.
 
    Lock mutex *m*.  If another thread has already locked it, the calling
    thread will block until the mutex is unlocked.  While blocked, the thread
-   will temporarily release the :term:`GIL` if it is held.
+   will temporarily detach the :term:`thread state <attached thread state>` if 
one exists.
 
    .. versionadded:: 3.13
 
diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index be9f5e7649ba78..74f34f81d4655f 100644
--- a/Doc/c-api/init_config.rst
+++ b/Doc/c-api/init_config.rst
@@ -578,8 +578,8 @@ Some options are read from the :mod:`sys` attributes. For 
example, the option
    * ``list[str]``
    * ``dict[str, str]``
 
-   The caller must hold the GIL. The function cannot be called before
-   Python initialization nor after Python finalization.
+   The caller must have an :term:`attached thread state`. The function cannot
+   be called before Python initialization nor after Python finalization.
 
    .. versionadded:: 3.14
 
@@ -601,8 +601,8 @@ Some options are read from the :mod:`sys` attributes. For 
example, the option
    * Return a new reference on success.
    * Set an exception and return ``NULL`` on error.
 
-   The caller must hold the GIL. The function cannot be called before
-   Python initialization nor after Python finalization.
+   The caller must have an :term:`attached thread state`. The function cannot
+   be called before Python initialization nor after Python finalization.
 
    .. versionadded:: 3.14
 
@@ -616,8 +616,8 @@ Some options are read from the :mod:`sys` attributes. For 
example, the option
    * Raise a :exc:`ValueError` if the option is read-only (cannot be set).
    * Raise a :exc:`TypeError` if *value* has not the proper type.
 
-   The caller must hold the GIL. The function cannot be called before
-   Python initialization nor after Python finalization.
+   The caller must have an :term:`attached thread state`. The function cannot
+   be called before Python initialization nor after Python finalization.
 
    .. versionadded:: 3.14
 
diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst
index aa2ef499bddaf3..64ae35daa703b8 100644
--- a/Doc/c-api/memory.rst
+++ b/Doc/c-api/memory.rst
@@ -110,12 +110,12 @@ The three allocation domains are:
 
 * Raw domain: intended for allocating memory for general-purpose memory
   buffers where the allocation *must* go to the system allocator or where the
-  allocator can operate without the :term:`GIL`. The memory is requested 
directly
-  from the system. See :ref:`Raw Memory Interface <raw-memoryinterface>`.
+  allocator can operate without an :term:`attached thread state`. The memory
+  is requested directly from the system. See :ref:`Raw Memory Interface 
<raw-memoryinterface>`.
 
 * "Mem" domain: intended for allocating memory for Python buffers and
   general-purpose memory buffers where the allocation must be performed with
-  the :term:`GIL` held. The memory is taken from the Python private heap.
+  an :term:`attached thread state`. The memory is taken from the Python 
private heap.
   See :ref:`Memory Interface <memoryinterface>`.
 
 * Object domain: intended for allocating memory for Python objects. The
@@ -139,8 +139,8 @@ Raw Memory Interface
 ====================
 
 The following function sets are wrappers to the system allocator. These
-functions are thread-safe, the :term:`GIL <global interpreter lock>` does not
-need to be held.
+functions are thread-safe, so a :term:`thread state` does not
+need to be :term:`attached <attached thread state>`.
 
 The :ref:`default raw memory allocator <default-memory-allocators>` uses
 the following functions: :c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc`
@@ -213,8 +213,7 @@ The :ref:`default memory allocator 
<default-memory-allocators>` uses the
 
 .. warning::
 
-   The :term:`GIL <global interpreter lock>` must be held when using these
-   functions.
+   There must be an :term:`attached thread state` when using these functions.
 
 .. versionchanged:: 3.6
 
@@ -327,8 +326,7 @@ The :ref:`default object allocator 
<default-memory-allocators>` uses the
 
 .. warning::
 
-   The :term:`GIL <global interpreter lock>` must be held when using these
-   functions.
+   There must be an :term:`attached thread state` when using these functions.
 
 .. c:function:: void* PyObject_Malloc(size_t n)
 
@@ -485,12 +483,12 @@ Customize Memory Allocators
    zero bytes.
 
    For the :c:macro:`PYMEM_DOMAIN_RAW` domain, the allocator must be
-   thread-safe: the :term:`GIL <global interpreter lock>` is not held when the
-   allocator is called.
+   thread-safe: a :term:`thread state` is not :term:`attached <attached thread 
state>`
+   when the allocator is called.
 
    For the remaining domains, the allocator must also be thread-safe:
    the allocator may be called in different interpreters that do not
-   share a ``GIL``.
+   share a :term:`GIL`.
 
    If the new allocator is not a hook (does not call the previous allocator),
    the :c:func:`PyMem_SetupDebugHooks` function must be called to reinstall the
@@ -507,8 +505,8 @@ Customize Memory Allocators
          :c:func:`Py_InitializeFromConfig` to install a custom memory
          allocator. There are no restrictions over the installed allocator
          other than the ones imposed by the domain (for instance, the Raw
-         Domain allows the allocator to be called without the GIL held). See
-         :ref:`the section on allocator domains <allocator-domains>` for more
+         Domain allows the allocator to be called without an :term:`attached 
thread state`).
+         See :ref:`the section on allocator domains <allocator-domains>` for 
more
          information.
 
        * If called after Python has finish initializing (after
@@ -555,7 +553,7 @@ Runtime checks:
   called on a memory block allocated by :c:func:`PyMem_Malloc`.
 - Detect write before the start of the buffer (buffer underflow).
 - Detect write after the end of the buffer (buffer overflow).
-- Check that the :term:`GIL <global interpreter lock>` is held when
+- Check that there is an :term:`attached thread state` when
   allocator functions of :c:macro:`PYMEM_DOMAIN_OBJ` (ex:
   :c:func:`PyObject_Malloc`) and :c:macro:`PYMEM_DOMAIN_MEM` (ex:
   :c:func:`PyMem_Malloc`) domains are called.
@@ -620,8 +618,8 @@ PYMEM_CLEANBYTE (meaning uninitialized memory is getting 
used).
    The :c:func:`PyMem_SetupDebugHooks` function now also works on Python
    compiled in release mode.  On error, the debug hooks now use
    :mod:`tracemalloc` to get the traceback where a memory block was allocated.
-   The debug hooks now also check if the GIL is held when functions of
-   :c:macro:`PYMEM_DOMAIN_OBJ` and :c:macro:`PYMEM_DOMAIN_MEM` domains are
+   The debug hooks now also check if there is an :term:`attached thread state` 
when
+   functions of :c:macro:`PYMEM_DOMAIN_OBJ` and :c:macro:`PYMEM_DOMAIN_MEM` 
domains are
    called.
 
 .. versionchanged:: 3.8
diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
index 01a8e44828b191..f7f4d37d4c721f 100644
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -709,7 +709,7 @@ since multiple such modules can be created from a single 
definition.
    mechanisms (either by calling it directly, or by referring to its
    implementation for details of the required state updates).
 
-   The caller must hold the GIL.
+   The caller must have an :term:`attached thread state`.
 
    Return ``-1`` with an exception set on error, ``0`` on success.
 
@@ -720,6 +720,6 @@ since multiple such modules can be created from a single 
definition.
    Removes the module object created from *def* from the interpreter state.
    Return ``-1`` with an exception set on error, ``0`` on success.
 
-   The caller must hold the GIL.
+   The caller must have an :term:`attached thread state`.
 
    .. versionadded:: 3.3
diff --git a/Doc/c-api/perfmaps.rst b/Doc/c-api/perfmaps.rst
index 3d44d2eb6bf41d..77b5e3c0876bbb 100644
--- a/Doc/c-api/perfmaps.rst
+++ b/Doc/c-api/perfmaps.rst
@@ -16,7 +16,7 @@ 
kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt>`_
 In Python, these helper APIs can be used by libraries and features that rely
 on generating machine code on the fly.
 
-Note that holding the Global Interpreter Lock (GIL) is not required for these 
APIs.
+Note that holding an :term:`attached thread state` is not required for these 
APIs.
 
 .. c:function:: int PyUnstable_PerfMapState_Init(void)
 
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 038e6977104560..54fd5a064aa2ac 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -55,7 +55,7 @@ Reflection
 
 .. c:function:: PyFrameObject* PyEval_GetFrame(void)
 
-   Return the current thread state's frame, which is ``NULL`` if no frame is
+   Return the :term:`attached thread state`'s frame, which is ``NULL`` if no 
frame is
    currently executing.
 
    See also :c:func:`PyThreadState_GetFrame`.
diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst
index 4ab5df4ccccdbb..b3c89800e386ff 100644
--- a/Doc/c-api/sys.rst
+++ b/Doc/c-api/sys.rst
@@ -232,7 +232,7 @@ Operating System Utilities
 
    The file descriptor is created non-inheritable (:pep:`446`).
 
-   The caller must hold the GIL.
+   The caller must have an :term:`attached thread state`.
 
    .. versionadded:: 3.14
 
@@ -378,8 +378,8 @@ accessible to C code.  They all work with the current 
interpreter thread's
    silently abort the operation by raising an error subclassed from
    :class:`Exception` (other errors will not be silenced).
 
-   The hook function is always called with the GIL held by the Python
-   interpreter that raised the event.
+   The hook function is always called with an :term:`attached thread state` by
+   the Python interpreter that raised the event.
 
    See :pep:`578` for a detailed description of auditing.  Functions in the
    runtime and standard library that raise events are listed in the
diff --git a/Doc/c-api/time.rst b/Doc/c-api/time.rst
index 7032cc48aa6913..31d6adbc225439 100644
--- a/Doc/c-api/time.rst
+++ b/Doc/c-api/time.rst
@@ -56,7 +56,7 @@ range.
 system time.)
 
 As any other C API (unless otherwise specified), the functions must be called
-with the :term:`GIL` held.
+with an :term:`attached thread state`.
 
 .. c:function:: int PyTime_Monotonic(PyTime_t *result)
 
@@ -78,29 +78,29 @@ Raw Clock Functions
 -------------------
 
 Similar to clock functions, but don't set an exception on error and don't
-require the caller to hold the GIL.
+require the caller to have an :term:`attached thread state`.
 
 On success, the functions return ``0``.
 
 On failure, they set ``*result`` to ``0`` and return ``-1``, *without* setting
-an exception. To get the cause of the error, acquire the GIL and call the
-regular (non-``Raw``) function. Note that the regular function may succeed 
after
+an exception. To get the cause of the error, :term:`attach <attached thread 
state>` a :term:`thread state`,
+and call the regular (non-``Raw``) function. Note that the regular function 
may succeed after
 the ``Raw`` one failed.
 
 .. c:function:: int PyTime_MonotonicRaw(PyTime_t *result)
 
    Similar to :c:func:`PyTime_Monotonic`,
-   but don't set an exception on error and don't require holding the GIL.
+   but don't set an exception on error and don't require an :term:`attached 
thread state`.
 
 .. c:function:: int PyTime_PerfCounterRaw(PyTime_t *result)
 
    Similar to :c:func:`PyTime_PerfCounter`,
-   but don't set an exception on error and don't require holding the GIL.
+   but don't set an exception on error and don't require an :term:`attached 
thread state`.
 
 .. c:function:: int PyTime_TimeRaw(PyTime_t *result)
 
    Similar to :c:func:`PyTime_Time`,
-   but don't set an exception on error and don't require holding the GIL.
+   but don't set an exception on error and don't require an :term:`attached 
thread state`.
 
 
 Conversion functions
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index 51c9f05fd6a807..9d551aa997ba1f 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -731,7 +731,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
       object becomes part of a refcount cycle, that cycle might be collected by
       a garbage collection on any thread).  This is not a problem for Python
       API calls, since the thread on which :c:member:`!tp_dealloc` is called
-      will own the Global Interpreter Lock (GIL).  However, if the object being
+      with an :term:`attached thread state`.  However, if the object being
       destroyed in turn destroys objects from some other C or C++ library, care
       should be taken to ensure that destroying those objects on the thread
       which called :c:member:`!tp_dealloc` will not violate any assumptions of
diff --git a/Doc/extending/newtypes_tutorial.rst 
b/Doc/extending/newtypes_tutorial.rst
index bcf938f117d148..b2ae18d75c3831 100644
--- a/Doc/extending/newtypes_tutorial.rst
+++ b/Doc/extending/newtypes_tutorial.rst
@@ -403,8 +403,8 @@ the new attribute values.  We might be tempted, for example 
to assign the
 But this would be risky.  Our type doesn't restrict the type of the
 ``first`` member, so it could be any kind of object.  It could have a
 destructor that causes code to be executed that tries to access the
-``first`` member; or that destructor could release the
-:term:`Global interpreter Lock <GIL>` and let arbitrary code run in other
+``first`` member; or that destructor could detach the
+:term:`thread state <attached thread state>` and let arbitrary code run in 
other
 threads that accesses and modifies our object.
 
 To be paranoid and protect ourselves against this possibility, we almost
@@ -413,8 +413,8 @@ don't we have to do this?
 
 * when we absolutely know that the reference count is greater than 1;
 
-* when we know that deallocation of the object [#]_ will neither release
-  the :term:`GIL` nor cause any calls back into our type's code;
+* when we know that deallocation of the object [#]_ will neither detach
+  the :term:`thread state <attached thread state>` nor cause any calls back 
into our type's code;
 
 * when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc`
   handler on a type which doesn't support cyclic garbage collection [#]_.
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 1734d4c7339c2b..0b26e18efd7f1b 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -132,6 +132,28 @@ Glossary
       iterator's :meth:`~object.__anext__` method until it raises a
       :exc:`StopAsyncIteration` exception.  Introduced by :pep:`492`.
 
+   attached thread state
+
+      A :term:`thread state` that is active for the current OS thread.
+
+      When a :term:`thread state` is attached, the OS thread has
+      access to the full Python C API and can safely invoke the
+      bytecode interpreter.
+
+      Unless a function explicitly notes otherwise, attempting to call
+      the C API without an attached thread state will result in a fatal
+      error or undefined behavior.  A thread state can be attached and detached
+      explicitly by the user through the C API, or implicitly by the runtime,
+      including during blocking C calls and by the bytecode interpreter in 
between
+      calls.
+
+      On most builds of Python, having an attached thread state implies that 
the
+      caller holds the :term:`GIL` for the current interpreter, so only
+      one OS thread can have an attached thread state at a given moment. In
+      :term:`free-threaded <free threading>` builds of Python, threads can 
concurrently
+      hold an attached thread state, allowing for true parallelism of the 
bytecode
+      interpreter.
+
    attribute
       A value associated with an object which is usually referenced by name
       using dotted expressions.
@@ -622,6 +644,10 @@ Glossary
       multi-threaded applications and makes it easier to use multi-core CPUs
       efficiently. For more details, see :pep:`703`.
 
+      In prior versions of Python's C API, a function might declare that it
+      requires the GIL to be held in order to use it. This refers to having an
+      :term:`attached thread state`.
+
    hash-based pyc
       A bytecode cache file that uses the hash rather than the last-modified
       time of the corresponding source file to determine its validity. See
@@ -1295,6 +1321,29 @@ Glossary
       See also :term:`binary file` for a file object able to read and write
       :term:`bytes-like objects <bytes-like object>`.
 
+   thread state
+
+      The information used by the :term:`CPython` runtime to run in an OS 
thread.
+      For example, this includes the current exception, if any, and the
+      state of the bytecode interpreter.
+
+      Each thread state is bound to a single OS thread, but threads may have
+      many thread states available.  At most, one of them may be
+      :term:`attached <attached thread state>` at once.
+
+      An :term:`attached thread state` is required to call most
+      of Python's C API, unless a function explicitly documents otherwise.
+      The bytecode interpreter only runs under an attached thread state.
+
+      Each thread state belongs to a single interpreter, but each interpreter
+      may have many thread states, including multiple for the same OS thread.
+      Thread states from multiple interpreters may be bound to the same
+      thread, but only one can be :term:`attached <attached thread state>` in
+      that thread at any given moment.
+
+      See :ref:`Thread State and the Global Interpreter Lock <threads>` for 
more
+      information.
+
    token
 
       A small unit of source code, generated by the

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to