Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
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'sstd::call_once1. The proposed internal-only API follows C++11'sstd::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, thePython-ast.c relies on the GIL and aninitialized variable to ensure that it is only initialized once:
Lines 1126 to 1135 ind61313b
| 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
Footnotes
Also,
pthread_onceand C11'scall_once.std::call_oncesupports error returns, which is important for CPython's use cases.↩