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_once1. The proposed internal-only API follows C++11's std::call_once, but adapted for C (i.e., error returns and function pointers):
typedefstruct {
uint8_tv;
} _PyOnceFlag;
typedefint_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:
| staticint |
| init_types(structast_state*state) |
| { |
| // init_types() must not be called after _PyAST_Fini() |
| // has been called |
| assert(state->initialized >= 0); |
| |
| if (state->initialized) { |
| return1; |
| } |
Linked PRs
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_once1. The proposed internal-only API follows C++11'sstd::call_once, but adapted for C (i.e., error returns and function pointers):As an example, the
Python-ast.crelies on the GIL and aninitializedvariable to ensure that it is only initialized once:cpython/Python/Python-ast.c
Lines 1126 to 1135 in d61313b
Linked PRs
Footnotes
Also,
pthread_onceand C11'scall_once.std::call_oncesupports error returns, which is important for CPython's use cases. ↩