示例#1
0
void *thr_reader(void *data)
{
	unsigned long tidx = (unsigned long)data;

	printf_verbose("thread_begin %s, tid %lu\n",
			"reader", urcu_get_thread_id());

	set_affinity();

	while (!test_go)
	{
	}

	for (;;) {
		pthread_mutex_lock(&per_thread_lock[tidx].lock);
		assert(test_array.a == 8);
		if (caa_unlikely(rduration))
			loop_sleep(rduration);
		pthread_mutex_unlock(&per_thread_lock[tidx].lock);
		URCU_TLS(nr_reads)++;
		if (caa_unlikely(!test_duration_read()))
			break;
	}

	tot_nr_reads[tidx] = URCU_TLS(nr_reads);
	printf_verbose("thread_end %s, tid %lu\n",
			"reader", urcu_get_thread_id());
	return ((void*)1);

}
示例#2
0
void *thr_writer(void *data)
{
	unsigned long wtidx = (unsigned long)data;

	printf_verbose("thread_begin %s, tid %lu\n",
			"writer", urcu_get_thread_id());

	set_affinity();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		pthread_mutex_lock(&lock);
		test_array.a = 0;
		test_array.a = 8;
		if (caa_unlikely(wduration))
			loop_sleep(wduration);
		pthread_mutex_unlock(&lock);
		URCU_TLS(nr_writes)++;
		if (caa_unlikely(!test_duration_write()))
			break;
		if (caa_unlikely(wdelay))
			loop_sleep(wdelay);
	}

	printf_verbose("thread_end %s, tid %lu\n",
			"writer", urcu_get_thread_id());
	tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
	return ((void*)2);
}
示例#3
0
void *test_hash_rw_thr_reader(void *_count)
{
	unsigned long long *count = _count;
	struct lfht_test_node *node;
	struct cds_lfht_iter iter;

	printf_verbose("thread_begin %s, tid %lu\n",
			"reader", urcu_get_thread_id());

	URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);

	set_affinity();

	rcu_register_thread();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		rcu_read_lock();
		cds_lfht_test_lookup(test_ht,
			(void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % lookup_pool_size) + lookup_pool_offset),
			sizeof(void *), &iter);
		node = cds_lfht_iter_get_test_node(&iter);
		if (node == NULL) {
			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, tid %lu\n",
			"reader", urcu_get_thread_id());
	printf_verbose("read tid : %lx, lookupfail %lu, lookupok %lu\n",
			urcu_get_thread_id(),
			URCU_TLS(lookup_fail),
			URCU_TLS(lookup_ok));
	return ((void*)1);

}
示例#4
0
static void *thr_dequeuer(void *_count)
{
	unsigned long long *count = _count;
	unsigned int counter = 0;

	printf_verbose("thread_begin %s, tid %lu\n",
			"dequeuer", urcu_get_thread_id());

	set_affinity();

	rcu_register_thread();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	assert(test_pop || test_pop_all);

	for (;;) {
		if (test_pop && test_pop_all) {
			/* both pop and pop all */
			if (counter & 1)
				do_test_pop(test_sync);
			else
				do_test_pop_all(test_sync);
			counter++;
		} else {
			if (test_pop)
				do_test_pop(test_sync);
			else
				do_test_pop_all(test_sync);
		}

		if (caa_unlikely(!test_duration_dequeue()))
			break;
		if (caa_unlikely(rduration))
			loop_sleep(rduration);
	}

	rcu_unregister_thread();

	printf_verbose("dequeuer thread_end, tid %lu, "
			"dequeues %llu, successful_dequeues %llu\n",
			urcu_get_thread_id(),
			URCU_TLS(nr_dequeues),
			URCU_TLS(nr_successful_dequeues));
	count[0] = URCU_TLS(nr_dequeues);
	count[1] = URCU_TLS(nr_successful_dequeues);
	return ((void*)2);
}
示例#5
0
void *thr_dequeuer(void *_count)
{
    unsigned long long *count = _count;

    printf_verbose("thread_begin %s, tid %lu\n",
                   "dequeuer", urcu_get_thread_id());

    set_affinity();

    rcu_register_thread();

    while (!test_go)
    {
    }
    cmm_smp_mb();

    for (;;) {
        struct cds_lfq_node_rcu *qnode;

        rcu_read_lock();
        qnode = cds_lfq_dequeue_rcu(&q);
        rcu_read_unlock();

        if (qnode) {
            struct test *node;

            node = caa_container_of(qnode, struct test, list);
            call_rcu(&node->rcu, free_node_cb);
            URCU_TLS(nr_successful_dequeues)++;
        }

        URCU_TLS(nr_dequeues)++;
        if (caa_unlikely(!test_duration_dequeue()))
            break;
        if (caa_unlikely(rduration))
            loop_sleep(rduration);
    }

    rcu_unregister_thread();
    printf_verbose("dequeuer thread_end, tid %lu, "
                   "dequeues %llu, successful_dequeues %llu\n",
                   urcu_get_thread_id(),
                   URCU_TLS(nr_dequeues),
                   URCU_TLS(nr_successful_dequeues));
    count[0] = URCU_TLS(nr_dequeues);
    count[1] = URCU_TLS(nr_successful_dequeues);
    return ((void*)2);
}
示例#6
0
static void *thr_enqueuer(void *_count)
{
	unsigned long long *count = _count;
	bool was_nonempty;

	printf_verbose("thread_begin %s, tid %lu\n",
			"enqueuer", urcu_get_thread_id());

	set_affinity();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		struct cds_wfs_node *node = malloc(sizeof(*node));
		if (!node)
			goto fail;
		cds_wfs_node_init(node);
		was_nonempty = cds_wfs_push(&s, node);
		URCU_TLS(nr_successful_enqueues)++;
		if (!was_nonempty)
			URCU_TLS(nr_empty_dest_enqueues)++;

		if (caa_unlikely(wdelay))
			loop_sleep(wdelay);
fail:
		URCU_TLS(nr_enqueues)++;
		if (caa_unlikely(!test_duration_enqueue()))
			break;
	}

	uatomic_inc(&test_enqueue_stopped);
	count[0] = URCU_TLS(nr_enqueues);
	count[1] = URCU_TLS(nr_successful_enqueues);
	count[2] = URCU_TLS(nr_empty_dest_enqueues);
	printf_verbose("enqueuer thread_end, tid %lu, "
			"enqueues %llu successful_enqueues %llu, "
			"empty_dest_enqueues %llu\n",
			urcu_get_thread_id(),
			URCU_TLS(nr_enqueues),
			URCU_TLS(nr_successful_enqueues),
			URCU_TLS(nr_empty_dest_enqueues));
	return ((void*)1);

}
示例#7
0
void *thr_enqueuer(void *_count)
{
    unsigned long long *count = _count;

    printf_verbose("thread_begin %s, tid %lu\n",
                   "enqueuer", urcu_get_thread_id());

    set_affinity();

    rcu_register_thread();

    while (!test_go)
    {
    }
    cmm_smp_mb();

    for (;;) {
        struct test *node = malloc(sizeof(*node));
        if (!node)
            goto fail;
        cds_lfq_node_init_rcu(&node->list);
        rcu_read_lock();
        cds_lfq_enqueue_rcu(&q, &node->list);
        rcu_read_unlock();
        URCU_TLS(nr_successful_enqueues)++;

        if (caa_unlikely(wdelay))
            loop_sleep(wdelay);
fail:
        URCU_TLS(nr_enqueues)++;
        if (caa_unlikely(!test_duration_enqueue()))
            break;
    }

    rcu_unregister_thread();

    count[0] = URCU_TLS(nr_enqueues);
    count[1] = URCU_TLS(nr_successful_enqueues);
    printf_verbose("enqueuer thread_end, tid %lu, "
                   "enqueues %llu successful_enqueues %llu\n",
                   urcu_get_thread_id(),
                   URCU_TLS(nr_enqueues),
                   URCU_TLS(nr_successful_enqueues));
    return ((void*)1);

}
int test_hash_rw_populate_hash(void)
{
	struct lfht_test_node *node;

	if (!init_populate)
		return 0;

	printf("Starting rw test\n");

	URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);

	if ((add_unique || add_replace) && init_populate * 10 > init_pool_size) {
		printf("WARNING: required to populate %lu nodes (-k), but random "
"pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
"larger random pool (-p option). This may take a while...\n", init_populate, init_pool_size);
	}

	while (URCU_TLS(nr_add) < init_populate) {
		struct cds_lfht_node *ret_node = NULL;

		node = malloc(sizeof(struct lfht_test_node));
		lfht_test_node_init(node,
			(void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % init_pool_size) + init_pool_offset),
			sizeof(void *));
		rcu_read_lock();
		if (add_unique) {
			ret_node = cds_lfht_add_unique(test_ht,
				test_hash(node->key, node->key_len, TEST_HASH_SEED),
				test_match, node->key, &node->node);
		} else {
			if (add_replace)
				ret_node = cds_lfht_add_replace(test_ht,
						test_hash(node->key, node->key_len, TEST_HASH_SEED),
						test_match, node->key, &node->node);
			else
				cds_lfht_add(test_ht,
					test_hash(node->key, node->key_len, TEST_HASH_SEED),
					&node->node);
		}
		rcu_read_unlock();
		if (add_unique && ret_node != &node->node) {
			free(node);
			URCU_TLS(nr_addexist)++;
		} else {
			if (add_replace && ret_node) {
				call_rcu(&to_test_node(ret_node)->head, free_node_cb);
				URCU_TLS(nr_addexist)++;
			} else {
				URCU_TLS(nr_add)++;
			}
		}
		URCU_TLS(nr_writes)++;
	}
	return 0;
}
示例#9
0
void *thr_dequeuer(void *_count)
{
	unsigned long long *count = _count;

	printf_verbose("thread_begin %s, tid %lu\n",
			"dequeuer", urcu_get_thread_id());

	set_affinity();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		struct cds_wfq_node *node = cds_wfq_dequeue_blocking(&q);

		if (node) {
			free(node);
			URCU_TLS(nr_successful_dequeues)++;
		}

		URCU_TLS(nr_dequeues)++;
		if (caa_unlikely(!test_duration_dequeue()))
			break;
		if (caa_unlikely(rduration))
			loop_sleep(rduration);
	}

	printf_verbose("dequeuer thread_end, tid %lu, "
			"dequeues %llu, successful_dequeues %llu\n",
			urcu_get_thread_id(),
			URCU_TLS(nr_dequeues),
			URCU_TLS(nr_successful_dequeues));
	count[0] = URCU_TLS(nr_dequeues);
	count[1] = URCU_TLS(nr_successful_dequeues);
	return ((void*)2);
}
示例#10
0
int main(int argc, char **argv)
{
    int err;
    pthread_t *tid_enqueuer, *tid_dequeuer;
    void *tret;
    unsigned long long *count_enqueuer, *count_dequeuer;
    unsigned long long tot_enqueues = 0, tot_dequeues = 0;
    unsigned long long tot_successful_enqueues = 0,
                       tot_successful_dequeues = 0;
    unsigned long long end_dequeues = 0;
    int i, a;

    if (argc < 4) {
        show_usage(argc, argv);
        return -1;
    }

    err = sscanf(argv[1], "%u", &nr_dequeuers);
    if (err != 1) {
        show_usage(argc, argv);
        return -1;
    }

    err = sscanf(argv[2], "%u", &nr_enqueuers);
    if (err != 1) {
        show_usage(argc, argv);
        return -1;
    }

    err = sscanf(argv[3], "%lu", &duration);
    if (err != 1) {
        show_usage(argc, argv);
        return -1;
    }

    for (i = 4; i < argc; i++) {
        if (argv[i][0] != '-')
            continue;
        switch (argv[i][1]) {
        case 'a':
            if (argc < i + 2) {
                show_usage(argc, argv);
                return -1;
            }
            a = atoi(argv[++i]);
            cpu_affinities[next_aff++] = a;
            use_affinity = 1;
            printf_verbose("Adding CPU %d affinity\n", a);
            break;
        case 'c':
            if (argc < i + 2) {
                show_usage(argc, argv);
                return -1;
            }
            rduration = atol(argv[++i]);
            break;
        case 'd':
            if (argc < i + 2) {
                show_usage(argc, argv);
                return -1;
            }
            wdelay = atol(argv[++i]);
            break;
        case 'v':
            verbose_mode = 1;
            break;
        }
    }

    printf_verbose("running test for %lu seconds, %u enqueuers, "
                   "%u dequeuers.\n",
                   duration, nr_enqueuers, nr_dequeuers);
    printf_verbose("Writer delay : %lu loops.\n", rduration);
    printf_verbose("Reader duration : %lu loops.\n", wdelay);
    printf_verbose("thread %-6s, tid %lu\n",
                   "main", urcu_get_thread_id());

    tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
    tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
    count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
    count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
    cds_lfq_init_rcu(&q, call_rcu);
    err = create_all_cpu_call_rcu_data(0);
    if (err) {
        printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
    }

    next_aff = 0;

    for (i = 0; i < nr_enqueuers; i++) {
        err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
                             &count_enqueuer[2 * i]);
        if (err != 0)
            exit(1);
    }
    for (i = 0; i < nr_dequeuers; i++) {
        err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
                             &count_dequeuer[2 * i]);
        if (err != 0)
            exit(1);
    }

    cmm_smp_mb();

    test_go = 1;

    for (i = 0; i < duration; i++) {
        sleep(1);
        if (verbose_mode) {
            fwrite(".", sizeof(char), 1, stdout);
            fflush(stdout);
        }
    }

    test_stop = 1;

    for (i = 0; i < nr_enqueuers; i++) {
        err = pthread_join(tid_enqueuer[i], &tret);
        if (err != 0)
            exit(1);
        tot_enqueues += count_enqueuer[2 * i];
        tot_successful_enqueues += count_enqueuer[2 * i + 1];
    }
    for (i = 0; i < nr_dequeuers; i++) {
        err = pthread_join(tid_dequeuer[i], &tret);
        if (err != 0)
            exit(1);
        tot_dequeues += count_dequeuer[2 * i];
        tot_successful_dequeues += count_dequeuer[2 * i + 1];
    }

    test_end(&q, &end_dequeues);
    err = cds_lfq_destroy_rcu(&q);
    assert(!err);

    printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
                   tot_enqueues, tot_dequeues);
    printf_verbose("total number of successful enqueues : %llu, "
                   "successful dequeues %llu\n",
                   tot_successful_enqueues, tot_successful_dequeues);
    printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
           "nr_dequeuers %3u "
           "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
           "successful enqueues %12llu successful dequeues %12llu "
           "end_dequeues %llu nr_ops %12llu\n",
           argv[0], duration, nr_enqueuers, wdelay,
           nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
           tot_successful_enqueues,
           tot_successful_dequeues, end_dequeues,
           tot_enqueues + tot_dequeues);
    if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
        printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
               "succ. dequeues + end dequeues %llu.\n",
               tot_successful_enqueues,
               tot_successful_dequeues + end_dequeues);

    free_all_cpu_call_rcu_data();
    free(count_enqueuer);
    free(count_dequeuer);
    free(tid_enqueuer);
    free(tid_dequeuer);
    return 0;
}
示例#11
0
int main(int argc, char **argv)
{
	int err;
	pthread_t *tid_reader, *tid_writer;
	void *tret;
	unsigned long long tot_reads = 0, tot_writes = 0;
	int i, a;

	if (argc < 4) {
		show_usage(argc, argv);
		return -1;
	}
	cmm_smp_mb();

	err = sscanf(argv[1], "%u", &nr_readers);
	if (err != 1) {
		show_usage(argc, argv);
		return -1;
	}

	err = sscanf(argv[2], "%u", &nr_writers);
	if (err != 1) {
		show_usage(argc, argv);
		return -1;
	}
	
	err = sscanf(argv[3], "%lu", &duration);
	if (err != 1) {
		show_usage(argc, argv);
		return -1;
	}

	for (i = 4; i < argc; i++) {
		if (argv[i][0] != '-')
			continue;
		switch (argv[i][1]) {
#ifdef DEBUG_YIELD
		case 'r':
			yield_active |= YIELD_READ;
			break;
		case 'w':
			yield_active |= YIELD_WRITE;
			break;
#endif
		case 'a':
			if (argc < i + 2) {
				show_usage(argc, argv);
				return -1;
			}
			a = atoi(argv[++i]);
			cpu_affinities[next_aff++] = a;
			use_affinity = 1;
			printf_verbose("Adding CPU %d affinity\n", a);
			break;
		case 'c':
			if (argc < i + 2) {
				show_usage(argc, argv);
				return -1;
			}
			rduration = atol(argv[++i]);
			break;
		case 'd':
			if (argc < i + 2) {
				show_usage(argc, argv);
				return -1;
			}
			wdelay = atol(argv[++i]);
			break;
		case 'e':
			if (argc < i + 2) {
				show_usage(argc, argv);
				return -1;
			}
			wduration = atol(argv[++i]);
			break;
		case 'v':
			verbose_mode = 1;
			break;
		}
	}

	printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
		duration, nr_readers, nr_writers);
	printf_verbose("Writer delay : %lu loops.\n", wdelay);
	printf_verbose("Reader duration : %lu loops.\n", rduration);
	printf_verbose("thread %-6s, tid %lu\n",
			"main", urcu_get_thread_id());

	tid_reader = calloc(nr_readers, sizeof(*tid_reader));
	tid_writer = calloc(nr_writers, sizeof(*tid_writer));
	tot_nr_reads = calloc(nr_readers, sizeof(*tot_nr_reads));
	tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
	per_thread_lock = calloc(nr_readers, sizeof(*per_thread_lock));
	for (i = 0; i < nr_readers; i++) {
		err = pthread_mutex_init(&per_thread_lock[i].lock, NULL);
		if (err != 0)
			exit(1);
	}

	next_aff = 0;

	for (i = 0; i < nr_readers; i++) {
		err = pthread_create(&tid_reader[i], NULL, thr_reader,
				     (void *)(long)i);
		if (err != 0)
			exit(1);
	}
	for (i = 0; i < nr_writers; i++) {
		err = pthread_create(&tid_writer[i], NULL, thr_writer,
				     (void *)(long)i);
		if (err != 0)
			exit(1);
	}

	cmm_smp_mb();

	test_go = 1;

	sleep(duration);

	test_stop = 1;

	for (i = 0; i < nr_readers; i++) {
		err = pthread_join(tid_reader[i], &tret);
		if (err != 0)
			exit(1);
		tot_reads += tot_nr_reads[i];
	}
	for (i = 0; i < nr_writers; i++) {
		err = pthread_join(tid_writer[i], &tret);
		if (err != 0)
			exit(1);
		tot_writes += tot_nr_writes[i];
	}

	printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
	       tot_writes);
	printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
		"nr_writers %3u "
		"wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
		argv[0], duration, nr_readers, rduration, wduration,
		nr_writers, wdelay, tot_reads, tot_writes,
		tot_reads + tot_writes);

	free(tid_reader);
	free(tid_writer);
	free(tot_nr_reads);
	free(tot_nr_writes);
	free(per_thread_lock);
	return 0;
}
示例#12
0
void *test_hash_rw_thr_writer(void *_count)
{
	struct lfht_test_node *node;
	struct cds_lfht_node *ret_node;
	struct cds_lfht_iter iter;
	struct wr_count *count = _count;
	int ret;

	printf_verbose("thread_begin %s, tid %lu\n",
			"writer", urcu_get_thread_id());

	URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);

	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)) {
			node = malloc(sizeof(struct lfht_test_node));
			lfht_test_node_init(node,
				(void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
				sizeof(void *));
			rcu_read_lock();
			if (add_unique) {
				ret_node = cds_lfht_add_unique(test_ht,
					test_hash(node->key, node->key_len, TEST_HASH_SEED),
					test_match, node->key, &node->node);
			} else {
				if (add_replace)
					ret_node = cds_lfht_add_replace(test_ht,
							test_hash(node->key, node->key_len, TEST_HASH_SEED),
							test_match, node->key, &node->node);
				else
					cds_lfht_add(test_ht,
						test_hash(node->key, node->key_len, TEST_HASH_SEED),
						&node->node);
			}
			rcu_read_unlock();
			if (add_unique && ret_node != &node->node) {
				free(node);
				URCU_TLS(nr_addexist)++;
			} else {
				if (add_replace && ret_node) {
					call_rcu(&to_test_node(ret_node)->head,
							free_node_cb);
					URCU_TLS(nr_addexist)++;
				} else {
					URCU_TLS(nr_add)++;
				}
			}
		} else {
			/* May delete */
			rcu_read_lock();
			cds_lfht_test_lookup(test_ht,
				(void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
				sizeof(void *), &iter);
			ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
			rcu_read_unlock();
			if (ret == 0) {
				node = cds_lfht_iter_get_test_node(&iter);
				call_rcu(&node->head, free_node_cb);
				URCU_TLS(nr_del)++;
			} else
				URCU_TLS(nr_delnoent)++;
		}
#if 0
		//if (URCU_TLS(nr_writes) % 100000 == 0) {
		if (URCU_TLS(nr_writes) % 1000 == 0) {
			rcu_read_lock();
			if (rand_r(&URCU_TLS(rand_lookup)) & 1) {
				ht_resize(test_ht, 1);
			} else {
				ht_resize(test_ht, -1);
			}
			rcu_read_unlock();
		}
#endif //0
		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, tid %lu\n",
			"writer", urcu_get_thread_id());
	printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
			"nr_delnoent %lu\n", urcu_get_thread_id(),
			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);
}