diff options
Diffstat (limited to 'crc32.c')
-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 | } |