Exemple #1
0
/*
 * Always called with rcu_registry lock held. Releases this lock between
 * iterations and grabs it again. Holds the lock when it returns.
 */
static void wait_for_readers(struct cds_list_head *input_readers,
			struct cds_list_head *cur_snap_readers,
			struct cds_list_head *qsreaders)
{
	unsigned int wait_loops = 0;
	struct rcu_reader *index, *tmp;

	/*
	 * Wait for each thread URCU_TLS(rcu_reader).ctr to either
	 * indicate quiescence (offline), or for them to observe the
	 * current rcu_gp.ctr value.
	 */
	for (;;) {
		if (wait_loops < RCU_QS_ACTIVE_ATTEMPTS)
			wait_loops++;
		if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) {
			uatomic_set(&rcu_gp.futex, -1);
			/*
			 * Write futex before write waiting (the other side
			 * reads them in the opposite order).
			 */
			cmm_smp_wmb();
			cds_list_for_each_entry(index, input_readers, node) {
				_CMM_STORE_SHARED(index->waiting, 1);
			}
			/* Write futex before read reader_gp */
			cmm_smp_mb();
		}
Exemple #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);
}
int compat_futex_async(int32_t *uaddr, int op, int32_t val,
                       const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
{
    /*
     * Check if NULL. Don't let users expect that they are taken into
     * account.
     */
    assert(!timeout);
    assert(!uaddr2);
    assert(!val3);

    /*
     * Ensure previous memory operations on uaddr have completed.
     */
    cmm_smp_mb();

    switch (op) {
    case FUTEX_WAIT:
        while (*uaddr == val)
            poll(NULL, 0, 10);
        break;
    case FUTEX_WAKE:
        break;
    default:
        return -EINVAL;
    }
    return 0;
}
Exemple #4
0
void *thr_writer(void *_count)
{
	unsigned long long *count = _count;

	printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
			"writer", (unsigned long) pthread_self(),
			(unsigned long) gettid());

	set_affinity();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		pthread_rwlock_wrlock(&lock);
		test_array.a = 0;
		test_array.a = 8;
		if (caa_unlikely(wduration))
			loop_sleep(wduration);
		pthread_rwlock_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, thread id : %lx, tid %lu\n",
			"writer", (unsigned long) pthread_self(),
			(unsigned long) gettid());
	*count = URCU_TLS(nr_writes);
	return ((void*)2);
}
Exemple #5
0
/*
 * Prepare futex.
 */
LTTNG_HIDDEN
void futex_nto1_prepare(int32_t *futex)
{
	uatomic_set(futex, -1);
	cmm_smp_mb();

	DBG("Futex n to 1 prepare done");
}
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);

}
Exemple #7
0
/*
 * Wait futex.
 */
