@@ -1972,13 +1972,11 @@ new_kwtuple(const char * const *keywords, int total, int pos)
1972
1972
static int
1973
1973
_parser_init (struct _PyArg_Parser * parser )
1974
1974
{
1975
+ // We allow threads to potentially race scanning the keywords
1976
+ // and format, since these are read-only. Modifications to the
1977
+ // _PyArg_Parser are protected by a _PyOnceFlag below.
1975
1978
const char * const * keywords = parser -> keywords ;
1976
1979
assert (keywords != NULL );
1977
- assert (parser -> pos == 0 &&
1978
- (parser -> format == NULL || parser -> fname == NULL ) &&
1979
- parser -> custom_msg == NULL &&
1980
- parser -> min == 0 &&
1981
- parser -> max == 0 );
1982
1980
1983
1981
int len , pos ;
1984
1982
if (scan_keywords (keywords , & len , & pos ) < 0 ) {
@@ -2012,6 +2010,18 @@ _parser_init(struct _PyArg_Parser *parser)
2012
2010
owned = 0 ;
2013
2011
}
2014
2012
2013
+ if (!_PyBeginOnce (& parser -> once )) {
2014
+ // someone else initialized the parser
2015
+ Py_DECREF (kwtuple );
2016
+ return 1 ;
2017
+ }
2018
+
2019
+ assert (parser -> pos == 0 &&
2020
+ (parser -> format == NULL || parser -> fname == NULL ) &&
2021
+ parser -> custom_msg == NULL &&
2022
+ parser -> min == 0 &&
2023
+ parser -> max == 0 );
2024
+
2015
2025
parser -> pos = pos ;
2016
2026
parser -> fname = fname ;
2017
2027
parser -> custom_msg = custommsg ;
@@ -2021,31 +2031,22 @@ _parser_init(struct _PyArg_Parser *parser)
2021
2031
parser -> initialized = owned ? 1 : -1 ;
2022
2032
2023
2033
assert (parser -> next == NULL );
2024
- parser -> next = _PyRuntime .getargs .static_parsers ;
2025
- _PyRuntime .getargs .static_parsers = parser ;
2034
+ struct _PyArg_Parser * next ;
2035
+ do {
2036
+ next = _Py_atomic_load_ptr (& _PyRuntime .getargs .static_parsers );
2037
+ parser -> next = next ;
2038
+ } while (!_Py_atomic_compare_exchange_ptr (& _PyRuntime .getargs .static_parsers , next , parser ));
2039
+ _PyEndOnce (& parser -> once );
2026
2040
return 1 ;
2027
2041
}
2028
2042
2029
2043
static int
2030
2044
parser_init (struct _PyArg_Parser * parser )
2031
2045
{
2032
- // volatile as it can be modified by other threads
2033
- // and should not be optimized or reordered by compiler
2034
- if (* ((volatile int * )& parser -> initialized )) {
2035
- assert (parser -> kwtuple != NULL );
2036
- return 1 ;
2037
- }
2038
- PyThread_acquire_lock (_PyRuntime .getargs .mutex , WAIT_LOCK );
2039
- // Check again if another thread initialized the parser
2040
- // while we were waiting for the lock.
2041
- if (* ((volatile int * )& parser -> initialized )) {
2042
- assert (parser -> kwtuple != NULL );
2043
- PyThread_release_lock (_PyRuntime .getargs .mutex );
2046
+ if (_PyOnce_Initialized (& parser -> once )) {
2044
2047
return 1 ;
2045
2048
}
2046
- int ret = _parser_init (parser );
2047
- PyThread_release_lock (_PyRuntime .getargs .mutex );
2048
- return ret ;
2049
+ return _parser_init (parser );
2049
2050
}
2050
2051
2051
2052
static void
0 commit comments