diff options
| author | Mark Adler <git@madler.net> | 2026-01-05 01:15:38 -0600 |
|---|---|---|
| committer | Mark Adler <git@madler.net> | 2026-01-05 15:03:04 -0600 |
| commit | c267ef7306fe9fc1399833e3556cd9798dec2eb0 (patch) | |
| tree | bc18574b8ea4fc37befdf0174fb5f04472911f6f /crc32.c | |
| parent | 916dc1ac351795c9bf86a3d19c3667b014b9d28e (diff) | |
| download | zlib-c267ef7306fe9fc1399833e3556cd9798dec2eb0.tar.gz zlib-c267ef7306fe9fc1399833e3556cd9798dec2eb0.tar.bz2 zlib-c267ef7306fe9fc1399833e3556cd9798dec2eb0.zip | |
Use atomics to build inflate fixed tables once.
This moves the once code from crc32.c to zutil.c, and uses it also
for building the inflate fixed tables when BUILDFIXED is defined.
The fixed tables are now housed in inftrees.c, shared by inflate.c
and infback.c. The once() function is now external, and so is
renamed to z_once() to avoid name collisions.
If either BUILDFIXED or DYNAMIC_CRC_TABLE is defined, and atomics
are not available, then a warning is issued noting that zlib is not
thread-safe.
Diffstat (limited to 'crc32.c')
| -rw-r--r-- | crc32.c | 87 |
1 files changed, 6 insertions, 81 deletions
| @@ -204,83 +204,8 @@ local z_crc_t FAR crc_table[256]; | |||
| 204 | local void write_table64(FILE *, const z_word_t FAR *, int); | 204 | local void write_table64(FILE *, const z_word_t FAR *, int); |
| 205 | #endif /* MAKECRCH */ | 205 | #endif /* MAKECRCH */ |
| 206 | 206 | ||
| 207 | /* | ||
| 208 | Define a once() function depending on the availability of atomics. If this is | ||
| 209 | compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in | ||
| 210 | multiple threads, and if atomics are not available, then get_crc_table() must | ||
| 211 | be called to initialize the tables and must return before any threads are | ||
| 212 | allowed to compute or combine CRCs. | ||
| 213 | */ | ||
| 214 | |||
| 215 | /* Definition of once functionality. */ | ||
| 216 | typedef struct once_s once_t; | ||
| 217 | |||
| 218 | /* Check for the availability of atomics. */ | ||
| 219 | #if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ | ||
| 220 | !defined(__STDC_NO_ATOMICS__) | ||
| 221 | |||
| 222 | #include <stdatomic.h> | ||
| 223 | |||
| 224 | /* Structure for once(), which must be initialized with ONCE_INIT. */ | ||
| 225 | struct once_s { | ||
| 226 | atomic_flag begun; | ||
| 227 | atomic_int done; | ||
| 228 | }; | ||
| 229 | #define ONCE_INIT {ATOMIC_FLAG_INIT, 0} | ||
| 230 | |||
| 231 | /* | ||
| 232 | Run the provided init() function exactly once, even if multiple threads | ||
| 233 | invoke once() at the same time. The state must be a once_t initialized with | ||
| 234 | ONCE_INIT. | ||
| 235 | */ | ||
| 236 | local void once(once_t *state, void (*init)(void)) { | ||
| 237 | if (!atomic_load(&state->done)) { | ||
| 238 | if (atomic_flag_test_and_set(&state->begun)) | ||
| 239 | while (!atomic_load(&state->done)) | ||
| 240 | ; | ||
| 241 | else { | ||
| 242 | init(); | ||
| 243 | atomic_store(&state->done, 1); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | #else /* no atomics */ | ||
| 249 | |||
| 250 | /* Structure for once(), which must be initialized with ONCE_INIT. */ | ||
| 251 | struct once_s { | ||
| 252 | volatile int begun; | ||
| 253 | volatile int done; | ||
| 254 | }; | ||
| 255 | #define ONCE_INIT {0, 0} | ||
| 256 | |||
| 257 | /* Test and set. Alas, not atomic, but tries to minimize the period of | ||
| 258 | vulnerability. */ | ||
| 259 | local int test_and_set(int volatile *flag) { | ||
| 260 | int was; | ||
| 261 | |||
| 262 | was = *flag; | ||
| 263 | *flag = 1; | ||
| 264 | return was; | ||
| 265 | } | ||
| 266 | |||
| 267 | /* Run the provided init() function once. This is not thread-safe. */ | ||
| 268 | local void once(once_t *state, void (*init)(void)) { | ||
| 269 | if (!state->done) { | ||
| 270 | if (test_and_set(&state->begun)) | ||
| 271 | while (!state->done) | ||
| 272 | ; | ||
| 273 | else { | ||
| 274 | init(); | ||
| 275 | state->done = 1; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | #endif | ||
| 281 | |||
| 282 | /* State for once(). */ | 207 | /* State for once(). */ |
| 283 | local once_t made = ONCE_INIT; | 208 | local z_once_t made = Z_ONCE_INIT; |
| 284 | 209 | ||
| 285 | /* | 210 | /* |
| 286 | Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: | 211 | Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: |
| @@ -548,7 +473,7 @@ local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { | |||
| 548 | */ | 473 | */ |
| 549 | const z_crc_t FAR * ZEXPORT get_crc_table(void) { | 474 | const z_crc_t FAR * ZEXPORT get_crc_table(void) { |
| 550 | #ifdef DYNAMIC_CRC_TABLE | 475 | #ifdef DYNAMIC_CRC_TABLE |
| 551 | once(&made, make_crc_table); | 476 | z_once(&made, make_crc_table); |
| 552 | #endif /* DYNAMIC_CRC_TABLE */ | 477 | #endif /* DYNAMIC_CRC_TABLE */ |
| 553 | return (const z_crc_t FAR *)crc_table; | 478 | return (const z_crc_t FAR *)crc_table; |
| 554 | } | 479 | } |
| @@ -585,7 +510,7 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, | |||
| 585 | if (buf == Z_NULL) return 0; | 510 | if (buf == Z_NULL) return 0; |
| 586 | 511 | ||
| 587 | #ifdef DYNAMIC_CRC_TABLE | 512 | #ifdef DYNAMIC_CRC_TABLE |
| 588 | once(&made, make_crc_table); | 513 | z_once(&made, make_crc_table); |
| 589 | #endif /* DYNAMIC_CRC_TABLE */ | 514 | #endif /* DYNAMIC_CRC_TABLE */ |
| 590 | 515 | ||
| 591 | /* Pre-condition the CRC */ | 516 | /* Pre-condition the CRC */ |
| @@ -697,7 +622,7 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, | |||
| 697 | if (buf == Z_NULL) return 0; | 622 | if (buf == Z_NULL) return 0; |
| 698 | 623 | ||
| 699 | #ifdef DYNAMIC_CRC_TABLE | 624 | #ifdef DYNAMIC_CRC_TABLE |
| 700 | once(&made, make_crc_table); | 625 | z_once(&made, make_crc_table); |
| 701 | #endif /* DYNAMIC_CRC_TABLE */ | 626 | #endif /* DYNAMIC_CRC_TABLE */ |
| 702 | 627 | ||
| 703 | /* Pre-condition the CRC */ | 628 | /* Pre-condition the CRC */ |
| @@ -1022,7 +947,7 @@ uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { | |||
| 1022 | if (len2 < 0) | 947 | if (len2 < 0) |
| 1023 | return 0; | 948 | return 0; |
| 1024 | #ifdef DYNAMIC_CRC_TABLE | 949 | #ifdef DYNAMIC_CRC_TABLE |
| 1025 | once(&made, make_crc_table); | 950 | z_once(&made, make_crc_table); |
| 1026 | #endif /* DYNAMIC_CRC_TABLE */ | 951 | #endif /* DYNAMIC_CRC_TABLE */ |
| 1027 | return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); | 952 | return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); |
| 1028 | } | 953 | } |
| @@ -1037,7 +962,7 @@ uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { | |||
| 1037 | if (len2 < 0) | 962 | if (len2 < 0) |
| 1038 | return 0; | 963 | return 0; |
| 1039 | #ifdef DYNAMIC_CRC_TABLE | 964 | #ifdef DYNAMIC_CRC_TABLE |
| 1040 | once(&made, make_crc_table); | 965 | z_once(&made, make_crc_table); |
| 1041 | #endif /* DYNAMIC_CRC_TABLE */ | 966 | #endif /* DYNAMIC_CRC_TABLE */ |
| 1042 | return x2nmodp(len2, 3); | 967 | return x2nmodp(len2, 3); |
| 1043 | } | 968 | } |