LTTNG_HIDDEN
void futex_nto1_wait(int32_t *futex)
{
	cmm_smp_mb();

	if (uatomic_read(futex) == -1) {
		futex_async(futex, FUTEX_WAIT, -1, NULL, NULL, 0);
	}

	DBG("Futex n to 1 wait done");
}
void *thr_dequeuer(void *_count)
{
	unsigned long long *count = _count;
	int ret;

	printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
			"dequeuer", pthread_self(), (unsigned long)gettid());

	set_affinity();

	ret = rcu_defer_register_thread();
	if (ret) {
		printf("Error in rcu_defer_register_thread\n");
		exit(-1);
	}
	rcu_register_thread();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		struct cds_lfq_node_rcu *qnode;
		struct test *node;

		rcu_read_lock();
		qnode = cds_lfq_dequeue_rcu(&q);
		node = caa_container_of(qnode, struct test, list);
		rcu_read_unlock();

		if (node) {
			call_rcu(&node->rcu, free_node_cb);
			nr_successful_dequeues++;
		}

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

	rcu_unregister_thread();
	rcu_defer_unregister_thread();
	printf_verbose("dequeuer thread_end, thread id : %lx, tid %lu, "
		       "dequeues %llu, successful_dequeues %llu\n",
		       pthread_self(), (unsigned long)gettid(), nr_dequeues,
		       nr_successful_dequeues);
	count[0] = nr_dequeues;
	count[1] = nr_successful_dequeues;
	return ((void*)2);
}
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);
}
Exemple #10
0
static void *thr_enqueuer(void *_count)
{
	unsigned long long *count = _count;
	bool was_nonempty;

	printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
			"enqueuer", (unsigned long) pthread_self(),
			(unsigned long) gettid());

	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, thread id : %lx, tid %lu, "
		       "enqueues %llu successful_enqueues %llu, "
		       "empty_dest_enqueues %llu\n",
		       pthread_self(),
			(unsigned long) gettid(),
		       URCU_TLS(nr_enqueues),
		       URCU_TLS(nr_successful_enqueues),
		       URCU_TLS(nr_empty_dest_enqueues));
	return ((void*)1);

}
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);
}
Exemple #12
0
int lttng_ust_enable_trace_clock_override(void)
{
	if (CMM_LOAD_SHARED(lttng_trace_clock))
		return -EBUSY;
	if (!user_tc.read64)
		return -EINVAL;
	if (!user_tc.freq)
		return -EINVAL;
	if (!user_tc.name)
		return -EINVAL;
	if (!user_tc.description)
		return -EINVAL;
	/* Use default uuid cb when NULL */
	cmm_smp_mb();	/* Store callbacks before trace clock */
	CMM_STORE_SHARED(lttng_trace_clock, &user_tc);
	return 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);

}
void *thr_writer(void *data)
{
	unsigned long wtidx = (unsigned long)data;
	long tidx;

	printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
			"writer", (unsigned long) pthread_self(),
			(unsigned long) gettid());

	set_affinity();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		for (tidx = 0; tidx < nr_readers; tidx++) {
			pthread_mutex_lock(&per_thread_lock[tidx].lock);
		}
		test_array.a = 0;
		test_array.a = 8;
		if (caa_unlikely(wduration))
			loop_sleep(wduration);
		for (tidx = (long)nr_readers - 1; tidx >= 0; tidx--) {
			pthread_mutex_unlock(&per_thread_lock[tidx].lock);
		}
		URCU_TLS(nr_writes)++;
		if (caa_unlikely(!test_duration_write()))
			break;
		if (caa_unlikely(wdelay))
			loop_sleep(wdelay);
	}

	printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
			"writer", (unsigned long) pthread_self(),
			(unsigned long) gettid());
	tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
	return ((void*)2);
}
void *thr_enqueuer(void *_count)
{
	unsigned long long *count = _count;

	printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
			"enqueuer", pthread_self(), (unsigned long)gettid());

	set_affinity();

	while (!test_go)
	{
	}
	cmm_smp_mb();

	for (;;) {
		struct cds_wfq_node *node = malloc(sizeof(*node));
		if (!node)
			goto fail;
		cds_wfq_node_init(node);
		cds_wfq_enqueue(&q, node);
		nr_successful_enqueues++;

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

	count[0] = nr_enqueues;
	count[1] = nr_successful_enqueues;
	printf_verbose("enqueuer thread_end, thread id : %lx, tid %lu, "
		       "enqueues %llu successful_enqueues %llu\n",
		       pthread_self(), (unsigned long)gettid(), nr_enqueues,
		       nr_successful_enqueues);
	return ((void*)1);

}
Exemple #16
0
void *thr_dequeuer(void *_count)
{
	unsigned long long *count = _count;

	printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
			"dequeuer", (unsigned long) pthread_self(),
			(unsigned long) gettid());

	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, thread id : %lx, tid %lu, "
		       "dequeues %llu, successful_dequeues %llu\n",
		       pthread_self(),
			(unsigned long) gettid(),
		       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);
}
int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
                         const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
{
    int ret, gret = 0;

    /*
     * Check if NULL. Don't let users expect that they are taken into
     * account.
     */
    assert(!timeout);
    assert(!uaddr2);
    assert(!val3);

    /*
     * memory barriers to serialize with the previous uaddr modification.
     */
    cmm_smp_mb();

    ret = pthread_mutex_lock(&__urcu_compat_futex_lock);
    assert(!ret);
    switch (op) {
    case FUTEX_WAIT:
        if (*uaddr != val)
            goto end;
        pthread_cond_wait(&__urcu_compat_futex_cond, &__urcu_compat_futex_lock);
        break;
    case FUTEX_WAKE:
        pthread_cond_broadcast(&__urcu_compat_futex_cond);
        break;
    default:
        gret = -EINVAL;
    }
end:
    ret = pthread_mutex_unlock(&__urcu_compat_futex_lock);
    assert(!ret);
    return gret;
}
Exemple #18
0
/*
 * Wait futex.
 */
