Beispiel #1
0
/*!
 * \brief Idle function for worker threads
 *
 * The worker waits here until it gets told by the threadpool
 * to wake up.
 *
 * worker is locked before entering this function.
 *
 * \param worker The idle worker
 * \retval 0 The thread is being woken up so that it can conclude.
 * \retval non-zero The thread is being woken up to do more work.
 */
static int worker_idle(struct worker_thread *worker)
{
	struct timeval start = ast_tvnow();
	struct timespec end = {
		.tv_sec = start.tv_sec + worker->options.idle_timeout,
		.tv_nsec = start.tv_usec * 1000,
	};
	while (!worker->wake_up) {
		if (worker->options.idle_timeout <= 0) {
			ast_cond_wait(&worker->cond, &worker->lock);
		} else if (ast_cond_timedwait(&worker->cond, &worker->lock, &end) == ETIMEDOUT) {
			break;
		}
	}

	if (!worker->wake_up) {
		ast_debug(1, "Worker thread idle timeout reached. Dying.\n");
		threadpool_idle_thread_dead(worker->pool, worker);
		worker->state = DEAD;
	}
	worker->wake_up = 0;
	return worker->state == ALIVE;
}

/*!
 * \brief Change a worker's state
 *
 * The threadpool calls into this function in order to let a worker know
 * how it should proceed.
 *
 * \retval -1 failure (state transition not permitted)
 * \retval 0 success
 */
static int worker_set_state(struct worker_thread *worker, enum worker_state state)
{
	SCOPED_MUTEX(lock, &worker->lock);

	switch (state) {
	case ALIVE:
		/* This can occur due to a race condition between being told to go active
		 * and an idle timeout happening.
		 */
		if (worker->state == DEAD) {
			return -1;
		}
		ast_assert(worker->state != ZOMBIE);
		break;
	case DEAD:
		break;
	case ZOMBIE:
		ast_assert(worker->state != DEAD);
		break;
	}

	worker->state = state;
	worker->wake_up = 1;
	ast_cond_signal(&worker->cond);

	return 0;
}
/*!
 * \brief Retrieve a ast_sip_contact_status object from sorcery creating
 *        one if not found.
 */
struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)
{
	struct ast_sip_contact_status *status;
	SCOPED_MUTEX(lock, &creation_lock);

	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (status) {
		return status;
	}

	status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (!status) {
		ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
			contact->aor, contact->uri);
		return NULL;
	}

	ast_string_field_set(status, uri, contact->uri);
	status->rtt_start = ast_tv(0, 0);
	status->rtt = 0;

	if (ast_sorcery_create(ast_sip_get_sorcery(), status)) {
		ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n",
			contact->uri);
		ao2_ref(status, -1);
		return NULL;
	}

	ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
		"+1", 1.0, ast_sip_get_contact_status_label(status->status));

	return status;
}
Beispiel #3
0
/*!
 * \brief a queued task to be used in the taskprocessor load test
 *
 * The task increments the number of tasks executed and puts the passed-in
 * data into the next slot in the array of random data.
 */
static int load_task(void *data)
{
	int *randdata = data;
	SCOPED_MUTEX(lock, &load_task_results.lock);
	load_task_results.task_rand[load_task_results.tasks_completed++] = *randdata;
	ast_cond_signal(&load_task_results.cond);
	return 0;
}
Beispiel #4
0
int ast_sem_getvalue(struct ast_sem *sem, int *sval)
{
	SCOPED_MUTEX(lock, &sem->mutex);

	ast_assert(sem->count >= 0);

	*sval = sem->count;

	return 0;
}
Beispiel #5
0
/*!
 * \brief Queued task for baseline test.
 *
 * The task simply sets a boolean to indicate the
 * task has been run and then signals a condition
 * saying it's complete
 */
static int task(void *data)
{
	struct task_data *task_data = data;

	SCOPED_MUTEX(lock, &task_data->lock);
	if (task_data->wait_time > 0) {
		usleep(task_data->wait_time * 1000);
	}
	task_data->task_complete = 1;
	ast_cond_signal(&task_data->cond);
	return 0;
}
Beispiel #6
0
static int shutdown_task_exec(void *data)
{
	struct shutdown_data *shutdown_data = data;
	SCOPED_MUTEX(lock, &shutdown_data->lock);
	shutdown_data->task_started = 1;
	ast_cond_signal(&shutdown_data->out);
	while (!shutdown_data->task_stop_waiting) {
		ast_cond_wait(&shutdown_data->in, &shutdown_data->lock);
	}
	shutdown_data->task_complete = 1;
	ast_cond_signal(&shutdown_data->out);
	return 0;
}
Beispiel #7
0
static int shutdown_waitfor_completion(struct shutdown_data *shutdown_data)
{
	struct timeval start = ast_tvnow();
	struct timespec end = {
		.tv_sec = start.tv_sec + 5,
		.tv_nsec = start.tv_usec * 1000
	};
	SCOPED_MUTEX(lock, &shutdown_data->lock);

	while (!shutdown_data->task_complete) {
		if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
			break;
		}
	}

	return shutdown_data->task_complete;
}

