Skip to content

Commit 9f9eb4c

Browse files
committed
Clarify some things.
1 parent 5abdb41 commit 9f9eb4c

1 file changed

Lines changed: 51 additions & 39 deletions

File tree

peps/pep-0788.rst

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -270,46 +270,23 @@ updated to switch over to terms like
270270
:term:`"global interpreter lock" <global interpreter lock>`, so this namespace
271271
seems to fit well for this PEP.
272272

273-
Specification
274-
=============
275-
276-
Interpreter reference counting
277-
------------------------------
278-
279-
Internally, the interpreter will have to keep track of a reference count
280-
field, which will determine when the interpreter state is actually
281-
deallocated. This is done to prevent use-after-free crashes in
282-
:c:func:`PyThreadState_Ensure` for interpreters with short lifetimes.
283-
284-
An interpreter state returned by :c:func:`Py_NewInterpreter` (or really,
285-
:c:func:`PyInterpreterState_New`) will start with a reference count of 1, and
286-
:c:func:`PyInterpreterState_Delete` will decrement the reference count. If the
287-
new reference count is zero, :c:func:`PyInterpreterState_Delete` will
288-
deallocate the interpreter state. However, the reference count will *not*
289-
prevent the interpreter from finalizing.
290-
291-
.. c:function:: PyInterpreterState *PyInterpreterState_Hold(void)
292-
293-
Similar to :c:func:`PyInterpreterState_Get`, but returns a strong
294-
reference to the interpreter (meaning, it has its reference count
295-
incremented by one, allowing the returned interpreter state to be safely
296-
accessed by another thread).
297-
298-
This function is generally meant to be used in tandem with
299-
:c:func:`PyThreadState_Ensure`.
300-
301-
The caller must have an :term:`attached thread state`, and cannot return
302-
``NULL``. Failures are always a fatal error.
303-
304-
305-
.. c:function:: void PyInterpreterState_Release(PyInterpreterState *interp)
273+
Preventing interpreter finalization with references
274+
---------------------------------------------------
306275

307-
Decrement the reference count of the interpreter, as was incremented by
308-
:c:func:`PyInterpreterState_Hold`.
276+
Several iterations of this API have taken an approach where
277+
:c:func:`PyThreadState_Ensure` can return a failure based on the state of
278+
the interpreter. Instead, this PEP takes an approach where an interpreter
279+
keeps track of the number of non-daemon threads, which inherently prevents
280+
it from beginning finalization.
309281

310-
This function cannot fail, other than with a fatal error. The caller must
311-
have an :term:`attached thread state` for *interp*.
282+
The main upside with this approach is that there's more consistency with
283+
attaching threads. Using an interpreter reference from the calling thread
284+
keeps the interpreter from finalizing before the thread starts, ensuring
285+
that it always works. An approach that were to return a failure based on
286+
the start-time of the thread could cause spurious issues.
312287

288+
Specification
289+
=============
313290

314291
Daemon and non-daemon threads
315292
-----------------------------
@@ -344,8 +321,43 @@ remain daemon by default.
344321
:attr:`threading.Thread.daemon`.
345322
346323
Return zero on success, non-zero *without* an exception set on failure.
347-
Failure generally means that threads have already finalized for the
348-
current interpreter.
324+
325+
Interpreter reference counting
326+
------------------------------
327+
328+
Internally, the interpreter will have to keep track of the number of
329+
non-daemon native threads, which will determine when the interpreter can
330+
finalize. This is done to prevent use-after-free crashes in
331+
:c:func:`PyThreadState_Ensure` for interpreters with short lifetimes, and
332+
to remove needless layers of synchronization between the calling thread and
333+
the started thread.
334+
335+
An interpreter state returned by :c:func:`Py_NewInterpreter` (or really,
336+
:c:func:`PyInterpreterState_New`) will start with a native thread countdown.
337+
For simplicity's sake, this will be referred to as a reference count.
338+
A non-zero reference count prevents the interpreter from finalizing.
339+
340+
.. c:function:: PyInterpreterState *PyInterpreterState_Hold(void)
341+
342+
Similar to :c:func:`PyInterpreterState_Get`, but returns a strong
343+
reference to the interpreter (meaning, it has its reference count
344+
incremented by one, allowing the returned interpreter state to be safely
345+
accessed by another thread, because it will be prevented from finalizing).
346+
347+
This function is generally meant to be used in tandem with
348+
:c:func:`PyThreadState_Ensure`.
349+
350+
The caller must have an :term:`attached thread state`, and cannot return
351+
``NULL``. Failures are always a fatal error.
352+
353+
354+
.. c:function:: void PyInterpreterState_Release(PyInterpreterState *interp)
355+
356+
Decrement the reference count of the interpreter, as was incremented by
357+
:c:func:`PyInterpreterState_Hold`.
358+
359+
This function cannot fail, other than with a fatal error. The caller must
360+
have an :term:`attached thread state` for *interp*.
349361
350362
Ensuring and releasing thread states
351363
------------------------------------

0 commit comments

Comments
 (0)