From: Nikola Pajkovsky Date: Thu, 25 Sep 2025 16:32:17 +0000 (+0200) Subject: hashtable: add option to disable RCU locks X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=512f176185ebcd98810e181601fcaf7f340439e9;p=thirdparty%2Fopenssl.git hashtable: add option to disable RCU locks a new config option _no_rcu_ is added into HT_CONFIG. When _no_rcu_ is set then hashtable can be guarded with any other locking primitives, and behives as ordinary hashtable. Also, all the impact of the atomics used internally to the hash table was mitigated. RCU performance # INFO: @ test/lhash_test.c:747 # multithread stress runs 40000 ops in 40.779656 seconds No RCU, guarded with RWLOCK # INFO: @ test/lhash_test.c:747 # multithread stress runs 40000 ops in 36.976926 seconds Signed-off-by: Nikola Pajkovsky Reviewed-by: Saša Nedvědický Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/28677) --- diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c index 50491db62bb..507327a1cbd 100644 --- a/crypto/core_namemap.c +++ b/crypto/core_namemap.c @@ -547,7 +547,7 @@ OSSL_NAMEMAP *ossl_namemap_stored(OSSL_LIB_CTX *libctx) OSSL_NAMEMAP *ossl_namemap_new(OSSL_LIB_CTX *libctx) { OSSL_NAMEMAP *namemap; - HT_CONFIG htconf = { NULL, NULL, NULL, NAMEMAP_HT_BUCKETS, 1, 1 }; + HT_CONFIG htconf = { NULL, NULL, NULL, NAMEMAP_HT_BUCKETS, 1, 1, 0 }; htconf.ctx = libctx; diff --git a/crypto/hashtable/hashtable.c b/crypto/hashtable/hashtable.c index 99971ef71fd..da81dab1308 100644 --- a/crypto/hashtable/hashtable.c +++ b/crypto/hashtable/hashtable.c @@ -71,7 +71,6 @@ # include #endif -#include "internal/numbers.h" /* * When we do a lookup/insert/delete, there is a high likelihood * that we will iterate over at least part of the neighborhood list @@ -188,10 +187,14 @@ HT *ossl_ht_new(const HT_CONFIG *conf) if (new == NULL) return NULL; - new->atomic_lock = CRYPTO_THREAD_lock_new(); - if (new->atomic_lock == NULL) + if (conf->lockless_reads && conf->no_rcu) goto err; + if (!conf->no_rcu) { + new->atomic_lock = CRYPTO_THREAD_lock_new(); + if (new->atomic_lock == NULL) + goto err; + } memcpy(&new->config, conf, sizeof(*conf)); if (new->config.init_neighborhoods != 0) { @@ -222,18 +225,21 @@ HT *ossl_ht_new(const HT_CONFIG *conf) goto err; new->md->neighborhood_mask = new->wpd.neighborhood_len - 1; - new->lock = ossl_rcu_lock_new(1, conf->ctx); - if (new->lock == NULL) - goto err; - + if (!conf->no_rcu) { + new->lock = ossl_rcu_lock_new(1, conf->ctx); + if (new->lock == NULL) + goto err; + } if (new->config.ht_hash_fn == NULL) new->config.ht_hash_fn = internal_ht_hash_fn; return new; err: - CRYPTO_THREAD_lock_free(new->atomic_lock); - ossl_rcu_lock_free(new->lock); + if (!conf->no_rcu) { + CRYPTO_THREAD_lock_free(new->atomic_lock); + ossl_rcu_lock_free(new->lock); + } if (new->md != NULL) OPENSSL_free(new->md->neighborhood_ptr_to_free); OPENSSL_free(new->md); @@ -243,16 +249,25 @@ err: int ossl_ht_read_lock(HT *htable) { + if (htable->config.no_rcu) + return 1; + return ossl_rcu_read_lock(htable->lock); } void ossl_ht_read_unlock(HT *htable) { + if (htable->config.no_rcu) + return; + ossl_rcu_read_unlock(htable->lock); } void ossl_ht_write_lock(HT *htable) { + if (htable->config.no_rcu) + return; + ossl_rcu_write_lock(htable->lock); htable->wpd.need_sync = 0; } @@ -261,6 +276,9 @@ void ossl_ht_write_unlock(HT *htable) { int need_sync = htable->wpd.need_sync; + if (htable->config.no_rcu) + return; + htable->wpd.need_sync = 0; ossl_rcu_write_unlock(htable->lock); if (need_sync) @@ -308,15 +326,25 @@ static int ossl_ht_flush_internal(HT *h) newmd->neighborhood_mask = DEFAULT_NEIGH_LEN - 1; /* Swap the old and new mutable data sets */ - oldmd = ossl_rcu_deref(&h->md); - ossl_rcu_assign_ptr(&h->md, &newmd); + if (!h->config.no_rcu) { + oldmd = ossl_rcu_deref(&h->md); + ossl_rcu_assign_ptr(&h->md, &newmd); + } else { + oldmd = h->md; + h->md = newmd; + } /* Set the number of entries to 0 */ h->wpd.value_count = 0; h->wpd.neighborhood_len = DEFAULT_NEIGH_LEN; - ossl_rcu_call(h->lock, free_oldmd, oldmd); + if (!h->config.no_rcu) { + ossl_rcu_call(h->lock, free_oldmd, oldmd); + } else { + free_oldmd(oldmd); + } h->wpd.need_sync = 1; + return 1; } @@ -334,8 +362,10 @@ void ossl_ht_free(HT *h) ossl_ht_flush_internal(h); ossl_ht_write_unlock(h); /* Freeing the lock does a final sync for us */ - CRYPTO_THREAD_lock_free(h->atomic_lock); - ossl_rcu_lock_free(h->lock); + if (!h->config.no_rcu) { + CRYPTO_THREAD_lock_free(h->atomic_lock); + ossl_rcu_lock_free(h->lock); + } OPENSSL_free(h->md->neighborhood_ptr_to_free); OPENSSL_free(h->md); OPENSSL_free(h); @@ -492,9 +522,14 @@ static int grow_hashtable(HT *h, size_t oldsize) /* * Now we replace the old mutable data with the new */ - ossl_rcu_assign_ptr(&h->md, &newmd); - ossl_rcu_call(h->lock, free_old_neigh_table, oldmd); - h->wpd.need_sync = 1; + if (!h->config.no_rcu) { + ossl_rcu_assign_ptr(&h->md, &newmd); + ossl_rcu_call(h->lock, free_old_neigh_table, oldmd); + h->wpd.need_sync = 1; + } else { + h->md = newmd; + free_old_neigh_table(oldmd); + } /* * And we're done */ @@ -552,7 +587,10 @@ static int ossl_ht_insert_locked(HT *h, uint64_t hash, PREFETCH_NEIGHBORHOOD(md->neighborhoods[neigh_idx]); for (j = 0; j < NEIGHBORHOOD_LEN; j++) { - ival = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value); + if (!h->config.no_rcu) + ival = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value); + else + ival = (HT_VALUE *)md->neighborhoods[neigh_idx].entries[j].value; if (ival == NULL) { empty_idx = j; /* lockless_reads implies no deletion, we can break out */ @@ -560,9 +598,13 @@ static int ossl_ht_insert_locked(HT *h, uint64_t hash, goto not_found; continue; } - if (!CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[j].hash, - &ihash, h->atomic_lock)) - return 0; + if (!h->config.no_rcu) { + if (!CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[j].hash, + &ihash, h->atomic_lock)) + return 0; + } else { + ihash = md->neighborhoods[neigh_idx].entries[j].hash; + } if (compare_hash(hash, ihash) && match_key(&newval->value.key, &ival->key)) { if (olddata == NULL) { @@ -570,13 +612,19 @@ static int ossl_ht_insert_locked(HT *h, uint64_t hash, return 0; } /* Do a replacement */ - if (!CRYPTO_atomic_store(&md->neighborhoods[neigh_idx].entries[j].hash, - hash, h->atomic_lock)) - return 0; - *olddata = (HT_VALUE *)md->neighborhoods[neigh_idx].entries[j].value; - ossl_rcu_assign_ptr(&md->neighborhoods[neigh_idx].entries[j].value, - &newval); - ossl_rcu_call(h->lock, free_old_ht_value, *olddata); + if (!h->config.no_rcu) { + if (!CRYPTO_atomic_store(&md->neighborhoods[neigh_idx].entries[j].hash, + hash, h->atomic_lock)) + return 0; + *olddata = (HT_VALUE *)md->neighborhoods[neigh_idx].entries[j].value; + ossl_rcu_assign_ptr(&md->neighborhoods[neigh_idx].entries[j].value, + &newval); + ossl_rcu_call(h->lock, free_old_ht_value, *olddata); + } else { + md->neighborhoods[neigh_idx].entries[j].hash = hash; + *olddata = (HT_VALUE *)md->neighborhoods[neigh_idx].entries[j].value; + md->neighborhoods[neigh_idx].entries[j].value = newval; + } h->wpd.need_sync = 1; return 1; } @@ -591,12 +639,17 @@ static int ossl_ht_insert_locked(HT *h, uint64_t hash, /* If we get to here, its just an insert */ if (empty_idx == SIZE_MAX) return -1; /* out of space */ - if (!CRYPTO_atomic_store(&md->neighborhoods[neigh_idx].entries[empty_idx].hash, - hash, h->atomic_lock)) - return 0; + if (!h->config.no_rcu) { + if (!CRYPTO_atomic_store(&md->neighborhoods[neigh_idx].entries[empty_idx].hash, + hash, h->atomic_lock)) + return 0; + ossl_rcu_assign_ptr(&md->neighborhoods[neigh_idx].entries[empty_idx].value, + &newval); + } else { + md->neighborhoods[neigh_idx].entries[empty_idx].hash = hash; + md->neighborhoods[neigh_idx].entries[empty_idx].value = newval; + } h->wpd.value_count++; - ossl_rcu_assign_ptr(&md->neighborhoods[neigh_idx].entries[empty_idx].value, - &newval); return 1; } @@ -684,21 +737,31 @@ HT_VALUE *ossl_ht_get(HT *h, HT_KEY *key) hash = h->config.ht_hash_fn(key); - md = ossl_rcu_deref(&h->md); + if (!h->config.no_rcu) + md = ossl_rcu_deref(&h->md); + else + md = h->md; neigh_idx = neigh_idx_start = hash & md->neighborhood_mask; do { PREFETCH_NEIGHBORHOOD(md->neighborhoods[neigh_idx]); for (j = 0; j < NEIGHBORHOOD_LEN; j++) { - ival = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value); + if (!h->config.no_rcu) + ival = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value); + else + ival = md->neighborhoods[neigh_idx].entries[j].value; if (ival == NULL) { if (lockless_reads) /* lockless_reads implies no deletion, we can break out */ return NULL; continue; } - if (!CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[j].hash, - &ehash, h->atomic_lock)) - return NULL; + if (!h->config.no_rcu) { + if (!CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[j].hash, + &ehash, h->atomic_lock)) + return NULL; + } else { + ehash = md->neighborhoods[neigh_idx].entries[j].hash; + } if (compare_hash(hash, ehash) && match_key(&ival->value.key, key)) return (HT_VALUE *)ival; } @@ -741,19 +804,53 @@ int ossl_ht_delete(HT *h, HT_KEY *key) continue; if (compare_hash(hash, h->md->neighborhoods[neigh_idx].entries[j].hash) && match_key(key, &v->value.key)) { - if (!CRYPTO_atomic_store(&h->md->neighborhoods[neigh_idx].entries[j].hash, - 0, h->atomic_lock)) - break; + if (!h->config.no_rcu) { + if (!CRYPTO_atomic_store(&h->md->neighborhoods[neigh_idx].entries[j].hash, + 0, h->atomic_lock)) + break; + ossl_rcu_assign_ptr(&h->md->neighborhoods[neigh_idx].entries[j].value, &nv); + } else { + h->md->neighborhoods[neigh_idx].entries[j].hash = 0; + h->md->neighborhoods[neigh_idx].entries[j].value = NULL; + } h->wpd.value_count--; - ossl_rcu_assign_ptr(&h->md->neighborhoods[neigh_idx].entries[j].value, - &nv); rc = 1; break; } } if (rc == 1) { - ossl_rcu_call(h->lock, free_old_entry, v); + if (!h->config.no_rcu) + ossl_rcu_call(h->lock, free_old_entry, v); + else + free_old_entry(v); h->wpd.need_sync = 1; } + return rc; } + +HT_VALUE *ossl_ht_deref_value(HT *h, HT_VALUE **val) +{ + HT_VALUE *v; + + if (!h->config.no_rcu) + v = ossl_rcu_deref(val); + else + v = *val; + + return v; +} + +void *ossl_ht_inner_value(HT *h, HT_VALUE *v) +{ + void *inner; + + if (!h->config.no_rcu) { + inner = v->value; + } else { + inner = v->value; + OPENSSL_free(v); + } + + return inner; +} diff --git a/doc/internal/man3/ossl_ht_new.pod b/doc/internal/man3/ossl_ht_new.pod index 18aa5d1e4d3..7ad33efbbe2 100644 --- a/doc/internal/man3/ossl_ht_new.pod +++ b/doc/internal/man3/ossl_ht_new.pod @@ -67,6 +67,7 @@ of: I The function to call to free a value, may be NULL. I The function to generate a hash value for a key, may be NULL. I The initial number of neighborhoods in the hash table. + I Disables RCU locking. Note that init_bucket_len may be set to zero, which will use the default initial bucket size, which will be automatically expanded with the hash table load @@ -84,6 +85,9 @@ Note that lockless_write operations are done at your own risk. Lockless is the callers responsibility in this mode of operation to provide thread synchronization. +Note that if RCU locks are disabled, calls to ossl_ht_[read/write]_[lock/unlock] +have no effect. + =item * ossl_ht_free() frees an allocated hash table. Each element in the table @@ -110,7 +114,8 @@ called to release the element data. =item * ossl_ht_insert() inserts an B element into the hash table, to be -hashed using the corresponding B value. +hashed using the corresponding B value. The returned pointer olddata must +be freed only when RCU is disabled and insert performs a replacement. =item * diff --git a/fuzz/hashtable.c b/fuzz/hashtable.c index 8aac7bf47b8..78536e42a33 100644 --- a/fuzz/hashtable.c +++ b/fuzz/hashtable.c @@ -99,7 +99,7 @@ static void fuzz_free_cb(HT_VALUE *v) int FuzzerInitialize(int *argc, char ***argv) { - HT_CONFIG fuzz_conf = {NULL, fuzz_free_cb, NULL, 0, 1}; + HT_CONFIG fuzz_conf = {NULL, fuzz_free_cb, NULL, 0, 1, 0}; OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); ERR_clear_error(); diff --git a/include/internal/hashtable.h b/include/internal/hashtable.h index 86d3518b77e..951265714c7 100644 --- a/include/internal/hashtable.h +++ b/include/internal/hashtable.h @@ -54,6 +54,7 @@ typedef struct ht_config_st { size_t init_neighborhoods; uint32_t collision_check; uint32_t lockless_reads; + uint32_t no_rcu; } HT_CONFIG; /* @@ -199,7 +200,7 @@ pfx ossl_unused int ossl_ht_##name##_##vtype##_insert(HT *h, HT_KEY *key, \ inval.type_id = &name##_##vtype##_id; \ rc = ossl_ht_insert(h, key, &inval, olddata == NULL ? NULL : &oval); \ if (oval != NULL) \ - *olddata = (vtype *)oval->value; \ + *olddata = (vtype *)ossl_ht_inner_value(h, oval); \ return rc; \ } \ \ @@ -221,7 +222,7 @@ pfx ossl_unused vtype *ossl_unused ossl_ht_##name##_##vtype##_get(HT *h, \ vv = ossl_ht_get(h, key); \ if (vv == NULL) \ return NULL; \ - *v = ossl_rcu_deref(&vv); \ + *v = ossl_ht_deref_value(h, &vv); \ return ossl_ht_##name##_##vtype##_from_value(*v); \ } \ \ @@ -352,4 +353,49 @@ void ossl_ht_value_list_free(HT_VALUE_LIST *list); */ HT_VALUE *ossl_ht_get(HT *htable, HT_KEY *key); +/** + * ossl_ht_deref_value - Dereference a value stored in a hash table entry + * @h: The hash table handle + * @val: Pointer to the value pointer inside the hash table + * + * This helper returns the actual value stored in a hash table entry, + * with awareness of whether the table is configured for RCU (Read-Copy-Update) + * safe lookups. + * + * If the hash table is configured to use RCU lookups, the function + * calls ossl_rcu_deref() to safely read the value under RCU protection. + * This ensures that the caller sees a consistent pointer in concurrent environments. + * + * If RCU is not enabled (i.e. `h->config.no_rcu` is true), the function + * simply dereferences @val directly. + * + * Return: + * A pointer to the dereferenced hash table value (`HT_VALUE *`), or NULL if + * the underlying pointer is NULL. + */ +HT_VALUE *ossl_ht_deref_value(HT *p, HT_VALUE **val); + +/** + * ossl_ht_inner_value - Extract the user payload from a hash table value + * @h: The hash table handle + * @v: The hash table value wrapper (HT_VALUE) + * + * This helper returns the user-provided payload stored inside a + * hash table value container. The behavior differs depending on + * whether the hash table is configured to use RCU (Read-Copy-Update) + * for concurrency control. + * + * - If RCU is enabled, the function simply returns `v->value` without + * modifying or freeing the container. + * + * - If RCU is disabled the container structure `v` is no longer needed once + * the inner pointer has been extracted. In this case, the function frees + * `v` and returns the inner `value` pointer directly. + * + * Return: + * A pointer to the user payload (`void *`) contained in the hash table + * value wrapper. + */ +void *ossl_ht_inner_value(HT *h, HT_VALUE *v); + #endif diff --git a/test/lhash_test.c b/test/lhash_test.c index c229df902c9..ad818032823 100644 --- a/test/lhash_test.c +++ b/test/lhash_test.c @@ -212,7 +212,7 @@ static uint64_t hashtable_hash(HT_KEY *key) return (uint64_t)(*(uint32_t *)key->keybuf); } -static int test_int_hashtable(void) +static int test_int_hashtable(int idx) { static struct { int data; @@ -227,11 +227,8 @@ static int test_int_hashtable(void) }; const size_t n_dels = OSSL_NELEM(dels); HT_CONFIG hash_conf = { - NULL, - NULL, - NULL, - 0, - 1, + .collision_check = 1, + .no_rcu = idx, }; INTKEY key; int rc = 0; @@ -405,13 +402,14 @@ static int test_hashtable_stress(int idx) unsigned int i; int testresult = 0, *p; HT_CONFIG hash_conf = { - NULL, /* use default context */ - hashtable_intfree, /* our free function */ - hashtable_hash, /* our hash function */ - 625000, /* preset hash size */ - 1, /* Check collisions */ - 0 /* Lockless reads */ + .ht_free_fn = hashtable_intfree, + .ht_hash_fn = hashtable_hash, + .init_neighborhoods = 625000, + .collision_check = 1, + .lockless_reads = idx % 2, + .no_rcu = idx / 2, }; + HT *h; INTKEY key; HT_VALUE *v; @@ -419,9 +417,11 @@ static int test_hashtable_stress(int idx) struct timeval start, end, delta; #endif - hash_conf.lockless_reads = idx; h = ossl_ht_new(&hash_conf); - + if (h == NULL + && hash_conf.no_rcu + && hash_conf.lockless_reads) + return 1; if (!TEST_ptr(h)) goto end; @@ -456,7 +456,7 @@ static int test_hashtable_stress(int idx) const int j = (7 * i + 4) % n * 3 + 1; HT_SET_KEY_FIELD(&key, mykey, j); - switch (idx) { + switch (idx % 2) { case 0: if (!TEST_int_eq((ossl_ht_delete(h, TO_HT_KEY(&key))), 1)) { TEST_info("hashtable didn't delete key %d\n", j); @@ -503,9 +503,14 @@ HT_END_KEY_DEFN(MTKEY) IMPLEMENT_HT_VALUE_TYPE_FNS(TEST_MT_ENTRY, mt, static) +struct ht_internal_st { + HT_CONFIG config; +}; + static int worker_num = 0; static CRYPTO_RWLOCK *worker_lock; static CRYPTO_RWLOCK *testrand_lock; +static CRYPTO_RWLOCK *no_rcu_lock; static int free_failure = 0; static int shutting_down = 0; static int global_iteration = 0; @@ -573,21 +578,36 @@ static void do_mt_hash_work(void) } switch(behavior) { case DO_LOOKUP: - if (!ossl_ht_read_lock(m_ht)) - break; + if (!m_ht->config.no_rcu) { + if (!ossl_ht_read_lock(m_ht)) + break; + } else { + if (!TEST_true(CRYPTO_THREAD_read_lock(no_rcu_lock))) + break; + } m = ossl_ht_mt_TEST_MT_ENTRY_get(m_ht, TO_HT_KEY(&key), &v); if (m != NULL && m != expected_m) { worker_exits[num] = "Read unexpected value from hashtable"; TEST_info("Iteration %d Read unexpected value %p when %p expected", giter, (void *)m, (void *)expected_m); } - ossl_ht_read_unlock(m_ht); + if (!m_ht->config.no_rcu) { + ossl_ht_read_unlock(m_ht); + } else { + if (!TEST_true(CRYPTO_THREAD_unlock(no_rcu_lock))) + break; + } if (worker_exits[num] != NULL) return; break; case DO_INSERT: case DO_REPLACE: - ossl_ht_write_lock(m_ht); + if (!m_ht->config.no_rcu) { + ossl_ht_write_lock(m_ht); + } else { + if (!TEST_true(CRYPTO_THREAD_write_lock(no_rcu_lock))) + break; + } if (behavior == DO_REPLACE) { expected_rc = 1; r = &m; @@ -607,12 +627,22 @@ static void do_mt_hash_work(void) } if (expected_rc == 1) expected_m->in_table = 1; - ossl_ht_write_unlock(m_ht); + if (!m_ht->config.no_rcu) { + ossl_ht_write_unlock(m_ht); + } else { + if (!TEST_true(CRYPTO_THREAD_unlock(no_rcu_lock))) + break; + } if (worker_exits[num] != NULL) return; break; case DO_DELETE: - ossl_ht_write_lock(m_ht); + if (!m_ht->config.no_rcu) { + ossl_ht_write_lock(m_ht); + } else { + if (!TEST_true(CRYPTO_THREAD_write_lock(no_rcu_lock))) + break; + } expected_rc = expected_m->in_table; if (expected_rc == 1) { /* @@ -632,7 +662,12 @@ static void do_mt_hash_work(void) expected_m->in_table ? "in table" : "not in table"); worker_exits[num] = "Failure on delete"; } - ossl_ht_write_unlock(m_ht); + if (!m_ht->config.no_rcu) { + ossl_ht_write_unlock(m_ht); + } else { + if (!TEST_true(CRYPTO_THREAD_unlock(no_rcu_lock))) + break; + } if (worker_exits[num] != NULL) return; break; @@ -643,14 +678,13 @@ static void do_mt_hash_work(void) } } -static int test_hashtable_multithread(void) +static int test_hashtable_multithread(int idx) { HT_CONFIG hash_conf = { - NULL, /* use default context */ - hashtable_mt_free, /* our free function */ - NULL, /* default hash function */ - 0, /* default hash size */ - 1, /* Check collisions */ + .ht_free_fn = hashtable_mt_free, + .init_neighborhoods = 0, + .collision_check = 1, + .no_rcu = idx, }; int ret = 0; thread_t workers[NUM_WORKERS]; @@ -672,6 +706,8 @@ static int test_hashtable_multithread(void) goto end_free; if (!TEST_ptr(testrand_lock = CRYPTO_THREAD_lock_new())) goto end_free; + if (!TEST_ptr(no_rcu_lock = CRYPTO_THREAD_lock_new())) + goto end_free; #ifdef MEASURE_HASH_PERFORMANCE gettimeofday(&start, NULL); #endif @@ -709,11 +745,15 @@ shutdown: TEST_info("multithread stress runs 40000 ops in %ld.%ld seconds", delta.tv_sec, delta.tv_usec); #endif + worker_num = 0; + free_failure = 0; + global_iteration = 0; end_free: shutting_down = 1; ossl_ht_free(m_ht); CRYPTO_THREAD_lock_free(worker_lock); CRYPTO_THREAD_lock_free(testrand_lock); + CRYPTO_THREAD_lock_free(no_rcu_lock); end: return ret; } @@ -722,8 +762,8 @@ int setup_tests(void) { ADD_TEST(test_int_lhash); ADD_TEST(test_stress); - ADD_TEST(test_int_hashtable); - ADD_ALL_TESTS(test_hashtable_stress, 2); - ADD_TEST(test_hashtable_multithread); + ADD_ALL_TESTS(test_int_hashtable, 2); + ADD_ALL_TESTS(test_hashtable_stress, 4); + ADD_ALL_TESTS(test_hashtable_multithread, 2); return 1; }