Closed
Description
Feature or enhancement
Some CPython internals require initialization exactly once. Some of these one time initializations are not thread-safe without the GIL or have data races according to the C11 memory model.
We should add a lightweight, thread-safe one-time initialization API similar to C++11's std::call_once
1. The proposed internal-only API follows C++11's std::call_once
, but adapted for C (i.e., error returns and function pointers):
typedef struct {
uint8_t v;
} _PyOnceFlag;
typedef int _Py_once_fn_t(void *arg);
// Calls `fn` once using `flag`. The `arg` is passed to the call to `fn`.
//
// Returns 1 on success and 0 on failure.
//
// If `fn` returns 1 (success), then subsequent calls immediately return 1.
// If `fn` returns 0 (failure), then subsequent calls will retry the call.
int _PyOnceFlag_CallOnce(_PyOnceFlag *flag, _Py_once_fn_t *fn, void *arg);
As an example, the Python-ast.c
relies on the GIL and an initialized
variable to ensure that it is only initialized once:
Lines 1126 to 1135 in d61313b
Linked PRs
Footnotes
-
Also,
pthread_once
and C11'scall_once
.std::call_once
supports error returns, which is important for CPython's use cases. ↩