Beispiel #1
0
/*
 * Return an allocated lttng hashtable.
 */
LTTNG_HIDDEN
struct lttng_ht *lttng_ht_new(unsigned long size, int type)
{
	struct lttng_ht *ht;

	/* Test size */
	if (!size)
		size = DEFAULT_HT_SIZE;

	pthread_mutex_lock(&seed_lock);
	if (!seed_init) {
		lttng_ht_seed = (unsigned long) time(NULL);
		seed_init = true;
	}
	pthread_mutex_unlock(&seed_lock);

	ht = zmalloc(sizeof(*ht));
	if (ht == NULL) {
		PERROR("zmalloc lttng_ht");
		goto error;
	}

	ht->ht = cds_lfht_new(size, min_hash_alloc_size, max_hash_buckets_size,
			CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
	/*
	 * There is already an assert in the RCU hashtable code so if the ht is
	 * NULL here there is a *huge* problem.
	 */
	assert(ht->ht);

	switch (type) {
	case LTTNG_HT_TYPE_STRING:
		ht->match_fct = match_str;
		ht->hash_fct = hash_key_str;
		break;
	case LTTNG_HT_TYPE_ULONG:
		ht->match_fct = match_ulong;
		ht->hash_fct = hash_key_ulong;
		break;
	case LTTNG_HT_TYPE_U64:
		ht->match_fct = match_u64;
		ht->hash_fct = hash_key_u64;
		break;
	case LTTNG_HT_TYPE_TWO_U64:
		ht->match_fct = match_two_u64;
		ht->hash_fct = hash_key_two_u64;
		break;
	default:
		ERR("Unknown lttng hashtable type %d", type);
		lttng_ht_destroy(ht);
		goto error;
	}

	DBG3("Created hashtable size %lu at %p of type %d", size, ht->ht, type);

	return ht;

error:
	return NULL;
}
void *thread_ht_cleanup(void *data)
{
	int ret, i, pollfd, err = -1;
	ssize_t size_ret;
	uint32_t revents, nb_fd;
	struct lttng_poll_event events;

	DBG("[ht-thread] startup.");

	rcu_register_thread();
	rcu_thread_online();

	health_register(health_sessiond, HEALTH_SESSIOND_TYPE_HT_CLEANUP);

	health_code_update();

	ret = sessiond_set_thread_pollset(&events, 2);
	if (ret < 0) {
		goto error_poll_create;
	}

	/* Add pipe to the pollset. */
	ret = lttng_poll_add(&events, ht_cleanup_pipe[0], LPOLLIN | LPOLLERR);
	if (ret < 0) {
		goto error;
	}

	health_code_update();

	while (1) {
		DBG3("[ht-thread] Polling on %d fds.",
			LTTNG_POLL_GETNB(&events));

		/* Inifinite blocking call, waiting for transmission */
restart:
		health_poll_entry();
		ret = lttng_poll_wait(&events, -1);
		health_poll_exit();
		if (ret < 0) {
			/*
			 * Restart interrupted system call.
			 */
			if (errno == EINTR) {
				goto restart;
			}
			goto error;
		}

		nb_fd = ret;

		for (i = 0; i < nb_fd; i++) {
			struct lttng_ht *ht;

			health_code_update();

			/* Fetch once the poll data */
			revents = LTTNG_POLL_GETEV(&events, i);
			pollfd = LTTNG_POLL_GETFD(&events, i);

			/* Thread quit pipe has been closed. Killing thread. */
			ret = sessiond_check_thread_quit_pipe(pollfd, revents);
			if (ret) {
				err = 0;
				goto exit;
			}
			assert(pollfd == ht_cleanup_pipe[0]);

			if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
				ERR("ht cleanup pipe error");
				goto error;
			} else if (!(revents & LPOLLIN)) {
				/* No POLLIN and not a catched error, stop the thread. */
				ERR("ht cleanup failed. revent: %u", revents);
				goto error;
			}

			/* Get socket from dispatch thread. */
			size_ret = lttng_read(ht_cleanup_pipe[0], &ht,
					sizeof(ht));
			if (size_ret < sizeof(ht)) {
				PERROR("ht cleanup notify pipe");
				goto error;
			}
			health_code_update();
			/*
			 * The whole point of this thread is to call
			 * lttng_ht_destroy from a context that is NOT:
			 * 1) a read-side RCU lock,
			 * 2) a call_rcu thread.
			 */
			lttng_ht_destroy(ht);

			health_code_update();
		}
	}

exit:
error:
	lttng_poll_clean(&events);
error_poll_create:
	utils_close_pipe(ht_cleanup_pipe);
	ht_cleanup_pipe[0] = ht_cleanup_pipe[1] = -1;
	DBG("[ust-thread] cleanup complete.");
	if (err) {
		health_error();
		ERR("Health error occurred in %s", __func__);
	}
	health_unregister(health_sessiond);
	rcu_thread_offline();
	rcu_unregister_thread();
	return NULL;
}