LTTNG_HIDDEN
void futex_nto1_wait(int32_t *futex)
{
	cmm_smp_mb();

	if (uatomic_read(futex) != -1)
		goto end;
	while (futex_async(futex, FUTEX_WAIT, -1, NULL, NULL, 0)) {
		switch (errno) {
		case EWOULDBLOCK:
			/* Value already changed. */
			goto end;
		case EINTR:
			/* Retry if interrupted by signal. */
			break;	/* Get out of switch. */
		default:
			/* Unexpected error. */
			PERROR("futex_async");
			abort();
		}
	}
end:
	DBG("Futex n to 1 wait done");
}
Exemple #19
0
int main(int argc, char **argv)
{
	int err;
	pthread_t *tid_reader, *tid_writer;
	void *tret;
	unsigned long long *count_reader, *count_writer;
	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, thread id : %lx, tid %lu\n",
			"main", (unsigned long) 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);

	next_aff = 0;

	for (i = 0; i < nr_readers; i++) {
		err = pthread_create(&tid_reader[i], NULL, thr_reader,
				     &count_reader[i]);
		if (err != 0)
			exit(1);
	}
	for (i = 0; i < nr_writers; i++) {
		err = pthread_create(&tid_writer[i], NULL, thr_writer,
				     &count_writer[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 += 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];
	}

	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(count_reader);
	free(count_writer);
	return 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;
}
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, thread id : %lx, tid %lu\n",
			"main", pthread_self(), (unsigned long)gettid());

	tid_enqueuer = malloc(sizeof(*tid_enqueuer) * nr_enqueuers);
	tid_dequeuer = malloc(sizeof(*tid_dequeuer) * nr_dequeuers);
	count_enqueuer = malloc(2 * sizeof(*count_enqueuer) * nr_enqueuers);
	count_dequeuer = malloc(2 * sizeof(*count_dequeuer) * nr_dequeuers);
	cds_wfq_init(&q);

	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)
			write (1, ".", 1);
	}

	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);

	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(count_enqueuer);
	free(count_dequeuer);
	free(tid_enqueuer);
	free(tid_dequeuer);
	return 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);
}
/*
 * main
 */
