Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: openssl/crypto/lhash/lhash.c

Issue 59793002: sh implementation to avoid unwanted resizes during iteration. (Closed) Base URL: http://src.chromium.org/chrome/trunk/deps/third_party/openssl/
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « openssl/crypto/lhash/lhash.h ('k') | openssl/crypto/objects/o_names.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* crypto/lhash/lhash.c */ 1 /* crypto/lhash/lhash.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
5 * This package is an SSL implementation written 5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com). 6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL. 7 * The implementation was written so as to conform with Netscapes SSL.
8 * 8 *
9 * This library is free for commercial and non-commercial use as long as 9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to. The following conditions 10 * the following conditions are aheared to. The following conditions
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91 87 * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91
88 * 88 *
89 * 1.3 eay - Fixed a few lint problems 19/3/1991 89 * 1.3 eay - Fixed a few lint problems 19/3/1991
90 * 90 *
91 * 1.2 eay - Fixed lh_doall problem 13/3/1991 91 * 1.2 eay - Fixed lh_doall problem 13/3/1991
92 * 92 *
93 * 1.1 eay - Added lh_doall 93 * 1.1 eay - Added lh_doall
94 * 94 *
95 * 1.0 eay - First version 95 * 1.0 eay - First version
96 */ 96 */
97 #include <limits.h>
97 #include <stdio.h> 98 #include <stdio.h>
98 #include <string.h> 99 #include <string.h>
99 #include <stdlib.h> 100 #include <stdlib.h>
100 #include <openssl/crypto.h> 101 #include <openssl/crypto.h>
101 #include <openssl/lhash.h> 102 #include <openssl/lhash.h>
102 103
103 const char lh_version[]="lhash" OPENSSL_VERSION_PTEXT; 104 const char lh_version[]="lhash" OPENSSL_VERSION_PTEXT;
104 105
105 #undef MIN_NODES 106 #undef MIN_NODES
106 #define MIN_NODES 16 107 #define MIN_NODES 16
107 #define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */ 108 #define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */
108 #define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */ 109 #define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */
109 110
111 /* Maximum number of nodes to guarantee the load computations don't overflow */
112 #define MAX_LOAD_ITEMS (UINT_MAX / LH_LOAD_MULT)
113
114 /* The field 'iteration_state' is used to hold data to ensure that a hash
115 * table is not resized during an 'insert' or 'delete' operation performed
116 * within a lh_doall/lh_doall_arg call.
117 *
118 * Conceptually, this records two things:
119 *
120 * - A 'depth' count, which is incremented at the start of lh_doall*,
121 * and decremented just before it returns.
122 *
123 * - A 'mutated' boolean flag, which is set in lh_insert() or lh_delete()
124 * when the operation is performed with a non-0 depth.
125 *
126 * The following are helper macros to handle this state in a more explicit
127 * way.
128 */
129
130 /* Reset the iteration state to its defaults. */
131 #define LH_ITERATION_RESET(lh) do { \
132 (lh)->iteration_state = 0; \
133 } while (0)
134
135 /* Returns 1 if the hash table is currently being iterated on, 0 otherwise. */
136 #define LH_ITERATION_IS_ACTIVE(lh) ((lh)->iteration_state >= 2)
137
138 /* Increment iteration depth. This should always be followed by a paired call
139 * to LH_ITERATION_DECREMENT_DEPTH(). */
140 #define LH_ITERATION_INCREMENT_DEPTH(lh) do { \
141 (lh)->iteration_state += 2; \
142 } while (0)
143
144 /* Decrement iteration depth. This should always be called after a paired call
145 * to LH_ITERATION_INCREMENT_DEPTH(). */
146 #define LH_ITERATION_DECREMENT_DEPTH(lh) do { \
147 (lh)->iteration_state -= 2; \
148 } while (0)
149
150 /* Return 1 if the iteration 'mutated' flag is set, 0 otherwise. */
151 #define LH_ITERATION_IS_MUTATED(lh) (((lh)->iteration_state & 1) != 0)
152
153 /* Set the iteration 'mutated' flag to 1. LH_ITERATION_RESET() to reset it. */
154 #define LH_ITERATION_SET_MUTATED(lh) do { \
155 (lh)->iteration_state |= 1; \
156 } while (0)
157
158 /* This macro returns 1 if the hash table should be expanded due to its current
159 * load, or 0 otherwise. The exact comparison to be performed is expressed by
160 * the mathematical expression (where '//' denotes division over real numbers):
161 *
162 * (num_items // num_nodes) >= (up_load // LOAD_MULT) or
163 * (num_items * LOAD_MULT // num_nodes) >= up_load.
164 *
165 * Given that the C language operator '/' implements integer division, i.e:
166 * a // b == (a / b) + epsilon (with 0 <= epsilon < 1, for positive a & b)
167 *
168 * This can be rewritten as:
169 * (num_items * LOAD_MULT / num_nodes) + epsilon >= up_load
170 * (num_items * LOAD_MULT / num_nodes) - up_load >= - epsilon
171 *
172 * Let's call 'A' the left-hand side of the equation above, it is an integer
173 * and:
174 * - If A >= 0, the expression is true for any value of epsilon.
175 * - If A <= -1, the expression is also true for any value of epsilon.
176 *
177 * In other words, this is equivalent to 'A >= 0', or:
178 * (num_items * LOAD_MULT / num_nodes) >= up_load
179 */
180 #define LH_SHOULD_EXPAND(lh) \
181 ((lh)->num_items < MAX_LOAD_ITEMS && \
182 (((lh)->num_items*LH_LOAD_MULT/(lh)->num_nodes) >= (lh)->up_load))
183
184 /* This macro returns 1 if the hash table should be contracted due to its
185 * current load, or 0 otherwise. Abbreviated computations are:
186 *
187 * (num_items // num_nodes) <= (down_load // LOAD_MULT)
188 * (num_items * LOAD_MULT // num_nodes) <= down_load
189 * (num_items * LOAD_MULT / num_nodes) + epsilon <= down_load
190 * (num_items * LOAD_MULT / num_nodes) - down_load <= -epsilon
191 *
192 * Let's call 'B' the left-hand side of the equation above:
193 * - If B <= -1, the expression is true for any value of epsilon.
194 * - If B >= 1, the expression is false for any value of epsilon.
195 * - If B == 0, the expression is true for 'epsilon == 0', and false
196 * otherwise, which is problematic.
197 *
198 * To work around this problem, while keeping the code simple, just change
199 * the initial expression to use a strict inequality, i.e.:
200 *
201 * (num_items // num_nodes) < (down_load // LOAD_MULT)
202 *
203 * Which leads to:
204 * (num_items * LOAD_MULT / num_nodes) - down_load < -epsilon
205 *
206 * Then:
207 * - If 'B <= -1', the expression is true for any value of epsilon.
208 * - If 'B' >= 0, the expression is false for any value of epsilon,
209 *
210 * In other words, this is equivalent to 'B < 0', or:
211 * (num_items * LOAD_MULT / num_nodes) < down_load
212 */
213 #define LH_SHOULD_CONTRACT(lh) \
214 (((lh)->num_nodes > MIN_NODES) && \
215 ((lh)->num_items < MAX_LOAD_ITEMS && \
216 ((lh)->num_items*LH_LOAD_MULT/(lh)->num_nodes) < (lh)->down_load))
217
110 static void expand(_LHASH *lh); 218 static void expand(_LHASH *lh);
111 static void contract(_LHASH *lh); 219 static void contract(_LHASH *lh);
112 static LHASH_NODE **getrn(_LHASH *lh, const void *data, unsigned long *rhash); 220 static LHASH_NODE **getrn(_LHASH *lh, const void *data, unsigned long *rhash);
113 221
114 _LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c) 222 _LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c)
115 { 223 {
116 _LHASH *ret; 224 _LHASH *ret;
117 int i; 225 int i;
118 226
119 if ((ret=OPENSSL_malloc(sizeof(_LHASH))) == NULL) 227 if ((ret=OPENSSL_malloc(sizeof(_LHASH))) == NULL)
(...skipping 20 matching lines...) Expand all
140 ret->num_comp_calls=0; 248 ret->num_comp_calls=0;
141 ret->num_insert=0; 249 ret->num_insert=0;
142 ret->num_replace=0; 250 ret->num_replace=0;
143 ret->num_delete=0; 251 ret->num_delete=0;
144 ret->num_no_delete=0; 252 ret->num_no_delete=0;
145 ret->num_retrieve=0; 253 ret->num_retrieve=0;
146 ret->num_retrieve_miss=0; 254 ret->num_retrieve_miss=0;
147 ret->num_hash_comps=0; 255 ret->num_hash_comps=0;
148 256
149 ret->error=0; 257 ret->error=0;
258 LH_ITERATION_RESET(ret);
150 return(ret); 259 return(ret);
151 err1: 260 err1:
152 OPENSSL_free(ret); 261 OPENSSL_free(ret);
153 err0: 262 err0:
154 return(NULL); 263 return(NULL);
155 } 264 }
156 265
157 void lh_free(_LHASH *lh) 266 void lh_free(_LHASH *lh)
158 { 267 {
159 unsigned int i; 268 unsigned int i;
(...skipping 16 matching lines...) Expand all
176 OPENSSL_free(lh); 285 OPENSSL_free(lh);
177 } 286 }
178 287
179 void *lh_insert(_LHASH *lh, void *data) 288 void *lh_insert(_LHASH *lh, void *data)
180 { 289 {
181 unsigned long hash; 290 unsigned long hash;
182 LHASH_NODE *nn,**rn; 291 LHASH_NODE *nn,**rn;
183 void *ret; 292 void *ret;
184 293
185 lh->error=0; 294 lh->error=0;
186 » if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)) 295 » /* Do not expand the array if the table is being iterated on. */
296 » if (LH_ITERATION_IS_ACTIVE(lh))
297 » » LH_ITERATION_SET_MUTATED(lh);
298 » else if (LH_SHOULD_EXPAND(lh))
187 expand(lh); 299 expand(lh);
188 300
189 rn=getrn(lh,data,&hash); 301 rn=getrn(lh,data,&hash);
190 302
191 if (*rn == NULL) 303 if (*rn == NULL)
192 { 304 {
193 if ((nn=(LHASH_NODE *)OPENSSL_malloc(sizeof(LHASH_NODE))) == NUL L) 305 if ((nn=(LHASH_NODE *)OPENSSL_malloc(sizeof(LHASH_NODE))) == NUL L)
194 { 306 {
195 lh->error++; 307 lh->error++;
196 return(NULL); 308 return(NULL);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 else 343 else
232 { 344 {
233 nn= *rn; 345 nn= *rn;
234 *rn=nn->next; 346 *rn=nn->next;
235 ret=nn->data; 347 ret=nn->data;
236 OPENSSL_free(nn); 348 OPENSSL_free(nn);
237 lh->num_delete++; 349 lh->num_delete++;
238 } 350 }
239 351
240 lh->num_items--; 352 lh->num_items--;
241 » if ((lh->num_nodes > MIN_NODES) && 353 » /* Do not contract the array if the table is being iterated on. */
242 » » (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))) 354 » if (LH_ITERATION_IS_ACTIVE(lh))
355 » » LH_ITERATION_SET_MUTATED(lh);
356 » else if (LH_SHOULD_CONTRACT(lh))
243 contract(lh); 357 contract(lh);
244 358
245 return(ret); 359 return(ret);
246 } 360 }
247 361
248 void *lh_retrieve(_LHASH *lh, const void *data) 362 void *lh_retrieve(_LHASH *lh, const void *data)
249 { 363 {
250 unsigned long hash; 364 unsigned long hash;
251 LHASH_NODE **rn; 365 LHASH_NODE **rn;
252 void *ret; 366 void *ret;
(...skipping 16 matching lines...) Expand all
269 383
270 static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DOALL_FN_TYPE func, 384 static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DOALL_FN_TYPE func,
271 LHASH_DOALL_ARG_FN_TYPE func_arg, void *arg) 385 LHASH_DOALL_ARG_FN_TYPE func_arg, void *arg)
272 { 386 {
273 int i; 387 int i;
274 LHASH_NODE *a,*n; 388 LHASH_NODE *a,*n;
275 389
276 if (lh == NULL) 390 if (lh == NULL)
277 return; 391 return;
278 392
393 LH_ITERATION_INCREMENT_DEPTH(lh);
279 /* reverse the order so we search from 'top to bottom' 394 /* reverse the order so we search from 'top to bottom'
280 * We were having memory leaks otherwise */ 395 * We were having memory leaks otherwise */
281 for (i=lh->num_nodes-1; i>=0; i--) 396 for (i=lh->num_nodes-1; i>=0; i--)
282 { 397 {
283 a=lh->b[i]; 398 a=lh->b[i];
284 while (a != NULL) 399 while (a != NULL)
285 { 400 {
286 » » » /* 28/05/91 - eay - n added so items can be deleted 401 » » » /* note that 'a' can be deleted by the callback */
287 » » » * via lh_doall */
288 » » » /* 22/05/08 - ben - eh? since a is not passed,
289 » » » * this should not be needed */
290 n=a->next; 402 n=a->next;
291 if(use_arg) 403 if(use_arg)
292 func_arg(a->data,arg); 404 func_arg(a->data,arg);
293 else 405 else
294 func(a->data); 406 func(a->data);
295 a=n; 407 a=n;
296 } 408 }
297 } 409 }
410
411 LH_ITERATION_DECREMENT_DEPTH(lh);
412 if (!LH_ITERATION_IS_ACTIVE(lh) && LH_ITERATION_IS_MUTATED(lh))
413 {
414 LH_ITERATION_RESET(lh);
415 /* Resize the buckets array if necessary. Each expand() or
416 * contract() call will double/halve the size of the array,
417 * respectively, so call them in a loop. */
418 while (LH_SHOULD_EXPAND(lh))
419 expand(lh);
420 while (LH_SHOULD_CONTRACT(lh))
421 contract(lh);
422 }
298 } 423 }
299 424
300 void lh_doall(_LHASH *lh, LHASH_DOALL_FN_TYPE func) 425 void lh_doall(_LHASH *lh, LHASH_DOALL_FN_TYPE func)
301 { 426 {
302 doall_util_fn(lh, 0, func, (LHASH_DOALL_ARG_FN_TYPE)0, NULL); 427 doall_util_fn(lh, 0, func, (LHASH_DOALL_ARG_FN_TYPE)0, NULL);
303 } 428 }
304 429
305 void lh_doall_arg(_LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg) 430 void lh_doall_arg(_LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg)
306 { 431 {
307 doall_util_fn(lh, 1, (LHASH_DOALL_FN_TYPE)0, func, arg); 432 doall_util_fn(lh, 1, (LHASH_DOALL_FN_TYPE)0, func, arg);
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 ret^=v*v; 591 ret^=v*v;
467 c++; 592 c++;
468 } 593 }
469 return((ret>>16)^ret); 594 return((ret>>16)^ret);
470 } 595 }
471 596
472 unsigned long lh_num_items(const _LHASH *lh) 597 unsigned long lh_num_items(const _LHASH *lh)
473 { 598 {
474 return lh ? lh->num_items : 0; 599 return lh ? lh->num_items : 0;
475 } 600 }
OLDNEW
« no previous file with comments | « openssl/crypto/lhash/lhash.h ('k') | openssl/crypto/objects/o_names.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698