Skip to content

Commit eff9b40

Browse files
Improve new PyThreadState API docs.
Co-authored-by: Petr Viktorin <encukou@gmail.com>
1 parent 74259f8 commit eff9b40

1 file changed

Lines changed: 18 additions & 122 deletions

File tree

Doc/c-api/threads.rst

Lines changed: 18 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -282,46 +282,19 @@ Attaching/detaching thread states
282282
Otherwise, if both of the above cases fail, a new thread state is created
283283
for *guard*. It is then attached and marked as owned by ``PyThreadState_Ensure``.
284284
285-
This function will return ``NULL`` to indicate a memory allocation failure, and
286-
otherwise return a pointer to the thread state that was previously attached
287-
(which might have been ``NULL``, in which case an non-``NULL`` sentinel value is
288-
returned instead to differentiate between failure -- this means that this function
289-
will sometimes return an invalid ``PyThreadState`` pointer).
290-
291-
To visualize, this function is roughly equivalent to the following:
292-
293-
.. code-block:: c
294-
295-
PyThreadState *
296-
PyThreadState_Ensure(PyInterpreterGuard *guard)
297-
{
298-
assert(guard != NULL);
299-
PyInterpreterState *interp = PyInterpreterGuard_GetInterpreter(guard);
300-
assert(interp != NULL);
301-
302-
PyThreadState *current_tstate = PyThreadState_GetUnchecked();
303-
if (current_tstate == NULL) {
304-
PyThreadState *last_used = PyGILState_GetThisThreadState();
305-
if (last_used != NULL) {
306-
++last_used->ensure_counter;
307-
PyThreadState_Swap(last_used);
308-
return NO_TSTATE_SENTINEL;
309-
}
310-
} else if (current_tstate->interp == interp) {
311-
++current_tstate->ensure_counter;
312-
return current_tstate;
313-
}
314-
315-
PyThreadState *new_tstate = PyThreadState_New(interp);
316-
if (new_tstate == NULL) {
317-
return NULL;
318-
}
319-
320-
++new_tstate->ensure_counter;
321-
new_tstate->owned_by_pythreadstate_ensure = true;
322-
PyThreadState_Swap(new_tstate);
323-
return current_tstate == NULL ? NO_TSTATE_SENTINEL : current_tstate;
324-
}
285+
The function's effect (if any) will be reversed by the matching call to
286+
:c:func:`PyThreadState_Release`.
287+
288+
On error, this function returns ``NULL`` *without* an exception set.
289+
Do not call :c:func:`!PyThreadState_Release` in this case.
290+
291+
On success, this function returns a pointer to the :term:`thread state` that
292+
was previously attached, or, if no state was previously attached, a value that
293+
is not a valid :c:type:`!PyThreadState` pointer.
294+
295+
The returned value must be passed to the matching call to :c:func:`!PyThreadState_Release`,
296+
and must not be passed to any other C API functions
297+
(unless it matches a known valid :c:type:`!PyThreadState` pointer).
325298
326299
.. versionadded:: next
327300
@@ -330,53 +303,17 @@ Attaching/detaching thread states
330303
331304
Get an attached thread state for the interpreter referenced by *view*.
332305
333-
*view* must not be ``NULL``. If the interpreter referenced by *view* has been
334-
finalized or is currently finalizing, then this function returns ``NULL`` without
335-
setting an exception. This function may also return ``NULL`` on other errors,
336-
such memory allocation failure.
337-
338-
The interpreter referenced by *view* will be implicitly guarded. The
339-
guard will be released upon the corresponding :c:func:`PyThreadState_Release`
306+
On success, the interpreter referenced by *view* will be implicitly guarded;
307+
the guard will be released upon the corresponding :c:func:`PyThreadState_Release`
340308
call.
341-
342-
On success, this function will return the thread state that was previously attached.
343-
If no thread state was previously attached, this returns a non-``NULL`` sentinel
344-
value. The behavior of whether this function creates a thread state is
345-
equivalent to that of :c:func:`PyThreadState_Ensure`.
346-
347-
To visualize, function is roughly equivalent to the following:
348-
349-
.. code-block:: c
350-
351-
PyThreadState *
352-
PyThreadState_EnsureFromView(PyInterpreterView *view)
353-
{
354-
assert(view != NULL);
355-
PyInterpreterGuard *guard = PyInterpreterGuard_FromView(view);
356-
if (guard == NULL) {
357-
return NULL;
358-
}
359-
360-
PyThreadState *tstate = PyThreadState_Ensure(guard);
361-
if (tstate == NULL) {
362-
PyInterpreterGuard_Close(guard);
363-
return NULL;
364-
}
365-
366-
if (tstate->guard == NULL) {
367-
tstate->guard = guard;
368-
} else {
369-
PyInterpreterGuard_Close(guard);
370-
}
371-
372-
return tstate;
373-
}
309+
Otherwise, the behavior and return value are the same as for
310+
:c:func:`PyThreadState_Ensure`.
374311
375312
376313
.. c:function:: void PyThreadState_Release(PyThreadState *tstate)
377314
378315
Undo a :c:func:`PyThreadState_Ensure` call. This must be called exactly once
379-
for each call to ``PyThreadState_Ensure``.
316+
for each successful call to ``PyThreadState_Ensure``.
380317
381318
This function will decrement an internal counter on the attached thread state. If
382319
this counter ever reaches below zero, this function emits a fatal error (via
@@ -390,47 +327,6 @@ Attaching/detaching thread states
390327
If *tstate* indicates that no prior thread state was attached, there will be
391328
no attached thread state upon returning.
392329
393-
To visualize, this function is roughly equivalent to the following:
394-
395-
.. code-block:: c
396-
397-
void
398-
PyThreadState_Release(PyThreadState *old_tstate)
399-
{
400-
PyThreadState *current_tstate = PyThreadState_Get();
401-
assert(old_tstate != NULL);
402-
assert(current_tstate != NULL);
403-
assert(current_tstate->ensure_counter > 0);
404-
if (--current_tstate->ensure_counter > 0) {
405-
// There are remaining PyThreadState_Ensure() calls
406-
// for this thread state.
407-
return;
408-
}
409-
410-
assert(current_tstate->ensure_counter == 0);
411-
if (old_tstate == NO_TSTATE_SENTINEL) {
412-
// No thread state was attached prior the PyThreadState_Ensure()
413-
// call. So, we can just destroy the current thread state and return.
414-
assert(current_tstate->owned_by_pythreadstate_ensure);
415-
PyThreadState_Clear(current_tstate);
416-
PyThreadState_DeleteCurrent();
417-
return;
418-
}
419-
420-
if (tstate->guard != NULL) {
421-
PyInterpreterGuard_Close(tstate->guard);
422-
return;
423-
}
424-
425-
if (tstate->owned_by_pythreadstate_ensure) {
426-
// The attached thread state was created by the initial PyThreadState_Ensure()
427-
// call. It's our job to destroy it.
428-
PyThreadState_Clear(current_tstate);
429-
PyThreadState_DeleteCurrent();
430-
}
431-
432-
PyThreadState_Swap(old_tstate);
433-
}
434330
435331
.. _legacy-api:
436332
.. _gilstate:

0 commit comments

Comments
 (0)