|
12 | 12 | #include "pycore_long.h" // _PyLong_AsByteArray() |
13 | 13 | #include "pycore_moduleobject.h" // _PyModule_GetState() |
14 | 14 | #include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() |
| 15 | +#include "pycore_lock.h" // _PyOnceFlag_CallOnce() |
15 | 16 |
|
16 | 17 | #include <stddef.h> // offsetof() |
17 | 18 |
|
@@ -1505,6 +1506,55 @@ static formatdef lilendian_table[] = { |
1505 | 1506 | {0} |
1506 | 1507 | }; |
1507 | 1508 |
|
| 1509 | +/* Ensure endian table optimization happens exactly once across all interpreters */ |
| 1510 | +static _PyOnceFlag endian_tables_init_once = {0}; |
| 1511 | + |
| 1512 | +static int |
| 1513 | +init_endian_tables(void *arg) |
| 1514 | +{ |
| 1515 | + (void)arg; // Unused but required by _Py_once_fn_t signature |
| 1516 | + |
| 1517 | + const formatdef *native = native_table; |
| 1518 | + formatdef *other, *ptr; |
| 1519 | +#if PY_LITTLE_ENDIAN |
| 1520 | + other = lilendian_table; |
| 1521 | +#else |
| 1522 | + other = bigendian_table; |
| 1523 | +#endif |
| 1524 | + /* Scan through the native table, find a matching |
| 1525 | + entry in the endian table and swap in the |
| 1526 | + native implementations whenever possible |
| 1527 | + (64-bit platforms may not have "standard" sizes) */ |
| 1528 | + while (native->format != '\0' && other->format != '\0') { |
| 1529 | + ptr = other; |
| 1530 | + while (ptr->format != '\0') { |
| 1531 | + if (ptr->format == native->format) { |
| 1532 | + /* Match faster when formats are |
| 1533 | + listed in the same order */ |
| 1534 | + if (ptr == other) |
| 1535 | + other++; |
| 1536 | + /* Only use the trick if the |
| 1537 | + size matches */ |
| 1538 | + if (ptr->size != native->size) |
| 1539 | + break; |
| 1540 | + /* Skip float and double, could be |
| 1541 | + "unknown" float format */ |
| 1542 | + if (ptr->format == 'd' || ptr->format == 'f') |
| 1543 | + break; |
| 1544 | + /* Skip _Bool, semantics are different for standard size */ |
| 1545 | + if (ptr->format == '?') |
| 1546 | + break; |
| 1547 | + ptr->pack = native->pack; |
| 1548 | + ptr->unpack = native->unpack; |
| 1549 | + break; |
| 1550 | + } |
| 1551 | + ptr++; |
| 1552 | + } |
| 1553 | + native++; |
| 1554 | + } |
| 1555 | + return 0; |
| 1556 | +} |
| 1557 | + |
1508 | 1558 |
|
1509 | 1559 | static const formatdef * |
1510 | 1560 | whichtable(const char **pfmt) |
@@ -2711,45 +2761,8 @@ _structmodule_exec(PyObject *m) |
2711 | 2761 | } |
2712 | 2762 |
|
2713 | 2763 | /* Check endian and swap in faster functions */ |
2714 | | - { |
2715 | | - const formatdef *native = native_table; |
2716 | | - formatdef *other, *ptr; |
2717 | | -#if PY_LITTLE_ENDIAN |
2718 | | - other = lilendian_table; |
2719 | | -#else |
2720 | | - other = bigendian_table; |
2721 | | -#endif |
2722 | | - /* Scan through the native table, find a matching |
2723 | | - entry in the endian table and swap in the |
2724 | | - native implementations whenever possible |
2725 | | - (64-bit platforms may not have "standard" sizes) */ |
2726 | | - while (native->format != '\0' && other->format != '\0') { |
2727 | | - ptr = other; |
2728 | | - while (ptr->format != '\0') { |
2729 | | - if (ptr->format == native->format) { |
2730 | | - /* Match faster when formats are |
2731 | | - listed in the same order */ |
2732 | | - if (ptr == other) |
2733 | | - other++; |
2734 | | - /* Only use the trick if the |
2735 | | - size matches */ |
2736 | | - if (ptr->size != native->size) |
2737 | | - break; |
2738 | | - /* Skip float and double, could be |
2739 | | - "unknown" float format */ |
2740 | | - if (ptr->format == 'd' || ptr->format == 'f') |
2741 | | - break; |
2742 | | - /* Skip _Bool, semantics are different for standard size */ |
2743 | | - if (ptr->format == '?') |
2744 | | - break; |
2745 | | - ptr->pack = native->pack; |
2746 | | - ptr->unpack = native->unpack; |
2747 | | - break; |
2748 | | - } |
2749 | | - ptr++; |
2750 | | - } |
2751 | | - native++; |
2752 | | - } |
| 2764 | + if (_PyOnceFlag_CallOnce(&endian_tables_init_once, init_endian_tables, NULL) == -1) { |
| 2765 | + return -1; |
2753 | 2766 | } |
2754 | 2767 |
|
2755 | 2768 | /* Add some symbolic constants to the module */ |
|
0 commit comments