static int shutdown_has_completed(struct shutdown_data *shutdown_data)
{
	SCOPED_MUTEX(lock, &shutdown_data->lock);
	return shutdown_data->task_complete;
}
Beispiel #8
0
static int shutdown_waitfor_start(struct shutdown_data *shutdown_data)
{
	struct timeval start = ast_tvnow();
	struct timespec end = {
		.tv_sec = start.tv_sec + 5,
		.tv_nsec = start.tv_usec * 1000
	};
	SCOPED_MUTEX(lock, &shutdown_data->lock);

	while (!shutdown_data->task_started) {
		if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
			break;
		}
	}

	return shutdown_data->task_started;
}

static void shutdown_poke(struct shutdown_data *shutdown_data)
{
	SCOPED_MUTEX(lock, &shutdown_data->lock);
	shutdown_data->task_stop_waiting = 1;
	ast_cond_signal(&shutdown_data->in);
}
Beispiel #9
0
char *ast_crypt(const char *key, const char *salt)
{
	const char *crypted;
	SCOPED_MUTEX(lock, &crypt_mutex);

	crypted = crypt(key, salt);

	/* Crypt may return success even if it doesn't recognize the salt. But
	 * in those cases it always mangles the salt in some way.
	 */
	if (!crypted || !ast_begins_with(crypted, salt)) {
		return NULL;
	}

	return ast_strdup(crypted);
}
Beispiel #10
0
/*!
 * \brief Retrieve a ast_sip_contact_status object from sorcery creating
 *        one if not found.
 */
struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)
{
	struct ast_sip_contact_status *status;
	SCOPED_MUTEX(lock, &creation_lock);

	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (status) {
		return status;
	}

	status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (!status) {
		ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
			contact->aor, contact->uri);
		return NULL;
	}

	ast_string_field_set(status, uri, contact->uri);
	status->rtt_start = ast_tv(0, 0);
	status->rtt = 0;

	if (ast_sorcery_create(ast_sip_get_sorcery(), status)) {
		ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n",
			contact->uri);
		ao2_ref(status, -1);
		return NULL;
	}

	/* The permanent contact added after asterisk start should be qualified. */
	if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED) && ast_tvzero(contact->expiration_time)) {
		/*
		 * The FULLY_BOOTED to filter out contacts that already existed when asterisk started.
		 * The zero expiration_time to select only permanent contacts.
		 */
		ao2_ref((struct ast_sip_contact *) contact, +1);
		if (ast_sip_push_task(NULL, qualify_and_schedule_aor_contact, (struct ast_sip_contact *) contact)) {
			ao2_ref((struct ast_sip_contact *) contact, -1);
		}
	}

	ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
		"+1", 1.0, ast_sip_get_contact_status_label(status->status));

	return status;
}
Beispiel #11
0
int ast_sem_wait(struct ast_sem *sem)
{
	SCOPED_MUTEX(lock, &sem->mutex);

	ast_assert(sem->count >= 0);

	/* Wait for a non-zero count */
	++sem->waiters;
	while (sem->count == 0) {
		ast_cond_wait(&sem->cond, &sem->mutex);
	}
	--sem->waiters;

	/* Take it! */
	--sem->count;

	return 0;
}
Beispiel #12
0
/*!
 * \brief Wait for a task to execute.
 */
