mirror of
https://github.com/python/cpython.git
synced 2025-10-08 08:01:55 +00:00
gh-111956: Add thread-safe one-time initialization. (gh-111960)
This commit is contained in:
parent
f66afa395a
commit
446f18a911
11 changed files with 1061 additions and 955 deletions
|
@ -1877,8 +1877,9 @@ new_kwtuple(const char * const *keywords, int total, int pos)
|
|||
}
|
||||
|
||||
static int
|
||||
_parser_init(struct _PyArg_Parser *parser)
|
||||
_parser_init(void *arg)
|
||||
{
|
||||
struct _PyArg_Parser *parser = (struct _PyArg_Parser *)arg;
|
||||
const char * const *keywords = parser->keywords;
|
||||
assert(keywords != NULL);
|
||||
assert(parser->pos == 0 &&
|
||||
|
@ -1889,7 +1890,7 @@ _parser_init(struct _PyArg_Parser *parser)
|
|||
|
||||
int len, pos;
|
||||
if (scan_keywords(keywords, &len, &pos) < 0) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *fname, *custommsg = NULL;
|
||||
|
@ -1898,7 +1899,7 @@ _parser_init(struct _PyArg_Parser *parser)
|
|||
assert(parser->fname == NULL);
|
||||
if (parse_format(parser->format, len, pos,
|
||||
&fname, &custommsg, &min, &max) < 0) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1911,7 +1912,7 @@ _parser_init(struct _PyArg_Parser *parser)
|
|||
if (kwtuple == NULL) {
|
||||
kwtuple = new_kwtuple(keywords, len, pos);
|
||||
if (kwtuple == NULL) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
owned = 1;
|
||||
}
|
||||
|
@ -1925,40 +1926,27 @@ _parser_init(struct _PyArg_Parser *parser)
|
|||
parser->min = min;
|
||||
parser->max = max;
|
||||
parser->kwtuple = kwtuple;
|
||||
parser->initialized = owned ? 1 : -1;
|
||||
parser->is_kwtuple_owned = owned;
|
||||
|
||||
assert(parser->next == NULL);
|
||||
parser->next = _PyRuntime.getargs.static_parsers;
|
||||
_PyRuntime.getargs.static_parsers = parser;
|
||||
return 1;
|
||||
parser->next = _Py_atomic_load_ptr(&_PyRuntime.getargs.static_parsers);
|
||||
do {
|
||||
// compare-exchange updates parser->next on failure
|
||||
} while (_Py_atomic_compare_exchange_ptr(&_PyRuntime.getargs.static_parsers,
|
||||
&parser->next, parser));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parser_init(struct _PyArg_Parser *parser)
|
||||
{
|
||||
// volatile as it can be modified by other threads
|
||||
// and should not be optimized or reordered by compiler
|
||||
if (*((volatile int *)&parser->initialized)) {
|
||||
assert(parser->kwtuple != NULL);
|
||||
return 1;
|
||||
}
|
||||
PyThread_acquire_lock(_PyRuntime.getargs.mutex, WAIT_LOCK);
|
||||
// Check again if another thread initialized the parser
|
||||
// while we were waiting for the lock.
|
||||
if (*((volatile int *)&parser->initialized)) {
|
||||
assert(parser->kwtuple != NULL);
|
||||
PyThread_release_lock(_PyRuntime.getargs.mutex);
|
||||
return 1;
|
||||
}
|
||||
int ret = _parser_init(parser);
|
||||
PyThread_release_lock(_PyRuntime.getargs.mutex);
|
||||
return ret;
|
||||
return _PyOnceFlag_CallOnce(&parser->once, &_parser_init, parser);
|
||||
}
|
||||
|
||||
static void
|
||||
parser_clear(struct _PyArg_Parser *parser)
|
||||
{
|
||||
if (parser->initialized == 1) {
|
||||
if (parser->is_kwtuple_owned) {
|
||||
Py_CLEAR(parser->kwtuple);
|
||||
}
|
||||
}
|
||||
|
@ -2025,7 +2013,7 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!parser_init(parser)) {
|
||||
if (parser_init(parser) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2258,7 +2246,7 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs,
|
|||
args = buf;
|
||||
}
|
||||
|
||||
if (!parser_init(parser)) {
|
||||
if (parser_init(parser) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2435,7 +2423,7 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
|
|||
args = buf;
|
||||
}
|
||||
|
||||
if (!parser_init(parser)) {
|
||||
if (parser_init(parser) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue