aboutsummaryrefslogtreecommitdiff
path: root/crc32.c
diff options
context:
space:
mode:
authorMark Adler <git@madler.net>2026-01-05 01:15:38 -0600
committerMark Adler <git@madler.net>2026-01-05 15:03:04 -0600
commitc267ef7306fe9fc1399833e3556cd9798dec2eb0 (patch)
treebc18574b8ea4fc37befdf0174fb5f04472911f6f /crc32.c
parent916dc1ac351795c9bf86a3d19c3667b014b9d28e (diff)
downloadzlib-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.c87
1 files changed, 6 insertions, 81 deletions
diff --git a/crc32.c b/crc32.c
index 33d8c79..630049f 100644
--- a/crc32.c
+++ b/crc32.c
@@ -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. */
216typedef 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. */
225struct 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 */
236local 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. */
251struct 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. */
259local 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. */
268local 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(). */
283local once_t made = ONCE_INIT; 208local 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 */
549const z_crc_t FAR * ZEXPORT get_crc_table(void) { 474const 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}