static int task_wait(struct task_data *task_data)
{
	struct timeval start = ast_tvnow();
	struct timespec end;
	SCOPED_MUTEX(lock, &task_data->lock);

	end.tv_sec = start.tv_sec + 30;
	end.tv_nsec = start.tv_usec * 1000;

	while (!task_data->task_complete) {
		int res;
		res = ast_cond_timedwait(&task_data->cond, &task_data->lock,
			&end);
		if (res == ETIMEDOUT) {
			return -1;
		}
	}

	return 0;
}
Beispiel #13
0
int ast_sem_post(struct ast_sem *sem)
{
	SCOPED_MUTEX(lock, &sem->mutex);

	ast_assert(sem->count >= 0);

	if (sem->count == AST_SEM_VALUE_MAX) {
		errno = EOVERFLOW;
		return -1;
	}

	/* Give it up! */
	++sem->count;

	/* Release a waiter, if needed */
	if (sem->waiters) {
		ast_cond_signal(&sem->cond);
	}

	return 0;
}
Beispiel #14
0
int ast_ari_add_handler(struct stasis_rest_handlers *handler)
{
	RAII_VAR(struct stasis_rest_handlers *, new_handler, NULL, ao2_cleanup);
	size_t old_size, new_size;

	SCOPED_MUTEX(lock, &root_handler_lock);

	old_size = sizeof(*new_handler) + root_handler->num_children * sizeof(handler);
	new_size = old_size + sizeof(handler);

	new_handler = ao2_alloc(new_size, NULL);
	if (!new_handler) {
		return -1;
	}
	memcpy(new_handler, root_handler, old_size);
	new_handler->children[new_handler->num_children++] = handler;

	ao2_cleanup(root_handler);
	ao2_ref(new_handler, +1);
	root_handler = new_handler;
	ast_module_ref(ast_module_info->self);
	return 0;
}
Beispiel #15
0
static void stasis_message_sink_dtor(void *obj)
{
	struct stasis_message_sink *sink = obj;

	{
		SCOPED_MUTEX(lock, &sink->lock);
		while (!sink->is_done) {
			/* Normally waiting forever is bad, but if we're not
			 * done, we're not done. */
			ast_cond_wait(&sink->cond, &sink->lock);
		}
	}

	ast_mutex_destroy(&sink->lock);
	ast_cond_destroy(&sink->cond);

	while (sink->num_messages > 0) {
		ao2_cleanup(sink->messages[--sink->num_messages]);
	}
	ast_free(sink->messages);
	sink->messages = NULL;
	sink->max_messages = 0;
}
Beispiel #16
0
/*!
 * \brief Idle function for worker threads
 *
 * The worker waits here until it gets told by the threadpool
 * to wake up.
 *
 * worker is locked before entering this function.
 *
 * \param worker The idle worker
 * \retval 0 The thread is being woken up so that it can conclude.
 * \retval non-zero The thread is being woken up to do more work.
 */
static int worker_idle(struct worker_thread *worker)
{
	struct timeval start = ast_tvnow();
	struct timespec end = {
		.tv_sec = start.tv_sec + worker->options.idle_timeout,
		.tv_nsec = start.tv_usec * 1000,
	};
	while (!worker->wake_up) {
		if (worker->options.idle_timeout <= 0) {
			ast_cond_wait(&worker->cond, &worker->lock);
		} else if (ast_cond_timedwait(&worker->cond, &worker->lock, &end) == ETIMEDOUT) {
			break;
		}
	}

	if (!worker->wake_up) {
		ast_debug(1, "Worker thread idle timeout reached. Dying.\n");
		threadpool_idle_thread_dead(worker->pool, worker);
		worker->state = DEAD;
	}
	worker->wake_up = 0;
	return worker->state == ALIVE;
}

/*!
 * \brief Change a worker's state
 *
 * The threadpool calls into this function in order to let a worker know
 * how it should proceed.
 */
static void worker_set_state(struct worker_thread *worker, enum worker_state state)
{
	SCOPED_MUTEX(lock, &worker->lock);
	worker->state = state;
	worker->wake_up = 1;
	ast_cond_signal(&worker->cond);
}
Beispiel #17
0
int ast_sem_wait(struct ast_sem *sem)
{
	int res;
	SCOPED_MUTEX(lock, &sem->mutex);

	ast_assert(sem->count >= 0);

	/* Wait for a non-zero count */
	++sem->waiters;
	while (sem->count == 0) {
		res = ast_cond_wait(&sem->cond, &sem->mutex);
		/* Give up on error */
		if (res != 0) {
			--sem->waiters;
			return res;
		}
	}
	--sem->waiters;

	/* Take it! */
	--sem->count;

	return 0;
}
Beispiel #18
0
int ast_crypt_validate(const char *key, const char *expected)
{
	SCOPED_MUTEX(lock, &crypt_mutex);
	return strcmp(expected, crypt(key, expected)) == 0;
}
Beispiel #19
0
static struct timespec make_deadline(int timeout_millis)
{
	struct timeval start = ast_tvnow();
	struct timeval delta = {
		.tv_sec = timeout_millis / 1000,
		.tv_usec = (timeout_millis % 1000) * 1000,
	};
	struct timeval deadline_tv = ast_tvadd(start, delta);
	struct timespec deadline = {
		.tv_sec = deadline_tv.tv_sec,
		.tv_nsec = 1000 * deadline_tv.tv_usec,
	};

	return deadline;
}

struct stasis_message_sink *stasis_message_sink_create(void)
{
	RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);

	sink = ao2_alloc(sizeof(*sink), stasis_message_sink_dtor);
	if (!sink) {
		return NULL;
	}
	ast_mutex_init(&sink->lock);
	ast_cond_init(&sink->cond, NULL);
	sink->max_messages = 4;
	sink->messages =
		ast_malloc(sizeof(*sink->messages) * sink->max_messages);
	if (!sink->messages) {
		return NULL;
	}
	ao2_ref(sink, +1);
	return sink;
}

