1 // SPDX-FileCopyrightText: 2009-2012 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com> 2 // 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 /* 6 * Userspace RCU library - test program 7 */ 8 9 #include "test_urcu_hash.h" 10 11 enum urcu_hash_addremove { 12 AR_RANDOM = 0, 13 AR_ADD = 1, 14 AR_REMOVE = -1, 15 }; /* 1: add, -1 remove, 0: random */ 16 17 static enum urcu_hash_addremove addremove; /* 1: add, -1 remove, 0: random */ 18 19 void test_hash_unique_sigusr1_handler(int signo __attribute__((unused))) 20 { 21 switch (addremove) { 22 case AR_ADD: 23 printf("Add/Remove: random.\n"); 24 addremove = AR_RANDOM; 25 break; 26 case AR_RANDOM: 27 printf("Add/Remove: remove only.\n"); 28 addremove = AR_REMOVE; 29 break; 30 case AR_REMOVE: 31 printf("Add/Remove: add only.\n"); 32 addremove = AR_ADD; 33 break; 34 } 35 } 36 37 void test_hash_unique_sigusr2_handler(int signo __attribute__((unused))) 38 { 39 char msg[1] = { 0x42 }; 40 ssize_t ret; 41 42 do { 43 ret = write(count_pipe[1], msg, 1); /* wakeup thread */ 44 } while (ret == -1L && errno == EINTR); 45 } 46 47 void *test_hash_unique_thr_reader(void *_count) 48 { 49 unsigned long long *count = _count; 50 51 printf_verbose("thread_begin %s, tid %lu\n", 52 "reader", urcu_get_thread_id()); 53 54 URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL); 55 56 set_affinity(); 57 58 rcu_register_thread(); 59 60 wait_until_go(); 61 62 for (;;) { 63 struct lfht_test_node *node; 64 struct cds_lfht_iter iter; 65 /* 66 * iterate on whole table, ensuring that no duplicate is 67 * found. 68 */ 69 rcu_read_lock(); 70 cds_lfht_for_each_entry(test_ht, &iter, node, node) { 71 struct cds_lfht_iter dup_iter; 72 73 dup_iter = 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); 78 } 79 } 80 rcu_read_unlock(); 81 82 rcu_debug_yield_read(); 83 if (caa_unlikely(rduration)) 84 loop_sleep(rduration); 85 URCU_TLS(nr_reads)++; 86 if (caa_unlikely(!test_duration_read())) 87 break; 88 if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0)) 89 rcu_quiescent_state(); 90 } 91 92 rcu_unregister_thread(); 93 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), 99 URCU_TLS(lookup_ok)); 100 return ((void*)1); 101 102 } 103 104 void *test_hash_unique_thr_writer(void *_count) 105 { 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; 110 int ret; 111 int loc_add_unique; 112 113 printf_verbose("thread_begin %s, tid %lu\n", 114 "writer", urcu_get_thread_id()); 115 116 URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL); 117 118 set_affinity(); 119 120 rcu_register_thread(); 121 122 wait_until_go(); 123 124 for (;;) { 125 /* 126 * add unique/add replace with new node key from range. 127 */ 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), 133 sizeof(void *)); 134 rcu_read_lock(); 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); 140 } else { 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), 147 &node->node); 148 ret_node = NULL; 149 #endif //0 150 } 151 rcu_read_unlock(); 152 if (loc_add_unique) { 153 if (ret_node != &node->node) { 154 free(node); 155 URCU_TLS(nr_addexist)++; 156 } else { 157 URCU_TLS(nr_add)++; 158 } 159 } else { 160 if (ret_node) { 161 call_rcu(&to_test_node(ret_node)->head, 162 free_node_cb); 163 URCU_TLS(nr_addexist)++; 164 } else { 165 URCU_TLS(nr_add)++; 166 } 167 } 168 } else { 169 /* May delete */ 170 rcu_read_lock(); 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)); 175 rcu_read_unlock(); 176 if (ret == 0) { 177 node = cds_lfht_iter_get_test_node(&iter); 178 call_rcu(&node->head, free_node_cb); 179 URCU_TLS(nr_del)++; 180 } else 181 URCU_TLS(nr_delnoent)++; 182 } 183 #if 0 184 //if (URCU_TLS(nr_writes) % 100000 == 0) { 185 if (URCU_TLS(nr_writes) % 1000 == 0) { 186 rcu_read_lock(); 187 if (rand_r(&URCU_TLS(rand_lookup)) & 1) { 188 ht_resize(test_ht, 1); 189 } else { 190 ht_resize(test_ht, -1); 191 } 192 rcu_read_unlock(); 193 } 194 #endif //0 195 URCU_TLS(nr_writes)++; 196 if (caa_unlikely(!test_duration_write())) 197 break; 198 if (caa_unlikely(wdelay)) 199 loop_sleep(wdelay); 200 if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0)) 201 rcu_quiescent_state(); 202 } 203 204 rcu_unregister_thread(); 205 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(), 210 URCU_TLS(nr_add), 211 URCU_TLS(nr_addexist), 212 URCU_TLS(nr_del), 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); 218 return ((void*)2); 219 } 220 221 int test_hash_unique_populate_hash(void) 222 { 223 struct lfht_test_node *node; 224 struct cds_lfht_node *ret_node; 225 226 printf("Starting uniqueness test.\n"); 227 228 URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL); 229 230 if (!init_populate) 231 return 0; 232 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); 237 } 238 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), 243 sizeof(void *)); 244 rcu_read_lock(); 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); 248 rcu_read_unlock(); 249 if (ret_node) { 250 call_rcu(&to_test_node(ret_node)->head, free_node_cb); 251 URCU_TLS(nr_addexist)++; 252 } else { 253 URCU_TLS(nr_add)++; 254 } 255 URCU_TLS(nr_writes)++; 256 } 257 return 0; 258 } 259