mirror of
https://github.com/python/cpython.git
synced 2026-04-14 07:41:00 +00:00
gh-142518: Annotate PyList_* C APIs for thread safety (#146109)
This commit is contained in:
parent
1e4ed93210
commit
5b25eaec37
2 changed files with 100 additions and 0 deletions
|
|
@ -74,11 +74,25 @@ List Objects
|
|||
Like :c:func:`PyList_GetItemRef`, but returns a
|
||||
:term:`borrowed reference` instead of a :term:`strong reference`.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the list concurrently. Prefer :c:func:`PyList_GetItemRef`, which returns
|
||||
a :term:`strong reference`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyList_GET_ITEM(PyObject *list, Py_ssize_t i)
|
||||
|
||||
Similar to :c:func:`PyList_GetItem`, but without error checking.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the list concurrently. Prefer :c:func:`PyList_GetItemRef`, which returns
|
||||
a :term:`strong reference`.
|
||||
|
||||
|
||||
.. c:function:: int PyList_SetItem(PyObject *list, Py_ssize_t index, PyObject *item)
|
||||
|
||||
|
|
@ -108,6 +122,14 @@ List Objects
|
|||
is being replaced; any reference in *list* at position *i* will be
|
||||
leaked.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, this macro has no internal
|
||||
synchronization. It is normally only used to fill in new lists where no
|
||||
other thread has a reference to the list. If the list may be shared,
|
||||
use :c:func:`PyList_SetItem` instead, which uses a :term:`per-object
|
||||
lock`.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Insert(PyObject *list, Py_ssize_t index, PyObject *item)
|
||||
|
||||
|
|
@ -138,6 +160,12 @@ List Objects
|
|||
Return ``0`` on success, ``-1`` on failure. Indexing from the end of the
|
||||
list is not supported.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, when *itemlist* is a :class:`list`,
|
||||
both *list* and *itemlist* are locked for the duration of the operation.
|
||||
For other iterables (or ``NULL``), only *list* is locked.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Extend(PyObject *list, PyObject *iterable)
|
||||
|
||||
|
|
@ -150,6 +178,14 @@ List Objects
|
|||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, when *iterable* is a :class:`list`,
|
||||
:class:`set`, :class:`dict`, or dict view, both *list* and *iterable*
|
||||
(or its underlying dict) are locked for the duration of the operation.
|
||||
For other iterables, only *list* is locked; *iterable* may be
|
||||
concurrently modified by another thread.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Clear(PyObject *list)
|
||||
|
||||
|
|
@ -168,6 +204,14 @@ List Objects
|
|||
Sort the items of *list* in place. Return ``0`` on success, ``-1`` on
|
||||
failure. This is equivalent to ``list.sort()``.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, element comparison via
|
||||
:meth:`~object.__lt__` can execute arbitrary Python code, during which
|
||||
the :term:`per-object lock` may be temporarily released. For built-in
|
||||
types (:class:`str`, :class:`int`, :class:`float`), the lock is not
|
||||
released during comparison.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Reverse(PyObject *list)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,3 +17,59 @@
|
|||
PyMutex_Lock:shared:
|
||||
PyMutex_Unlock:shared:
|
||||
PyMutex_IsLocked:atomic:
|
||||
|
||||
# List objects (Doc/c-api/list.rst)
|
||||
|
||||
# Type checks - read ob_type pointer, always safe
|
||||
PyList_Check:atomic:
|
||||
PyList_CheckExact:atomic:
|
||||
|
||||
# Creation - pure allocation, no shared state
|
||||
PyList_New:atomic:
|
||||
|
||||
# Size - uses atomic load on free-threaded builds
|
||||
PyList_Size:atomic:
|
||||
PyList_GET_SIZE:atomic:
|
||||
|
||||
# Strong-reference lookup - lock-free with atomic ops
|
||||
PyList_GetItemRef:atomic:
|
||||
|
||||
# Borrowed-reference lookups - no locking; returned borrowed
|
||||
# reference is unsafe in free-threaded builds without
|
||||
# external synchronization
|
||||
PyList_GetItem:compatible:
|
||||
PyList_GET_ITEM:compatible:
|
||||
|
||||
# Single-item mutations - hold per-object lock for duration;
|
||||
# appear atomic to lock-free readers
|
||||
PyList_SetItem:atomic:
|
||||
PyList_Append:atomic:
|
||||
|
||||
# Insert - protected by per-object critical section; shifts
|
||||
# elements so lock-free readers may observe intermediate states
|
||||
PyList_Insert:shared:
|
||||
|
||||
# Initialization macro - no synchronization; normally only used
|
||||
# to fill in new lists where there is no previous content
|
||||
PyList_SET_ITEM:compatible:
|
||||
|
||||
# Bulk operations - hold per-object lock for duration
|
||||
PyList_GetSlice:atomic:
|
||||
PyList_AsTuple:atomic:
|
||||
PyList_Clear:atomic:
|
||||
|
||||
# Reverse - protected by per-object critical section; swaps
|
||||
# elements so lock-free readers may observe intermediate states
|
||||
PyList_Reverse:shared:
|
||||
|
||||
# Slice assignment - lock target list; also lock source when it
|
||||
# is a list
|
||||
PyList_SetSlice:shared:
|
||||
|
||||
# Sort - per-object lock held; comparison callbacks may execute
|
||||
# arbitrary Python code
|
||||
PyList_Sort:shared:
|
||||
|
||||
# Extend - lock target list; also lock source when it is a
|
||||
# list, set, or dict
|
||||
PyList_Extend:shared:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue