gh-114271: Make _thread.ThreadHandle thread-safe in free-threaded builds (GH-115190)

Make `_thread.ThreadHandle` thread-safe in free-threaded builds

We protect the mutable state of `ThreadHandle` using a `_PyOnceFlag`.
Concurrent operations (i.e. `join` or `detach`) on `ThreadHandle` block
until it is their turn to execute or an earlier operation succeeds.
Once an operation has been applied successfully all future operations
complete immediately.

The `join()` method is now idempotent. It may be called multiple times
but the underlying OS thread will only be joined once. After `join()`
succeeds, any future calls to `join()` will succeed immediately.

The internal thread handle `detach()` method has been removed.
This commit is contained in:
mpage 2024-03-01 13:43:12 -08:00 committed by GitHub
parent 5e0c7bc1d3
commit 9e88173d36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 230 additions and 106 deletions

View file

@ -249,6 +249,13 @@ _PyRawMutex_UnlockSlow(_PyRawMutex *m)
}
}
int
_PyEvent_IsSet(PyEvent *evt)
{
uint8_t v = _Py_atomic_load_uint8(&evt->v);
return v == _Py_LOCKED;
}
void
_PyEvent_Notify(PyEvent *evt)
{
@ -297,6 +304,30 @@ PyEvent_WaitTimed(PyEvent *evt, PyTime_t timeout_ns)
}
}
_PyEventRc *
_PyEventRc_New(void)
{
_PyEventRc *erc = (_PyEventRc *)PyMem_RawCalloc(1, sizeof(_PyEventRc));
if (erc != NULL) {
erc->refcount = 1;
}
return erc;
}
void
_PyEventRc_Incref(_PyEventRc *erc)
{
_Py_atomic_add_ssize(&erc->refcount, 1);
}
void
_PyEventRc_Decref(_PyEventRc *erc)
{
if (_Py_atomic_add_ssize(&erc->refcount, -1) == 1) {
PyMem_RawFree(erc);
}
}
static int
unlock_once(_PyOnceFlag *o, int res)
{