Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-127989: C API: Refer to attached thread states instead of the GIL #127990

Merged
merged 76 commits into from
Mar 20, 2025
Merged
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
ad7ee2d
Document the term 'thread state.'
ZeroIntensity Dec 14, 2024
bea045a
Change term for PyDict_GetItem
ZeroIntensity Dec 14, 2024
e286ba5
Change term for PyErr_Occurred
ZeroIntensity Dec 14, 2024
6006b22
Change term for PyErr_SetInterrupt
ZeroIntensity Dec 14, 2024
8dc3928
Change term for PyErr_SetInterruptEx
ZeroIntensity Dec 14, 2024
f46ca3d
Change term for PyConfig_Get
ZeroIntensity Dec 14, 2024
555a03c
Change term for PyConfig_Names
ZeroIntensity Dec 14, 2024
ddb98cd
Change term for PyConfig_Set
ZeroIntensity Dec 14, 2024
5d423f8
Change term for PyUnstable_AtExit
ZeroIntensity Dec 14, 2024
d2d2f67
Change term for Py_Initialize note
ZeroIntensity Dec 14, 2024
aa9c4c6
Change term for PyInterpreterState_Get
ZeroIntensity Dec 14, 2024
c05be67
Change term for PyInterpreterState_GetID
ZeroIntensity Dec 14, 2024
3a69922
Change term for PyThreadState_SetAsyncEx
ZeroIntensity Dec 14, 2024
3336ad7
Change term for Py_NewInterpreterFromConfig
ZeroIntensity Dec 14, 2024
3991681
Change term for Py_FinalizeEx
ZeroIntensity Dec 14, 2024
6d397eb
Change term for Py_AddPendingCall
ZeroIntensity Dec 14, 2024
3b7b3ff
Change term for PyEval_SetProfile
ZeroIntensity Dec 14, 2024
5358d14
Change term for PyEval_SetProfileAllThreads
ZeroIntensity Dec 14, 2024
093ba05
Change term for PyEval_SetTrace
ZeroIntensity Dec 14, 2024
11582fa
Change term for PyEval_SetTraceAllThreads
ZeroIntensity Dec 14, 2024
3d55d2d
Change term for PyRefTracer_SetTracer
ZeroIntensity Dec 14, 2024
2785c1d
Change term for PyRefTracer_GetTracer
ZeroIntensity Dec 14, 2024
6d80b02
Change term for PyMutex_Lock
ZeroIntensity Dec 14, 2024
94e046b
Change term for allocator domains
ZeroIntensity Dec 14, 2024
713beb2
Change term for raw memory interface
ZeroIntensity Dec 14, 2024
2140bde
Change term for memory interface
ZeroIntensity Dec 14, 2024
f608211
Change term for object allocators
ZeroIntensity Dec 14, 2024
d619387
Change term for PyMem_SetAllocator
ZeroIntensity Dec 14, 2024
e7828ed
Change term for PyMem_SetAllocator (again)
ZeroIntensity Dec 14, 2024
6b33565
Change term for debug hooks
ZeroIntensity Dec 14, 2024
6230177
Change term for debug hooks (again)
ZeroIntensity Dec 14, 2024
f74832a
Change term for PyState*
ZeroIntensity Dec 14, 2024
7161fc0
Change term for various things
ZeroIntensity Dec 14, 2024
d58b74f
Change term for clock functions
ZeroIntensity Dec 14, 2024
a761c4a
Change term for raw clock functions
ZeroIntensity Dec 14, 2024
de122f5
Change term for tp_dealloc warning
ZeroIntensity Dec 14, 2024
0b0176b
Change term for the types tutorial
ZeroIntensity Dec 14, 2024
c15f5c4
Add more information about thread states.
ZeroIntensity Dec 14, 2024
0130b20
Change terms for 'cautions regarding runtime finalization'
ZeroIntensity Dec 14, 2024
a1e47b7
Simplify PyEval_SaveThread and PyEval_RestoreThread
ZeroIntensity Dec 14, 2024
0173c46
Some more terminology fixups.
ZeroIntensity Dec 14, 2024
166d970
Fix Sphinx build errors.
ZeroIntensity Dec 14, 2024
adae494
Change some usage of the term 'global interpreter lock'
ZeroIntensity Dec 14, 2024
a70ab11
Add some more terms for disambiguation.
ZeroIntensity Dec 14, 2024
8584c86
Change usage of some terms.
ZeroIntensity Dec 14, 2024
48b145a
Play around with terminology.
ZeroIntensity Dec 14, 2024
8ce3d7d
Various terminology changes.
ZeroIntensity Dec 14, 2024
e5f1d18
Change the glossary definition a little bit.
ZeroIntensity Dec 14, 2024
905ca5b
Change some phrasing.
ZeroIntensity Dec 14, 2024
f2826c4
Fix some usage of terms.
ZeroIntensity Dec 14, 2024
5c44391
Change some usage of 'global interpreter lock'
ZeroIntensity Dec 15, 2024
7d5877f
Fix pre-commit lint.
ZeroIntensity Dec 15, 2024
283fc92
Delete redundant file
ZeroIntensity Dec 16, 2024
a7488ab
Revert "Delete redundant file"
ZeroIntensity Dec 16, 2024
4c532b6
Remove accidental find-and-replace change.
ZeroIntensity Dec 16, 2024
352acc5
Switch to a reference
ZeroIntensity Dec 16, 2024
ed550bc
Use a less wordy phrase for detaching.
ZeroIntensity Dec 16, 2024
d7cf403
Fix a typo in PyInterpreterState_Get
ZeroIntensity Dec 16, 2024
f61a6da
Change some wording in PyEval_SaveThread and PyEval_RestoreThread
ZeroIntensity Dec 16, 2024
36af941
Change wording for PyThreadState_Swap
ZeroIntensity Dec 16, 2024
0b23daa
Make glossary terms more clear.
ZeroIntensity Dec 16, 2024
163b0b8
Change up wording for 'attached thread state'
ZeroIntensity Dec 16, 2024
3b2bed8
Clarify that the C API is what needs a thread state.
ZeroIntensity Dec 16, 2024
80ae46b
Update Doc/glossary.rst
ZeroIntensity Dec 17, 2024
3dee63f
Update Doc/glossary.rst
ZeroIntensity Dec 17, 2024
9ed3a0b
Drop the phrase 'current thread state' and only use 'attached thread …
ZeroIntensity Feb 12, 2025
b3cbbf8
Add extra note about free-threading.
ZeroIntensity Feb 12, 2025
1c37d59
Add a seealso.
ZeroIntensity Feb 12, 2025
32a4937
Merge from main.
ZeroIntensity Feb 12, 2025
2fba67c
Fix weird merge artifact.
ZeroIntensity Feb 12, 2025
a0dc12c
Merge branch 'main' into clarify-gil-tstate
ZeroIntensity Feb 27, 2025
94619f6
Change term for new PyConfig* APIs
ZeroIntensity Feb 27, 2025
e6f1f28
Change term for PyUnstable_InterpreterState_GetMainModule
ZeroIntensity Feb 27, 2025
828d24b
Change term for Py_fopen
ZeroIntensity Feb 27, 2025
ace174f
Merge branch 'main' into clarify-gil-tstate
encukou Mar 19, 2025
788d735
Change artifact from 'runtime context' to 'thread state'
ZeroIntensity Mar 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/c-api/dict.rst
Original file line number Diff line number Diff line change
@@ -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.


