1 // SPDX-FileCopyrightText: 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
6 * Userspace RCU library - test program
9 #include "test_urcu_hash.h"
11 enum urcu_hash_addremove
{
15 }; /* 1: add, -1 remove, 0: random */
17 static enum urcu_hash_addremove addremove
; /* 1: add, -1 remove, 0: random */
19 void test_hash_unique_sigusr1_handler(int signo
__attribute__((unused
)))
23 printf("Add/Remove: random.\n");
24 addremove
= AR_RANDOM
;
27 printf("Add/Remove: remove only.\n");
28 addremove
= AR_REMOVE
;
31 printf("Add/Remove: add only.\n");
37 void test_hash_unique_sigusr2_handler(int signo
__attribute__((unused
)))
39 char msg
[1] = { 0x42 };
43 ret
= write(count_pipe
[1], msg
, 1); /* wakeup thread */
44 } while (ret
== -1L && errno
== EINTR
);
47 void *test_hash_unique_thr_reader(void *_count
)
49 unsigned long long *count
= _count
;
51 printf_verbose("thread_begin %s, tid %lu\n",
52 "reader", urcu_get_thread_id());
54 URCU_TLS(rand_lookup
) = urcu_get_thread_id() ^ time(NULL
);
58 rcu_register_thread();
63 struct lfht_test_node
*node
;
64 struct cds_lfht_iter iter
;
66 * iterate on whole table, ensuring that no duplicate is
70 cds_lfht_for_each_entry(test_ht
, &iter
, node
, node
) {
71 struct cds_lfht_iter dup_iter
;
74 cds_lfht_next_duplicate(test_ht
, test_match
,
75 node
->key
, &dup_iter
);
76 if (dup_iter
.node
!= NULL
) {
77 printf("[ERROR] Duplicate key %p found\n", node
->key
);
82 rcu_debug_yield_read();
83 if (caa_unlikely(rduration
))
84 loop_sleep(rduration
);
86 if (caa_unlikely(!test_duration_read()))
88 if (caa_unlikely((URCU_TLS(nr_reads
) & ((1 << 10) - 1)) == 0))
89 rcu_quiescent_state();
92 rcu_unregister_thread();
94 *count
= URCU_TLS(nr_reads
);
95 printf_verbose("thread_end %s, tid %lu\n",
96 "reader", urcu_get_thread_id());
97 printf_verbose("read tid : %lu, lookupfail %lu, lookupok %lu\n",
98 urcu_get_thread_id(), URCU_TLS(lookup_fail
),
104 void *test_hash_unique_thr_writer(void *_count
)
106 struct lfht_test_node
*node
;
107 struct cds_lfht_node
*ret_node
;
108 struct cds_lfht_iter iter
;
109 struct wr_count
*count
= _count
;
113 printf_verbose("thread_begin %s, tid %lu\n",
114 "writer", urcu_get_thread_id());
116 URCU_TLS(rand_lookup
) = urcu_get_thread_id() ^ time(NULL
);
120 rcu_register_thread();
126 * add unique/add replace with new node key from range.
128 if (1 || (addremove
== AR_ADD
|| add_only
)
129 || (addremove
== AR_RANDOM
&& rand_r(&URCU_TLS(rand_lookup
)) & 1)) {
130 node
= malloc(sizeof(struct lfht_test_node
));
131 lfht_test_node_init(node
,
132 (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup
)) % write_pool_size
) + write_pool_offset
),
135 loc_add_unique
= rand_r(&URCU_TLS(rand_lookup
)) & 1;
136 if (loc_add_unique
) {
137 ret_node
= cds_lfht_add_unique(test_ht
,
138 test_hash(node
->key
, node
->key_len
, TEST_HASH_SEED
),
139 test_match
, node
->key
, &node
->node
);
141 ret_node
= cds_lfht_add_replace(test_ht
,
142 test_hash(node
->key
, node
->key_len
, TEST_HASH_SEED
),
143 test_match
, node
->key
, &node
->node
);
144 #if 0 //generate an error on purpose
145 cds_lfht_add(test_ht
,
146 test_hash(node
->key
, node
->key_len
, TEST_HASH_SEED
),
152 if (loc_add_unique
) {
153 if (ret_node
!= &node
->node
) {
155 URCU_TLS(nr_addexist
)++;
161 call_rcu(&to_test_node(ret_node
)->head
,
163 URCU_TLS(nr_addexist
)++;
171 cds_lfht_test_lookup(test_ht
,
172 (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup
)) % write_pool_size
) + write_pool_offset
),
173 sizeof(void *), &iter
);
174 ret
= cds_lfht_del(test_ht
, cds_lfht_iter_get_node(&iter
));
177 node
= cds_lfht_iter_get_test_node(&iter
);
178 call_rcu(&node
->head
, free_node_cb
);
181 URCU_TLS(nr_delnoent
)++;
184 //if (URCU_TLS(nr_writes) % 100000 == 0) {
185 if (URCU_TLS(nr_writes
) % 1000 == 0) {
187 if (rand_r(&URCU_TLS(rand_lookup
)) & 1) {
188 ht_resize(test_ht
, 1);
190 ht_resize(test_ht
, -1);
195 URCU_TLS(nr_writes
)++;
196 if (caa_unlikely(!test_duration_write()))
198 if (caa_unlikely(wdelay
))
200 if (caa_unlikely((URCU_TLS(nr_writes
) & ((1 << 10) - 1)) == 0))
201 rcu_quiescent_state();
204 rcu_unregister_thread();
206 printf_verbose("thread_end %s, tid %lu\n",
207 "writer", urcu_get_thread_id());
208 printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
209 "nr_delnoent %lu\n", urcu_get_thread_id(),
211 URCU_TLS(nr_addexist
),
213 URCU_TLS(nr_delnoent
));
214 count
->update_ops
= URCU_TLS(nr_writes
);
215 count
->add
= URCU_TLS(nr_add
);
216 count
->add_exist
= URCU_TLS(nr_addexist
);
217 count
->remove
= URCU_TLS(nr_del
);
221 int test_hash_unique_populate_hash(void)
223 struct lfht_test_node
*node
;
224 struct cds_lfht_node
*ret_node
;
226 printf("Starting uniqueness test.\n");
228 URCU_TLS(rand_lookup
) = urcu_get_thread_id() ^ time(NULL
);
233 if (init_populate
* 10 > init_pool_size
) {
234 printf("WARNING: required to populate %lu nodes (-k), but random "
235 "pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
236 "larger random pool (-p option). This may take a while...\n", init_populate
, init_pool_size
);
239 while (URCU_TLS(nr_add
) < init_populate
) {
240 node
= malloc(sizeof(struct lfht_test_node
));
241 lfht_test_node_init(node
,
242 (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup
)) % init_pool_size
) + init_pool_offset
),
245 ret_node
= cds_lfht_add_replace(test_ht
,
246 test_hash(node
->key
, node
->key_len
, TEST_HASH_SEED
),
247 test_match
, node
->key
, &node
->node
);
250 call_rcu(&to_test_node(ret_node
)->head
, free_node_cb
);
251 URCU_TLS(nr_addexist
)++;
255 URCU_TLS(nr_writes
)++;