/*!
 * \brief Implementation of the stasis_message_sink_cb() callback.
 *
 * Why the roundabout way of exposing this via stasis_message_sink_cb()? Well,
 * it has to do with how we load modules.
 *
 * Modules have their own metadata compiled into them in the module info block
 * at the end of the file.  This includes dependency information in the
 * \c nonoptreq field.
 *
 * Asterisk loads the module, inspects the field, then loads any needed
 * dependencies. This works because Asterisk passes \c RTLD_LAZY to the initial
 * dlopen(), which defers binding function references until they are called.
 *
 * But when you take the address of a function, that function needs to be
 * available at load time. So if some module used the address of
 * message_sink_cb() directly, and \c res_stasis_test.so wasn't loaded yet, then
 * that module would fail to load.
 *
 * The stasis_message_sink_cb() function gives us a layer of indirection so that
 * the initial lazy binding will still work as expected.
 */
static void message_sink_cb(void *data, struct stasis_subscription *sub,
	struct stasis_message *message)
{
	struct stasis_message_sink *sink = data;

	SCOPED_MUTEX(lock, &sink->lock);

	if (stasis_subscription_final_message(sub, message)) {
		sink->is_done = 1;
		ast_cond_signal(&sink->cond);
		return;
	}

	if (stasis_subscription_change_type() == stasis_message_type(message)) {
		/* Ignore subscription changes */
		return;
	}

	if (sink->num_messages == sink->max_messages) {
		size_t new_max_messages = sink->max_messages * 2;
		struct stasis_message **new_messages = ast_realloc(
			sink->messages,
			sizeof(*new_messages) * new_max_messages);
		if (!new_messages) {
			return;
		}
		sink->max_messages = new_max_messages;
		sink->messages = new_messages;
	}

	ao2_ref(message, +1);
	sink->messages[sink->num_messages++] = message;
	ast_cond_signal(&sink->cond);
}

stasis_subscription_cb stasis_message_sink_cb(void)
{
	return message_sink_cb;
}


int stasis_message_sink_wait_for_count(struct stasis_message_sink *sink,
	int num_messages, int timeout_millis)
{
	struct timespec deadline = make_deadline(timeout_millis);

	SCOPED_MUTEX(lock, &sink->lock);
	while (sink->num_messages < num_messages) {
		int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);

		if (r == ETIMEDOUT) {
			break;
		}
		if (r != 0) {
			ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
				strerror(r));
			break;
		}
	}
	return sink->num_messages;
}

int stasis_message_sink_should_stay(struct stasis_message_sink *sink,
	int num_messages, int timeout_millis)
{
	struct timespec deadline = make_deadline(timeout_millis);

	SCOPED_MUTEX(lock, &sink->lock);
	while (sink->num_messages == num_messages) {
		int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);

		if (r == ETIMEDOUT) {
			break;
		}
		if (r != 0) {
			ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
				strerror(r));
			break;
		}
	}
	return sink->num_messages;
}

int stasis_message_sink_wait_for(struct stasis_message_sink *sink, int start,
	stasis_wait_cb cmp_cb, const void *data, int timeout_millis)
{
	struct timespec deadline = make_deadline(timeout_millis);

	SCOPED_MUTEX(lock, &sink->lock);

	/* wait for the start */
	while (sink->num_messages < start + 1) {
		int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);

		if (r == ETIMEDOUT) {
			/* Timed out waiting for the start */
			return -1;
		}
		if (r != 0) {
			ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
				strerror(r));
			return -2;
		}
	}


	while (!cmp_cb(sink->messages[start], data)) {
		++start;

		while (sink->num_messages < start + 1) {
			int r = ast_cond_timedwait(&sink->cond,
				&sink->lock, &deadline);

			if (r == ETIMEDOUT) {
				return -1;
			}
			if (r != 0) {
				ast_log(LOG_ERROR,
					"Unexpected condition error: %s\n",
					strerror(r));
				return -2;
			}
		}
	}

	return start;
}

struct stasis_message *stasis_test_message_create(void)
{
	RAII_VAR(void *, data, NULL, ao2_cleanup);

	if (!stasis_test_message_type()) {
		return NULL;
	}

	/* We just need the unique pointer; don't care what's in it */
	data = ao2_alloc(1, NULL);
	if (!data) {
		return NULL;
	}

	return stasis_message_create(stasis_test_message_type(), data);
}
Beispiel #20
0
static struct stasis_rest_handlers *get_root_handler(void)
{
    SCOPED_MUTEX(lock, &root_handler_lock);
    ao2_ref(root_handler, +1);
    return root_handler;
}