lookup_pool_size = DEFAULT_RAND_POOL,
write_pool_size = DEFAULT_RAND_POOL;
int validate_lookup;
+int sanity_test;
+unsigned int key_bits = 32;
int count_pipe[2];
}
}
-#if 0
void free_node_cb(struct rcu_head *head)
{
struct ja_test_node *node =
- caa_container_of(head, struct ja_test_node, head);
+ caa_container_of(head, struct ja_test_node, node.head);
free(node);
}
+#if 0
static
void test_delete_all_nodes(struct cds_lfht *ht)
{
printf(" [-N size] Write pool size.\n");
printf(" [-O size] Init pool size.\n");
printf(" [-V] Validate lookups of init values (use with filled init pool, same lookup range, with different write range).\n");
+ printf(" [-s] Do sanity test.\n");
+ printf(" [-B] Key bits for multithread test (default: 32).\n");
printf("\n\n");
}
printf("Test #2: successful key lookup (8-bit).\n");
for (key = 0; key < 200; key++) {
- struct cds_hlist_head *head;
+ struct cds_hlist_head head;
rcu_read_lock();
head = cds_ja_lookup(test_ja, key);
- if (!head) {
+ if (cds_hlist_empty(&head)) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
printf("OK\n");
printf("Test #3: unsuccessful key lookup (8-bit).\n");
for (key = 200; key < 240; key++) {
- struct cds_hlist_head *head;
+ struct cds_hlist_head head;
rcu_read_lock();
head = cds_ja_lookup(test_ja, key);
- if (head) {
+ if (!cds_hlist_empty(&head)) {
fprintf(stderr,
"Error unexpected lookup node %" PRIu64 "\n",
key);
rcu_read_unlock();
}
printf("OK\n");
+ printf("Test #4: remove keys (8-bit).\n");
+ for (key = 0; key < 200; key++) {
+ struct cds_hlist_head head;
+ struct ja_test_node *node;
+
+ rcu_read_lock();
+ head = cds_ja_lookup(test_ja, key);
+ node = cds_hlist_first_entry_rcu(&head, struct ja_test_node, node.list);
+ if (!node) {
+ fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
+ assert(0);
+ }
+ ret = cds_ja_del(test_ja, key, &node->node);
+ if (ret) {
+ fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
+ assert(0);
+ }
+ call_rcu(&node->node.head, free_node_cb);
+ head = cds_ja_lookup(test_ja, key);
+ if (!cds_hlist_empty(&head)) {
+ fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+ printf("OK\n");
- ret = cds_ja_destroy(test_ja);
+ ret = cds_ja_destroy(test_ja, free_node_cb);
if (ret) {
fprintf(stderr, "Error destroying judy array\n");
return -1;
/* Add keys */
printf("Test #1: add keys (16-bit).\n");
- //for (key = 0; key < 10000; key++) {
- for (key = 0; key < 65536; key+=256) {
+ for (key = 0; key < 10000; key++) {
+ //for (key = 0; key < 65536; key+=256) {
struct ja_test_node *node =
calloc(sizeof(*node), 1);
printf("OK\n");
printf("Test #2: successful key lookup (16-bit).\n");
- //for (key = 0; key < 10000; key++) {
- for (key = 0; key < 65536; key+=256) {
- struct cds_hlist_head *head;
+ for (key = 0; key < 10000; key++) {
+ //for (key = 0; key < 65536; key+=256) {
+ struct cds_hlist_head head;
rcu_read_lock();
head = cds_ja_lookup(test_ja, key);
- if (!head) {
+ if (cds_hlist_empty(&head)) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
printf("OK\n");
printf("Test #3: unsuccessful key lookup (16-bit).\n");
for (key = 11000; key <= 11002; key++) {
- struct cds_hlist_head *head;
+ struct cds_hlist_head head;
rcu_read_lock();
head = cds_ja_lookup(test_ja, key);
- if (head) {
+ if (!cds_hlist_empty(&head)) {
fprintf(stderr,
"Error unexpected lookup node %" PRIu64 "\n",
key);
rcu_read_unlock();
}
printf("OK\n");
+ printf("Test #4: remove keys (16-bit).\n");
+ for (key = 0; key < 10000; key++) {
+ //for (key = 0; key < 65536; key+=256) {
+ struct cds_hlist_head head;
+ struct ja_test_node *node;
+
+ rcu_read_lock();
+ head = cds_ja_lookup(test_ja, key);
+ node = cds_hlist_first_entry_rcu(&head, struct ja_test_node, node.list);
+ if (!node) {
+ fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
+ assert(0);
+ }
+ ret = cds_ja_del(test_ja, key, &node->node);
+ if (ret) {
+ fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
+ assert(0);
+ }
+ call_rcu(&node->node.head, free_node_cb);
+ head = cds_ja_lookup(test_ja, key);
+ if (!cds_hlist_empty(&head)) {
+ fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+ printf("OK\n");
- ret = cds_ja_destroy(test_ja);
+ ret = cds_ja_destroy(test_ja, free_node_cb);
if (ret) {
fprintf(stderr, "Error destroying judy array\n");
return -1;
return 0;
}
+/*
+ * nr_dup is number of nodes per key.
+ */
static
-int test_sparse_key(unsigned int bits)
+int test_sparse_key(unsigned int bits, int nr_dup)
{
- int ret;
uint64_t key, max_key;
- int zerocount;
+ int zerocount, i, ret;
if (bits == 64)
max_key = UINT64_MAX;
/* Add keys */
printf("Test #1: add keys (%u-bit).\n", bits);
- zerocount = 0;
- for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
- struct ja_test_node *node =
- calloc(sizeof(*node), 1);
+ for (i = 0; i < nr_dup; i++) {
+ zerocount = 0;
+ for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
+ struct ja_test_node *node =
+ calloc(sizeof(*node), 1);
- ja_test_node_init(node, key);
- rcu_read_lock();
- ret = cds_ja_add(test_ja, key, &node->node);
- rcu_read_unlock();
- if (ret) {
- fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
- ret, key);
- assert(0);
+ ja_test_node_init(node, key);
+ rcu_read_lock();
+ ret = cds_ja_add(test_ja, key, &node->node);
+ rcu_read_unlock();
+ if (ret) {
+ fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+ ret, key);
+ assert(0);
+ }
+ if (key == 0)
+ zerocount++;
}
- if (key == 0)
- zerocount++;
}
printf("OK\n");
printf("Test #2: successful key lookup (%u-bit).\n", bits);
zerocount = 0;
for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
- struct cds_hlist_head *head;
+ struct cds_hlist_head head;
+ struct ja_test_node *node;
+ struct cds_hlist_node *pos;
+ int count = 0;
rcu_read_lock();
head = cds_ja_lookup(test_ja, key);
- if (!head) {
+ if (cds_hlist_empty(&head)) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
+ cds_hlist_for_each_entry_rcu(node, pos, &head, node.list) {
+ count++;
+ }
+ if (count != nr_dup) {
+ fprintf(stderr, "Unexpected number of match for key %" PRIu64 ", expected %d, got %d.\n", key, nr_dup, count);
+ }
rcu_read_unlock();
if (key == 0)
zerocount++;
printf("Test #3: unsuccessful key lookup (%u-bit).\n", bits);
zerocount = 0;
for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
- struct cds_hlist_head *head;
+ struct cds_hlist_head head;
rcu_read_lock();
head = cds_ja_lookup(test_ja, key + 42);
- if (head) {
+ if (!cds_hlist_empty(&head)) {
fprintf(stderr,
"Error unexpected lookup node %" PRIu64 "\n",
key + 42);
}
printf("OK\n");
}
+ printf("Test #4: remove keys (16-bit).\n");
+ zerocount = 0;
+ for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
+ struct cds_hlist_head head;
+ struct ja_test_node *node;
+ struct cds_hlist_node *pos;
+ int count = 0;
+
+ rcu_read_lock();
+ head = cds_ja_lookup(test_ja, key);
+
+
+ cds_hlist_for_each_entry_rcu(node, pos, &head, node.list) {
+ struct cds_hlist_head testhead;
+
+ count++;
+ if (!node) {
+ fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
+ assert(0);
+ }
+ ret = cds_ja_del(test_ja, key, &node->node);
+ if (ret) {
+ fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
+ assert(0);
+ }
+ call_rcu(&node->node.head, free_node_cb);
+ testhead = cds_ja_lookup(test_ja, key);
+ if (count < nr_dup && cds_hlist_empty(&testhead)) {
+ fprintf(stderr, "Error: no node found after deletion of some nodes of a key\n");
+ assert(0);
+ }
+ }
+ head = cds_ja_lookup(test_ja, key);
+ if (!cds_hlist_empty(&head)) {
+ fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
+ assert(0);
+ }
+ rcu_read_unlock();
+ if (key == 0)
+ zerocount++;
+ }
+ printf("OK\n");
- ret = cds_ja_destroy(test_ja);
+ ret = cds_ja_destroy(test_ja, free_node_cb);
if (ret) {
fprintf(stderr, "Error destroying judy array\n");
return -1;
return 0;
}
+static
+int do_sanity_test(void)
+{
+ int i, j, ret;
-int main(int argc, char **argv)
+ printf("Sanity test start.\n");
+
+ for (i = 0; i < 3; i++) {
+ ret = test_8bit_key();
+ if (ret) {
+ return ret;
+ }
+ rcu_quiescent_state();
+ }
+ ret = test_16bit_key();
+ if (ret) {
+ return ret;
+ }
+ rcu_quiescent_state();
+
+ /* key bits */
+ for (i = 8; i <= 64; i *= 2) {
+ /* nr of nodes per key */
+ for (j = 1; j < 4; j++) {
+ ret = test_sparse_key(i, j);
+ if (ret) {
+ return ret;
+ }
+ rcu_quiescent_state();
+ }
+ }
+ printf("Sanity test end.\n");
+
+ return 0;
+}
+
+enum urcu_ja_addremove {
+ AR_RANDOM = 0,
+ AR_ADD = 1,
+ AR_REMOVE = -1,
+}; /* 1: add, -1 remove, 0: random */
+
+static enum urcu_ja_addremove addremove; /* 1: add, -1 remove, 0: random */
+
+static
+void test_ja_rw_sigusr1_handler(int signo)
+{
+ switch (addremove) {
+ case AR_ADD:
+ printf("Add/Remove: random.\n");
+ addremove = AR_RANDOM;
+ break;
+ case AR_RANDOM:
+ printf("Add/Remove: remove only.\n");
+ addremove = AR_REMOVE;
+ break;
+ case AR_REMOVE:
+ printf("Add/Remove: add only.\n");
+ addremove = AR_ADD;
+ break;
+ }
+}
+
+static
+void *test_ja_rw_thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ struct cds_hlist_head head;
+ uint64_t key;
+
+ printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
+ "reader", pthread_self(), (unsigned long) gettid());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+
+ /* note: only looking up ulong keys */
+ key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % lookup_pool_size) + lookup_pool_offset;
+ head = cds_ja_lookup(test_ja, key);
+ if (cds_hlist_empty(&head)) {
+ if (validate_lookup) {
+ printf("[ERROR] Lookup cannot find initial node.\n");
+ exit(-1);
+ }
+ URCU_TLS(lookup_fail)++;
+ } else {
+ URCU_TLS(lookup_ok)++;
+ }
+ rcu_debug_yield_read();
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
+ rcu_quiescent_state();
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
+ "reader", pthread_self(), (unsigned long) gettid());
+ printf_verbose("readid : %lx, lookupfail %lu, lookupok %lu\n",
+ pthread_self(), URCU_TLS(lookup_fail),
+ URCU_TLS(lookup_ok));
+ return ((void*)1);
+}
+
+static
+void *test_ja_rw_thr_writer(void *_count)
+{
+ struct wr_count *count = _count;
+ struct cds_hlist_head head;
+ uint64_t key;
+ int ret;
+
+ printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
+ "writer", pthread_self(), (unsigned long) gettid());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ if ((addremove == AR_ADD || add_only)
+ || (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
+ struct ja_test_node *node = malloc(sizeof(*node));
+
+ /* note: only inserting ulong keys */
+ key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset;
+ ja_test_node_init(node, key);
+ rcu_read_lock();
+ ret = cds_ja_add(test_ja, key, &node->node);
+ URCU_TLS(nr_add)++;
+ rcu_read_unlock();
+ if (ret) {
+ fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+ ret, key);
+ assert(0);
+ }
+ } else {
+ struct ja_test_node *node;
+
+ /* May delete */
+ /* note: only deleting ulong keys */
+ key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset;
+
+ rcu_read_lock();
+
+ head = cds_ja_lookup(test_ja, key);
+ node = cds_hlist_first_entry_rcu(&head, struct ja_test_node, node.list);
+ if (node) {
+ ret = cds_ja_del(test_ja, key, &node->node);
+ if (!ret) {
+ call_rcu(&node->node.head, free_node_cb);
+ URCU_TLS(nr_del)++;
+ } else {
+ URCU_TLS(nr_delnoent)++;
+ }
+ } else {
+ URCU_TLS(nr_delnoent)++;
+ }
+ }
+
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
+ rcu_quiescent_state();
+ }
+
+ rcu_unregister_thread();
+
+ printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
+ "writer", pthread_self(), (unsigned long) gettid());
+ printf_verbose("info id %lx: nr_add %lu, nr_addexist %lu, nr_del %lu, "
+ "nr_delnoent %lu\n", pthread_self(), URCU_TLS(nr_add),
+ URCU_TLS(nr_addexist), URCU_TLS(nr_del),
+ URCU_TLS(nr_delnoent));
+ count->update_ops = URCU_TLS(nr_writes);
+ count->add = URCU_TLS(nr_add);
+ count->add_exist = URCU_TLS(nr_addexist);
+ count->remove = URCU_TLS(nr_del);
+ return ((void*)2);
+}
+
+static
+int do_mt_populate_ja(void)
+{
+ struct cds_hlist_head head;
+ uint64_t key;
+ int ret;
+
+ if (!init_populate)
+ return 0;
+
+ printf("Starting rw test\n");
+
+ for (key = init_pool_offset; key < init_pool_offset + init_pool_size; key++) {
+ struct ja_test_node *node = malloc(sizeof(*node));
+
+ /* note: only inserting ulong keys */
+ key = (unsigned long) key;
+ ja_test_node_init(node, key);
+ rcu_read_lock();
+ ret = cds_ja_add(test_ja, key, &node->node);
+ URCU_TLS(nr_add)++;
+ URCU_TLS(nr_writes)++;
+ rcu_read_unlock();
+ if (ret) {
+ fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+ ret, key);
+ assert(0);
+ }
+ }
+ return 0;
+}
+
+static
+int do_mt_test(void)
{
- int err;
pthread_t *tid_reader, *tid_writer;
void *tret;
+ int ret, i, err;
unsigned long long *count_reader;
struct wr_count *count_writer;
unsigned long long tot_reads = 0, tot_writes = 0,
tot_add = 0, tot_add_exist = 0, tot_remove = 0;
- int i, a, ret;
unsigned int remain;
+
+ tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
+ tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
+ count_reader = malloc(sizeof(*count_reader) * nr_readers);
+ count_writer = malloc(sizeof(*count_writer) * nr_writers);
+
+ printf("Allocating Judy Array for %u-bit keys\n", key_bits);
+ test_ja = cds_ja_new(key_bits);
+ if (!test_ja) {
+ printf("Error allocating judy array.\n");
+ ret = -1;
+ goto end;
+ }
+
+ do_mt_populate_ja();
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i],
+ NULL, test_ja_rw_thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i],
+ NULL, test_ja_rw_thr_writer,
+ &count_writer[i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ rcu_thread_offline_qsbr();
+
+ remain = duration;
+ do {
+ remain = sleep(remain);
+ } while (remain > 0);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += count_writer[i].update_ops;
+ tot_add += count_writer[i].add;
+ tot_add_exist += count_writer[i].add_exist;
+ tot_remove += count_writer[i].remove;
+ }
+
+ ret = cds_ja_destroy(test_ja, free_node_cb);
+ if (ret) {
+ fprintf(stderr, "Error destroying judy array\n");
+ goto end;
+ }
+ rcu_thread_online_qsbr();
+
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(count_writer);
+ ret = 0;
+end:
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int i, j, a, ret, err;
uint64_t key;
+ struct sigaction act;
if (argc < 4) {
show_usage(argc, argv);
case 'V':
validate_lookup = 1;
break;
+ case 's':
+ sanity_test = 1;
+ break;
+ case 'B':
+ key_bits = atol(argv[++i]);
+ break;
}
}
printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
"main", pthread_self(), (unsigned long)gettid());
- tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
- tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
- count_reader = malloc(sizeof(*count_reader) * nr_readers);
- count_writer = malloc(sizeof(*count_writer) * nr_writers);
+ memset(&act, 0, sizeof(act));
+ ret = sigemptyset(&act.sa_mask);
+ if (ret == -1) {
+ perror("sigemptyset");
+ return -1;
+ }
+ act.sa_handler = test_ja_rw_sigusr1_handler;
+ act.sa_flags = SA_RESTART;
+ ret = sigaction(SIGUSR1, &act, NULL);
+ if (ret == -1) {
+ perror("sigaction");
+ return -1;
+ }
err = create_all_cpu_call_rcu_data(0);
if (err) {
rcu_register_thread();
- printf("Test start.\n");
-
- for (i = 0; i < 3; i++) {
- ret = test_8bit_key();
+ if (sanity_test) {
+ ret = do_sanity_test();
if (ret) {
- return ret;
+ fprintf(stderr, "Error in sanity test\n");
}
- rcu_quiescent_state();
- }
- ret = test_16bit_key();
- if (ret) {
- return ret;
- }
- rcu_quiescent_state();
-
- ret = test_sparse_key(8);
- if (ret) {
- return ret;
- }
- rcu_quiescent_state();
-
- ret = test_sparse_key(16);
- if (ret) {
- return ret;
- }
- rcu_quiescent_state();
-
- ret = test_sparse_key(32);
- if (ret) {
- return ret;
+ } else {
+ do_mt_test();
}
- rcu_quiescent_state();
-
- ret = test_sparse_key(64);
- if (ret) {
- return ret;
- }
- rcu_quiescent_state();
- printf("Test end.\n");
rcu_unregister_thread();
+ free_all_cpu_call_rcu_data();
return 0;
#if 0
rcu_thread_offline();
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i],
- NULL, get_thr_reader_cb(),
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i],
- NULL, get_thr_writer_cb(),
- &count_writer[i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- remain = duration;
- do {
- remain = sleep(remain);
- } while (remain > 0);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += count_writer[i].update_ops;
- tot_add += count_writer[i].add;
- tot_add_exist += count_writer[i].add_exist;
- tot_remove += count_writer[i].remove;
- }
-
/* teardown counter thread */
act.sa_handler = SIG_IGN;
act.sa_flags = SA_RESTART;
tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
(long long) tot_add + init_populate - tot_remove - count);
rcu_unregister_thread();
- free_all_cpu_call_rcu_data();
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(count_writer);
#endif
return 0;
}