Skip to content

Commit e4c71c5

Browse files
add thread safety annotations for tuple C-API
1 parent 7817651 commit e4c71c5

File tree

2 files changed

+59
-11
lines changed

2 files changed

+59
-11
lines changed

Doc/c-api/tuple.rst

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,10 @@ Tuple Objects
8080
:c:func:`Py_NewRef(PyTuple_GetItem(...)) <Py_NewRef>`
8181
or :c:func:`PySequence_GetItem`.
8282
83-
8483
.. c:function:: PyObject* PyTuple_GET_ITEM(PyObject *p, Py_ssize_t pos)
8584
8685
Like :c:func:`PyTuple_GetItem`, but does no checking of its arguments.
8786
88-
8987
.. c:function:: PyObject* PyTuple_GetSlice(PyObject *p, Py_ssize_t low, Py_ssize_t high)
9088
9189
Return the slice of the tuple pointed to by *p* between *low* and *high*,
@@ -99,7 +97,8 @@ Tuple Objects
9997
10098
Insert a reference to object *o* at position *pos* of the tuple pointed to by
10199
*p*. Return ``0`` on success. If *pos* is out of bounds, return ``-1``
102-
and set an :exc:`IndexError` exception.
100+
and set an :exc:`IndexError` exception. This function should only be used to fill in brand new tuples;
101+
using it on an existing tuples is thread-unsafe.
103102
104103
.. note::
105104
@@ -110,7 +109,7 @@ Tuple Objects
110109
.. c:function:: void PyTuple_SET_ITEM(PyObject *p, Py_ssize_t pos, PyObject *o)
111110
112111
Like :c:func:`PyTuple_SetItem`, but does no error checking, and should *only* be
113-
used to fill in brand new tuples.
112+
used to fill in brand new tuples. Using it on an existing tuple is thread-unsafe.
114113
115114
Bounds checking is performed as an assertion if Python is built in
116115
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
@@ -122,12 +121,6 @@ Tuple Objects
122121
is being replaced; any reference in the tuple at position *pos* will be
123122
leaked.
124123
125-
.. warning::
126-
127-
This macro should *only* be used on tuples that are newly created.
128-
Using this macro on a tuple that is already in use (or in other words, has
129-
a refcount > 1) could lead to undefined behavior.
130-
131124
132125
.. c:function:: int _PyTuple_Resize(PyObject **p, Py_ssize_t newsize)
133126
@@ -142,6 +135,11 @@ Tuple Objects
142135
``*p`` is destroyed. On failure, returns ``-1`` and sets ``*p`` to ``NULL``, and
143136
raises :exc:`MemoryError` or :exc:`SystemError`.
144137
138+
.. note::
139+
140+
In the :term:`free-threaded build`, this function must only be used on
141+
tuples that are not yet visible to other threads.
142+
145143
146144
.. _struct-sequence-objects:
147145
@@ -236,11 +234,12 @@ type.
236234
.. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos)
237235
238236
Return the object at position *pos* in the struct sequence pointed to by *p*.
237+
The returned reference is borrowed from the struct sequence *p*
238+
(that is: it is only valid as long as you hold a reference to *p*).
239239
240240
Bounds checking is performed as an assertion if Python is built in
241241
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
242242
243-
244243
.. c:function:: PyObject* PyStructSequence_GET_ITEM(PyObject *p, Py_ssize_t pos)
245244
246245
Alias to :c:func:`PyStructSequence_GetItem`.

Doc/data/threadsafety.dat

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,52 @@ PyCapsule_SetContext:distinct:
153153
# Import - looks up a capsule from a module attribute and
154154
# calls PyCapsule_GetPointer; may call arbitrary code
155155
PyCapsule_Import:compatible:
156+
157+
# Tuple objects
158+
159+
PyTuple_CheckExact:atomic:
160+
161+
# Creation - pure allocation, no shared state
162+
PyTuple_New:atomic:
163+
PyTuple_FromArray:atomic:
164+
PyTuple_Pack:atomic:
165+
166+
# Size - tuples are immutable so size never changes
167+
PyTuple_Size:atomic:
168+
PyTuple_GET_SIZE:atomic:
169+
170+
# Borrowed-reference lookups - tuples are immutable so items
171+
# never change, however the tuple must be kept alive while using the borrowed reference
172+
PyTuple_GetItem:compatible:
173+
PyTuple_GET_ITEM:compatible:
174+
175+
# Slice - creates a new tuple from an immutable source
176+
PyTuple_GetSlice:atomic:
177+
178+
# SetItem - only usable on tuples with refcount 1
179+
PyTuple_SetItem:compatible:
180+
181+
# SET_ITEM - no synchronization; only for filling in brand new tuples
182+
PyTuple_SET_ITEM:compatible:
183+
184+
# Resize - only usable on tuples with refcount 1
185+
_PyTuple_Resize:distinct:
186+
187+
# Struct Sequence objects
188+
189+
# Creation
190+
PyStructSequence_NewType:atomic:
191+
PyStructSequence_New:atomic:
192+
193+
# Initialization - modifies the type object in place
194+
PyStructSequence_InitType:distinct:
195+
PyStructSequence_InitType2:distinct:
196+
197+
# Borrowed-reference lookups - same as tuple items
198+
PyStructSequence_GetItem:compatible:
199+
PyStructSequence_GET_ITEM:compatible:
200+
201+
# SetItem - only for filling in brand new instances
202+
PyStructSequence_SetItem:compatible:
203+
PyStructSequence_SET_ITEM:compatible:
204+

0 commit comments

Comments
 (0)