int main(int argc, char **argv)
{
	int ret = 0, retval = 0;
	void *status;

	if (set_signal_handler()) {
		retval = -1;
		goto exit_set_signal_handler;
	}

	/* Parse arguments */
	progname = argv[0];
	if (parse_args(argc, argv)) {
		retval = -1;
		goto exit_options;
	}

	/* Daemonize */
	if (opt_daemon) {
		int i;

		/*
		 * fork
		 * child: setsid, close FD 0, 1, 2, chdir /
		 * parent: exit (if fork is successful)
		 */
		ret = daemon(0, 0);
		if (ret < 0) {
			PERROR("daemon");
			retval = -1;
			goto exit_options;
		}
		/*
		 * We are in the child. Make sure all other file
		 * descriptors are closed, in case we are called with
		 * more opened file descriptors than the standard ones.
		 */
		for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
			(void) close(i);
		}
	}

	/*
	 * Starting from here, we can create threads. This needs to be after
	 * lttng_daemonize due to RCU.
	 */

	health_consumerd = health_app_create(NR_HEALTH_CONSUMERD_TYPES);
	if (!health_consumerd) {
		retval = -1;
		goto exit_health_consumerd_cleanup;
	}

	/* Set up max poll set size */
	if (lttng_poll_set_max_size()) {
		retval = -1;
		goto exit_init_data;
	}

	if (*command_sock_path == '\0') {
		switch (opt_type) {
		case LTTNG_CONSUMER_KERNEL:
			ret = snprintf(command_sock_path, PATH_MAX,
					DEFAULT_KCONSUMERD_CMD_SOCK_PATH,
					DEFAULT_LTTNG_RUNDIR);
			if (ret < 0) {
				retval = -1;
				goto exit_init_data;
			}
			break;
		case LTTNG_CONSUMER64_UST:
			ret = snprintf(command_sock_path, PATH_MAX,
					DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH,
					DEFAULT_LTTNG_RUNDIR);
			if (ret < 0) {
				retval = -1;
				goto exit_init_data;
			}
			break;
		case LTTNG_CONSUMER32_UST:
			ret = snprintf(command_sock_path, PATH_MAX,
					DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH,
					DEFAULT_LTTNG_RUNDIR);
			if (ret < 0) {
				retval = -1;
				goto exit_init_data;
			}
			break;
		default:
			ERR("Unknown consumerd type");
			retval = -1;
			goto exit_init_data;
		}
	}

	/* Init */
	if (lttng_consumer_init()) {
		retval = -1;
		goto exit_init_data;
	}

	/* Initialize communication library */
	lttcomm_init();
	/* Initialize TCP timeout values */
	lttcomm_inet_init();

	if (!getuid()) {
		/* Set limit for open files */
		set_ulimit();
	}

	/* create the consumer instance with and assign the callbacks */
	ctx = lttng_consumer_create(opt_type, lttng_consumer_read_subbuffer,
		NULL, lttng_consumer_on_recv_stream, NULL);
	if (!ctx) {
		retval = -1;
		goto exit_init_data;
	}

	lttng_consumer_set_command_sock_path(ctx, command_sock_path);
	if (*error_sock_path == '\0') {
		switch (opt_type) {
		case LTTNG_CONSUMER_KERNEL:
			ret = snprintf(error_sock_path, PATH_MAX,
					DEFAULT_KCONSUMERD_ERR_SOCK_PATH,
					DEFAULT_LTTNG_RUNDIR);
			if (ret < 0) {
				retval = -1;
				goto exit_init_data;
			}
			break;
		case LTTNG_CONSUMER64_UST:
			ret = snprintf(error_sock_path, PATH_MAX,
					DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH,
					DEFAULT_LTTNG_RUNDIR);
			if (ret < 0) {
				retval = -1;
				goto exit_init_data;
			}
			break;
		case LTTNG_CONSUMER32_UST:
			ret = snprintf(error_sock_path, PATH_MAX,
					DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH,
					DEFAULT_LTTNG_RUNDIR);
			if (ret < 0) {
				retval = -1;
				goto exit_init_data;
			}
			break;
		default:
			ERR("Unknown consumerd type");
			retval = -1;
			goto exit_init_data;
		}
	}

	/* Connect to the socket created by lttng-sessiond to report errors */
	DBG("Connecting to error socket %s", error_sock_path);
	ret = lttcomm_connect_unix_sock(error_sock_path);
	/*
	 * Not a fatal error, but all communication with lttng-sessiond will
	 * fail.
	 */
	if (ret < 0) {
		WARN("Cannot connect to error socket (is lttng-sessiond started?)");
	}
	lttng_consumer_set_error_sock(ctx, ret);

	/*
	 * Block RT signals used for UST periodical metadata flush and the live
	 * timer in main, and create a dedicated thread to handle these signals.
	 */
	if (consumer_signal_init()) {
		retval = -1;
		goto exit_init_data;
	}

	ctx->type = opt_type;

	if (utils_create_pipe(health_quit_pipe)) {
		retval = -1;
		goto exit_health_pipe;
	}

	/* Create thread to manage the client socket */
	ret = pthread_create(&health_thread, NULL,
			thread_manage_health, (void *) NULL);
	if (ret) {
		errno = ret;
		PERROR("pthread_create health");
		retval = -1;
		goto exit_health_thread;
	}

	/*
	 * Wait for health thread to be initialized before letting the
	 * sessiond thread reply to the sessiond that we are ready.
	 */
	while (uatomic_read(&lttng_consumer_ready)) {
		usleep(100000);
	}
	cmm_smp_mb();	/* Read ready before following operations */

	/* Create thread to manage channels */
	ret = pthread_create(&channel_thread, NULL,
			consumer_thread_channel_poll,
			(void *) ctx);
	if (ret) {
		errno = ret;
		PERROR("pthread_create");
		retval = -1;
		goto exit_channel_thread;
	}

	/* Create thread to manage the polling/writing of trace metadata */
	ret = pthread_create(&metadata_thread, NULL,
			consumer_thread_metadata_poll,
			(void *) ctx);
	if (ret) {
		errno = ret;
		PERROR("pthread_create");
		retval = -1;
		goto exit_metadata_thread;
	}

	/* Create thread to manage the polling/writing of trace data */
	ret = pthread_create(&data_thread, NULL, consumer_thread_data_poll,
			(void *) ctx);
	if (ret) {
		errno = ret;
		PERROR("pthread_create");
		retval = -1;
		goto exit_data_thread;
	}

	/* Create the thread to manage the receive of fd */
	ret = pthread_create(&sessiond_thread, NULL,
			consumer_thread_sessiond_poll,
			(void *) ctx);
	if (ret) {
		errno = ret;
		PERROR("pthread_create");
		retval = -1;
		goto exit_sessiond_thread;
	}

	/*
	 * Create the thread to manage the UST metadata periodic timer and
	 * live timer.
	 */
	ret = pthread_create(&metadata_timer_thread, NULL,
			consumer_timer_thread, (void *) ctx);
	if (ret) {
		errno = ret;
		PERROR("pthread_create");
		retval = -1;
		goto exit_metadata_timer_thread;
	}

	ret = pthread_detach(metadata_timer_thread);
	if (ret) {
		errno = ret;
		PERROR("pthread_detach");
		retval = -1;
		goto exit_metadata_timer_detach;
	}

	/*
	 * This is where we start awaiting program completion (e.g. through
	 * signal that asks threads to teardown.
	 */

