diff options
Diffstat (limited to 'Python/getargs.c')
-rw-r--r-- | Python/getargs.c | 46 |
1 files changed, 17 insertions, 29 deletions
diff --git a/Python/getargs.c b/Python/getargs.c index 5a12ca8..4f873e5 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -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; } |