From 2209f63bda59360dd2fe765b71f89d84955ddd24 Mon Sep 17 00:00:00 2001 From: Mark Adler Date: Sun, 18 Jan 2026 10:18:46 -0800 Subject: Make z_once() local to avoid conditional external symbols. --- zutil.h | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 16 deletions(-) (limited to 'zutil.h') diff --git a/zutil.h b/zutil.h index 94fa1aff..acc1907f 100644 --- a/zutil.h +++ b/zutil.h @@ -254,30 +254,74 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif -#if defined(BUILDFIXED) || defined(DYNAMIC_CRC_TABLE) -/* Structure for z_once(), which must be initialized with Z_ONCE_INIT. */ -typedef struct z_once_s z_once_t; -void ZLIB_INTERNAL z_once(z_once_t *state, void (*init)(void)); +#ifdef Z_ONCE +/* + Create a local z_once() function depending on the availability of atomics. + */ + +/* Check for the availability of atomics. */ #if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ !defined(__STDC_NO_ATOMICS__) + #include -struct z_once_s { +typedef struct { atomic_flag begun; atomic_int done; -}; +} z_once_t; #define Z_ONCE_INIT {ATOMIC_FLAG_INIT, 0} -#else /* no atomics! */ -struct z_once_s { + +/* + Run the provided init() function exactly once, even if multiple threads + invoke once() at the same time. The state must be a once_t initialized with + Z_ONCE_INIT. + */ +local void z_once(z_once_t *state, void (*init)(void)) { + if (!atomic_load(&state->done)) { + if (atomic_flag_test_and_set(&state->begun)) + while (!atomic_load(&state->done)) + ; + else { + init(); + atomic_store(&state->done, 1); + } + } +} + +#else /* no atomics */ + +#warning zlib not thread-safe + +typedef struct z_once_s { volatile int begun; volatile int done; -}; +} z_once_t; #define Z_ONCE_INIT {0, 0} -#endif -#endif + +/* Test and set. Alas, not atomic, but tries to limit the period of + vulnerability. */ +local int test_and_set(int volatile *flag) { + int was; + + was = *flag; + *flag = 1; + return was; +} + +/* Run the provided init() function once. This is not thread-safe. */ +local void z_once(z_once_t *state, void (*init)(void)) { + if (!state->done) { + if (test_and_set(&state->begun)) + while (!state->done) + ; + else { + init(); + state->done = 1; + } + } +} + +#endif /* ?atomics */ + +#endif /* Z_ONCE */ #endif /* ZUTIL_H */ -- cgit v1.2.3-55-g6feb