gh-122581: Avoid data races when collecting parser statistics (#122694) · python/cpython@ce0d66c

GitHub

Original file line numberDiff line numberDiff line change@@ -21,15 +21,20 @@ extern "C" {

2121struct_parser_runtime_state {

2222#ifdefPy_DEBUG

2323longmemo_statistics[_PYPEGEN_NSTATISTICS];

24+#ifdefPy_GIL_DISABLED

25+PyMutexmutex;

26+#endif

2427#else

2528int_not_used;

2629#endif

2730struct_exprdummy_name;

2831};

29323033_Py_DECLARE_STR(empty, "")

34+#if defined(Py_DEBUG) && defined(Py_GIL_DISABLED)

3135#define_parser_runtime_state_INIT \

3236 { \

37+ .mutex = {0}, \

3338 .dummy_name = { \

3439 .kind = Name_kind, \

3540 .v.Name.id = &_Py_STR(empty), \

@@ -40,6 +45,20 @@ _Py_DECLARE_STR(empty, "")

4045 .end_col_offset = 0, \

4146 }, \

4247 }

48+#else

49+#define_parser_runtime_state_INIT \

50+ { \

51+ .dummy_name = { \

52+ .kind = Name_kind, \

53+ .v.Name.id = &_Py_STR(empty), \

54+ .v.Name.ctx = Load, \

55+ .lineno = 1, \

56+ .col_offset = 0, \

57+ .end_lineno = 1, \

58+ .end_col_offset = 0, \

59+ }, \

60+ }

61+#endif

43624463externstruct_mod*_PyParser_ASTFromString(

4564constchar*str,

Original file line numberDiff line numberDiff line change@@ -296,12 +296,22 @@ _PyPegen_fill_token(Parser *p)

296296#defineNSTATISTICS _PYPEGEN_NSTATISTICS

297297#definememo_statistics _PyRuntime.parser.memo_statistics

298298299+#ifdefPy_GIL_DISABLED

300+#defineMUTEX_LOCK() PyMutex_Lock(&_PyRuntime.parser.mutex)

301+#defineMUTEX_UNLOCK() PyMutex_Unlock(&_PyRuntime.parser.mutex)

302+#else

303+#defineMUTEX_LOCK()

304+#defineMUTEX_UNLOCK()

305+#endif

306+299307void

300308_PyPegen_clear_memo_statistics(void)

301309{

310+MUTEX_LOCK();

302311for (inti=0; i<NSTATISTICS; i++) {

303312memo_statistics[i] =0;

304313 }

314+MUTEX_UNLOCK();

305315}

306316307317PyObject*

@@ -311,18 +321,23 @@ _PyPegen_get_memo_statistics(void)

311321if (ret==NULL) {

312322returnNULL;

313323 }

324+325+MUTEX_LOCK();

314326for (inti=0; i<NSTATISTICS; i++) {

315327PyObject*value=PyLong_FromLong(memo_statistics[i]);

316328if (value==NULL) {

329+MUTEX_UNLOCK();

317330Py_DECREF(ret);

318331returnNULL;

319332 }

320333// PyList_SetItem borrows a reference to value.

321334if (PyList_SetItem(ret, i, value) <0) {

335+MUTEX_UNLOCK();

322336Py_DECREF(ret);

323337returnNULL;

324338 }

325339 }

340+MUTEX_UNLOCK();

326341returnret;

327342}

328343#endif

@@ -348,7 +363,9 @@ _PyPegen_is_memoized(Parser *p, int type, void *pres)

348363if (count <= 0) {

349364count=1;

350365 }

366+MUTEX_LOCK();

351367memo_statistics[type] +=count;

368+MUTEX_UNLOCK();

352369 }

353370#endif

354371p->mark=m->mark;