exit_metadata_timer_detach:
exit_metadata_timer_thread:
	ret = pthread_join(sessiond_thread, &status);
	if (ret) {
		errno = ret;
		PERROR("pthread_join sessiond_thread");
		retval = -1;
	}
exit_sessiond_thread:

	ret = pthread_join(data_thread, &status);
	if (ret) {
		errno = ret;
		PERROR("pthread_join data_thread");
		retval = -1;
	}
exit_data_thread:

	ret = pthread_join(metadata_thread, &status);
	if (ret) {
		errno = ret;
		PERROR("pthread_join metadata_thread");
		retval = -1;
	}
exit_metadata_thread:

	ret = pthread_join(channel_thread, &status);
	if (ret) {
		errno = ret;
		PERROR("pthread_join channel_thread");
		retval = -1;
	}
exit_channel_thread:

	ret = pthread_join(health_thread, &status);
	if (ret) {
		errno = ret;
		PERROR("pthread_join health_thread");
		retval = -1;
	}
exit_health_thread:

	utils_close_pipe(health_quit_pipe);
exit_health_pipe:

exit_init_data:
	lttng_consumer_destroy(ctx);
	lttng_consumer_cleanup();

	if (health_consumerd) {
		health_app_destroy(health_consumerd);
	}
exit_health_consumerd_cleanup:

exit_options:

exit_set_signal_handler:
	if (!retval) {
		exit(EXIT_SUCCESS);
	} else {
		exit(EXIT_FAILURE);
	}
}