diff options
| author | Mark Adler <madler@alumni.caltech.edu> | 2018-12-26 13:50:27 -0800 |
|---|---|---|
| committer | Mark Adler <madler@alumni.caltech.edu> | 2018-12-26 13:50:27 -0800 |
| commit | 7c0c75e990ca5395139c148f120042048b0ce091 (patch) | |
| tree | a852f93466339e316d7df629ec198082f50c92b7 | |
| parent | f8719f5ae5acdc31d3794ddfea8ac963359de41e (diff) | |
| download | zlib-7c0c75e990ca5395139c148f120042048b0ce091.tar.gz zlib-7c0c75e990ca5395139c148f120042048b0ce091.tar.bz2 zlib-7c0c75e990ca5395139c148f120042048b0ce091.zip | |
Use atomic test and set, if available, for dynamic CRC tables.
| -rw-r--r-- | crc32.c | 154 |
1 files changed, 112 insertions, 42 deletions
| @@ -112,7 +112,6 @@ local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); | |||
| 112 | 112 | ||
| 113 | #ifdef DYNAMIC_CRC_TABLE | 113 | #ifdef DYNAMIC_CRC_TABLE |
| 114 | 114 | ||
| 115 | local volatile int crc_table_empty = 1; | ||
| 116 | local z_crc_t FAR crc_table[256]; | 115 | local z_crc_t FAR crc_table[256]; |
| 117 | local z_crc_t FAR x2n_table[32]; | 116 | local z_crc_t FAR x2n_table[32]; |
| 118 | local void make_crc_table OF((void)); | 117 | local void make_crc_table OF((void)); |
| @@ -129,6 +128,94 @@ local void make_crc_table OF((void)); | |||
| 129 | #endif /* MAKECRCH */ | 128 | #endif /* MAKECRCH */ |
| 130 | 129 | ||
| 131 | /* | 130 | /* |
| 131 | Define a once() function depending on the availability of atomics. If this is | ||
| 132 | compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in | ||
| 133 | multiple threads, and if atomics are not available, then get_crc_table() must | ||
| 134 | be called to initialize the tables and must return before any threads are | ||
| 135 | allowed to compute or combine CRCs. | ||
| 136 | */ | ||
| 137 | |||
| 138 | /* Definition of once functionality. */ | ||
| 139 | typedef struct once_s once_t; | ||
| 140 | local void once OF((once_t *, void (*)(void))); | ||
| 141 | |||
| 142 | /* Check for the availability of atomics. */ | ||
| 143 | #if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ | ||
| 144 | !defined(__STDC_NO_ATOMICS__) | ||
| 145 | |||
| 146 | #include <stdatomic.h> | ||
| 147 | |||
| 148 | /* Structure for once(), which must be initialized with ONCE_INIT. */ | ||
| 149 | struct once_s { | ||
| 150 | atomic_flag begun; | ||
| 151 | atomic_int done; | ||
| 152 | }; | ||
| 153 | #define ONCE_INIT {ATOMIC_FLAG_INIT, 0} | ||
| 154 | |||
| 155 | /* | ||
| 156 | Run the provided init() function exactly once, even if multiple threads | ||
| 157 | invoke once() at the same time. The state must be a once_t initialized with | ||
| 158 | ONCE_INIT. | ||
| 159 | */ | ||
| 160 | local void once(state, init) | ||
| 161 | once_t *state; | ||
| 162 | void (*init)(void); | ||
| 163 | { | ||
| 164 | if (!atomic_load(&state->done)) { | ||
| 165 | if (atomic_flag_test_and_set(&state->begun)) | ||
| 166 | while (!atomic_load(&state->done)) | ||
| 167 | ; | ||
| 168 | else { | ||
| 169 | init(); | ||
| 170 | atomic_store(&state->done, 1); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | #else /* no atomics */ | ||
| 176 | |||
| 177 | /* Structure for once(), which must be initialized with ONCE_INIT. */ | ||
| 178 | struct once_s { | ||
| 179 | volatile int begun; | ||
| 180 | volatile int done; | ||
| 181 | }; | ||
| 182 | #define ONCE_INIT {0, 0} | ||
| 183 | |||
| 184 | /* Test and set. Alas, not atomic, but tries to minimize the period of | ||
| 185 | vulnerability. */ | ||
| 186 | local int test_and_set OF((int volatile *)); | ||
| 187 | local int test_and_set(flag) | ||
| 188 | int volatile *flag; | ||
| 189 | { | ||
| 190 | int was; | ||
| 191 | |||
| 192 | was = *flag; | ||
| 193 | *flag = 1; | ||
| 194 | return was; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* Run the provided init() function once. This is not thread-safe. */ | ||
| 198 | local void once(state, init) | ||
| 199 | once_t *state; | ||
| 200 | void (*init)(void); | ||
| 201 | { | ||
| 202 | if (!state->done) { | ||
| 203 | if (test_and_set(&state->begun)) | ||
| 204 | while (!state->done) | ||
| 205 | ; | ||
| 206 | else { | ||
| 207 | init(); | ||
| 208 | state->done = 1; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | #endif | ||
| 214 | |||
| 215 | /* State for once(). */ | ||
| 216 | local once_t made = ONCE_INIT; | ||
| 217 | |||
| 218 | /* | ||
| 132 | Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: | 219 | Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: |
| 133 | x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. | 220 | x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. |
| 134 | 221 | ||
| @@ -155,45 +242,31 @@ local void make_crc_table OF((void)); | |||
| 155 | 242 | ||
| 156 | local void make_crc_table() | 243 | local void make_crc_table() |
| 157 | { | 244 | { |
| 245 | unsigned i, j, n; | ||
| 158 | z_crc_t p; | 246 | z_crc_t p; |
| 159 | static volatile int first = 1; /* flag to limit concurrent making */ | 247 | |
| 160 | 248 | /* initialize the CRC of bytes tables */ | |
| 161 | /* See if another task is already doing this (not thread-safe, but better | 249 | for (i = 0; i < 256; i++) { |
| 162 | than nothing -- significantly reduces duration of vulnerability in | 250 | p = i; |
| 163 | case the advice about DYNAMIC_CRC_TABLE is ignored) */ | 251 | for (j = 0; j < 8; j++) |
| 164 | if (first) { | 252 | p = p & 1 ? (p >> 1) ^ POLY : p >> 1; |
| 165 | unsigned i, j, n; | 253 | crc_table[i] = p; |
| 166 | first = 0; | ||
| 167 | |||
| 168 | /* initialize the CRC of bytes tables */ | ||
| 169 | for (i = 0; i < 256; i++) { | ||
| 170 | p = i; | ||
| 171 | for (j = 0; j < 8; j++) | ||
| 172 | p = p & 1 ? (p >> 1) ^ POLY : p >> 1; | ||
| 173 | crc_table[i] = p; | ||
| 174 | #ifdef W | 254 | #ifdef W |
| 175 | crc_big_table[i] = byte_swap(p); | 255 | crc_big_table[i] = byte_swap(p); |
| 176 | #endif | 256 | #endif |
| 177 | } | 257 | } |
| 258 | |||
| 259 | /* initialize the x^2^n mod p(x) table */ | ||
| 260 | p = (z_crc_t)1 << 30; /* x^1 */ | ||
| 261 | x2n_table[0] = p; | ||
| 262 | for (n = 1; n < 32; n++) | ||
| 263 | x2n_table[n] = p = multmodp(p, p); | ||
| 178 | 264 | ||
| 179 | /* initialize the x^2^n mod p(x) table */ | ||
| 180 | p = (z_crc_t)1 << 30; /* x^1 */ | ||
| 181 | x2n_table[0] = p; | ||
| 182 | for (n = 1; n < 32; n++) | ||
| 183 | x2n_table[n] = p = multmodp(p, p); | ||
| 184 | #ifdef W | 265 | #ifdef W |
| 185 | /* initialize the braiding tables -- needs x2n_table[] */ | 266 | /* initialize the braiding tables -- needs x2n_table[] */ |
| 186 | braid(crc_braid_table, crc_braid_big_table, N, W); | 267 | braid(crc_braid_table, crc_braid_big_table, N, W); |
| 187 | #endif | 268 | #endif |
| 188 | 269 | ||
| 189 | /* mark tables as complete, in case someone else is waiting */ | ||
| 190 | crc_table_empty = 0; | ||
| 191 | } | ||
| 192 | else { /* not first */ | ||
| 193 | /* wait for the other guy to finish (not efficient, but rare) */ | ||
| 194 | while (crc_table_empty) | ||
| 195 | ; | ||
| 196 | } | ||
| 197 | #ifdef MAKECRCH | 270 | #ifdef MAKECRCH |
| 198 | { | 271 | { |
| 199 | /* | 272 | /* |
| @@ -532,13 +605,13 @@ local z_word_t crc_word_big(data) | |||
| 532 | #endif /* W */ | 605 | #endif /* W */ |
| 533 | 606 | ||
| 534 | /* ========================================================================= | 607 | /* ========================================================================= |
| 535 | * This function can be used by asm versions of crc32() | 608 | * This function can be used by asm versions of crc32(), and to force the |
| 609 | * generation of the CRC tables in a threaded application. | ||
| 536 | */ | 610 | */ |
| 537 | const z_crc_t FAR * ZEXPORT get_crc_table() | 611 | const z_crc_t FAR * ZEXPORT get_crc_table() |
| 538 | { | 612 | { |
| 539 | #ifdef DYNAMIC_CRC_TABLE | 613 | #ifdef DYNAMIC_CRC_TABLE |
| 540 | if (crc_table_empty) | 614 | once(&made, make_crc_table); |
| 541 | make_crc_table(); | ||
| 542 | #endif /* DYNAMIC_CRC_TABLE */ | 615 | #endif /* DYNAMIC_CRC_TABLE */ |
| 543 | return (const z_crc_t FAR *)crc_table; | 616 | return (const z_crc_t FAR *)crc_table; |
| 544 | } | 617 | } |
| @@ -553,8 +626,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) | |||
| 553 | if (buf == Z_NULL) return 0; | 626 | if (buf == Z_NULL) return 0; |
| 554 | 627 | ||
| 555 | #ifdef DYNAMIC_CRC_TABLE | 628 | #ifdef DYNAMIC_CRC_TABLE |
| 556 | if (crc_table_empty) | 629 | once(&made, make_crc_table); |
| 557 | make_crc_table(); | ||
| 558 | #endif /* DYNAMIC_CRC_TABLE */ | 630 | #endif /* DYNAMIC_CRC_TABLE */ |
| 559 | 631 | ||
| 560 | /* Pre-condition the CRC */ | 632 | /* Pre-condition the CRC */ |
| @@ -882,8 +954,7 @@ uLong ZEXPORT crc32_combine64(crc1, crc2, len2) | |||
| 882 | z_off64_t len2; | 954 | z_off64_t len2; |
| 883 | { | 955 | { |
| 884 | #ifdef DYNAMIC_CRC_TABLE | 956 | #ifdef DYNAMIC_CRC_TABLE |
| 885 | if (crc_table_empty) | 957 | once(&made, make_crc_table); |
| 886 | make_crc_table(); | ||
| 887 | #endif /* DYNAMIC_CRC_TABLE */ | 958 | #endif /* DYNAMIC_CRC_TABLE */ |
| 888 | return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; | 959 | return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; |
| 889 | } | 960 | } |
| @@ -902,8 +973,7 @@ uLong ZEXPORT crc32_combine_gen64(len2) | |||
| 902 | z_off64_t len2; | 973 | z_off64_t len2; |
| 903 | { | 974 | { |
| 904 | #ifdef DYNAMIC_CRC_TABLE | 975 | #ifdef DYNAMIC_CRC_TABLE |
| 905 | if (crc_table_empty) | 976 | once(&made, make_crc_table); |
| 906 | make_crc_table(); | ||
| 907 | #endif /* DYNAMIC_CRC_TABLE */ | 977 | #endif /* DYNAMIC_CRC_TABLE */ |
| 908 | return x2nmodp(len2, 3); | 978 | return x2nmodp(len2, 3); |
| 909 | } | 979 | } |