6 changes: 3 additions & 3 deletions Doc/c-api/exceptions.rst
Original file line number Diff line number Diff line change
@@ -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

301 changes: 157 additions & 144 deletions Doc/c-api/init.rst

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions Doc/c-api/init_config.rst
Original file line number Diff line number Diff line change
@@ -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

32 changes: 15 additions & 17 deletions Doc/c-api/memory.rst
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions Doc/c-api/module.rst
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion Doc/c-api/perfmaps.rst
Original file line number Diff line number Diff line change
@@ -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)

2 changes: 1 addition & 1 deletion Doc/c-api/reflection.rst
Original file line number Diff line number Diff line change
@@ -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`.
6 changes: 3 additions & 3 deletions Doc/c-api/sys.rst
Original file line number Diff line number Diff line change
@@ -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
14 changes: 7 additions & 7 deletions Doc/c-api/time.rst
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion Doc/c-api/typeobj.rst
Original file line number Diff line number Diff line change
@@ -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
8 changes: 4 additions & 4 deletions Doc/extending/newtypes_tutorial.rst
Original file line number Diff line number Diff line change
@@ -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 [#]_.
49 changes: 49 additions & 0 deletions Doc/glossary.rst
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few points to consider, which are reflected in my other comments:

  • current does not imply attached, but attached does implies current
  • the glossary probably isn't the best place for C-API details
  • "runtime context" or "execution context" might be a clearer term for users than "thread state"

The only tricky part is that we already talk about "contexts" relative to asyncio.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit the suggestions tomorrow when I'm available to do a full find-and-replace so I don't blow up CI in the meantime.

For the per-thread thread state pointer (what a mouthful!), I'm happy with something like "runtime context," because there was no prior term for it, but I think we do want to keep the term "thread state." Thread states are documented, and users like to read the source code to understand some C functions--seeing _PyThreadState_GET and "thread state" in the documentation makes things more clear. That, and "context" doesn't convey the fact that it's a thread-local too well, which is important.

the glossary probably isn't the best place for C-API details

Hmm, we do have "borrowed reference" and "strong reference" in there; where else should "thread state" point to?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"runtime context" or "execution context" might be a clearer term for users than "thread state"

I like "thread state" :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for sticking with thread state.

Between contextvars and context managers, and just the general idea of "context of execution", "context" is seriously overloaded already.

"thread state" isn't completely unambiguous (it could theoretically take on the holistic meaning of "all state associated with the current thread, including the execution stack and all thread local variables"), but the context(!) of use should help avoid that misinterpretation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Runtime context" in particular is problematic, since the execution model is set up with the hierarchy of:

  • there is one runtime, which may be serially finalized and reinitialized, but you can never have more than one at a time
  • the runtime will host at least one interpreter, but may host more
  • each interpreter will have at least one thread state, but may have more
  • for an OS thread to execute Python code, it must be associated with a Python thread state (which also indirectly determines which interpreter it is associated with)

Original file line number Diff line number Diff line change
@@ -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
Loading