Linux Audio

Check our new training course

Loading...
/*
 * Copyright (c) 2017 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @addtogroup t_poll_api
 * @{
 * @defgroup t_poll_api_basic test_poll_api_basic
 * @brief TestPurpose: verify zephyr poll apis across different context
 * - API coverage
 *   -# k_sem_init K_SEMA_DEFINE
 *   -# k_sem_take k_sema_give k_sema_reset
 *   -# k_sem_count_get
 * @}
 */

#include <ztest.h>
#include <kernel.h>

/* global values and data structures */
struct fifo_msg {
	void *private;
	u32_t msg;
};

#define SIGNAL_RESULT 0x1ee7d00d
#define FIFO_MSG_VALUE 0xdeadbeef

/* verify k_poll() without waiting */
static struct k_sem no_wait_sem;
static struct k_fifo no_wait_fifo;
static struct k_poll_signal no_wait_signal;

void test_poll_no_wait(void)
{
	struct fifo_msg msg = { NULL, FIFO_MSG_VALUE }, *msg_ptr;

	k_sem_init(&no_wait_sem, 1, 1);
	k_fifo_init(&no_wait_fifo);
	k_poll_signal_init(&no_wait_signal);

	struct k_poll_event events[] = {
		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
					 K_POLL_MODE_NOTIFY_ONLY,
					 &no_wait_sem),
		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
					 K_POLL_MODE_NOTIFY_ONLY,
					 &no_wait_fifo),
		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
					 K_POLL_MODE_NOTIFY_ONLY,
					 &no_wait_signal),
	};

	/* test polling events that are already ready */
	k_fifo_put(&no_wait_fifo, &msg);
	k_poll_signal(&no_wait_signal, SIGNAL_RESULT);

	zassert_equal(k_poll(events, ARRAY_SIZE(events), 0), 0, "");

	zassert_equal(events[0].state, K_POLL_STATE_SEM_AVAILABLE, "");
	zassert_equal(k_sem_take(&no_wait_sem, 0), 0, "");

	zassert_equal(events[1].state, K_POLL_STATE_FIFO_DATA_AVAILABLE, "");
	msg_ptr = k_fifo_get(&no_wait_fifo, 0);
	zassert_not_null(msg_ptr, "");
	zassert_equal(msg_ptr, &msg, "");
	zassert_equal(msg_ptr->msg, FIFO_MSG_VALUE, "");

	zassert_equal(events[2].state, K_POLL_STATE_SIGNALED, "");
	zassert_equal(no_wait_signal.signaled, 1, "");
	zassert_equal(no_wait_signal.result, SIGNAL_RESULT, "");

	/* verify events are not ready anymore (user has to clear them first) */
	events[0].state = K_POLL_STATE_NOT_READY;
	events[1].state = K_POLL_STATE_NOT_READY;
	events[2].state = K_POLL_STATE_NOT_READY;
	no_wait_signal.signaled = 0;

	zassert_equal(k_poll(events, ARRAY_SIZE(events), 0), -EAGAIN, "");
	zassert_equal(events[0].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(events[1].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(events[2].state, K_POLL_STATE_NOT_READY, "");

	zassert_not_equal(k_sem_take(&no_wait_sem, 0), 0, "");
	zassert_is_null(k_fifo_get(&no_wait_fifo, 0), "");
}

/* verify k_poll() that has to wait */

static K_SEM_DEFINE(wait_sem, 0, 1);
static K_FIFO_DEFINE(wait_fifo);
static struct k_poll_signal wait_signal = K_POLL_SIGNAL_INITIALIZER();

struct fifo_msg wait_msg = { NULL, FIFO_MSG_VALUE };

static struct k_thread poll_wait_helper_thread;
static K_THREAD_STACK_DEFINE(poll_wait_helper_stack, KB(1));

#define TAG_0 10
#define TAG_1 11
#define TAG_2 12

struct k_poll_event wait_events[] = {
	K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
					K_POLL_MODE_NOTIFY_ONLY,
					&wait_sem, TAG_0),
	K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
					K_POLL_MODE_NOTIFY_ONLY,
					&wait_fifo, TAG_1),
	K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SIGNAL,
					K_POLL_MODE_NOTIFY_ONLY,
					&wait_signal, TAG_2),
};

static void poll_wait_helper(void *use_fifo, void *p2, void *p3)
{
	(void)p2; (void)p3;

	k_sleep(250);

	k_sem_give(&wait_sem);

	if ((intptr_t)use_fifo) {
		k_fifo_put(&wait_fifo, &wait_msg);
	}

	k_poll_signal(&wait_signal, SIGNAL_RESULT);
}

void test_poll_wait(void)
{
	const int main_low_prio = 10;

	struct fifo_msg *msg_ptr;
	int rc;

	int old_prio = k_thread_priority_get(k_current_get());

	/*
	 * Wait for 3 non-ready events to become ready from a higher priority
	 * thread.
	 */
	k_thread_priority_set(k_current_get(), main_low_prio);

	k_thread_create(&poll_wait_helper_thread, poll_wait_helper_stack,
			K_THREAD_STACK_SIZEOF(poll_wait_helper_stack),
			poll_wait_helper, (void *)1, 0, 0,
			main_low_prio - 1, 0, 0);

	rc = k_poll(wait_events, ARRAY_SIZE(wait_events), K_SECONDS(1));

	k_thread_priority_set(k_current_get(), old_prio);

	zassert_equal(rc, 0, "");

	zassert_equal(wait_events[0].state, K_POLL_STATE_SEM_AVAILABLE, "");
	zassert_equal(k_sem_take(&wait_sem, 0), 0, "");
	zassert_equal(wait_events[0].tag, TAG_0, "");

	zassert_equal(wait_events[1].state,
		      K_POLL_STATE_FIFO_DATA_AVAILABLE, "");
	msg_ptr = k_fifo_get(&wait_fifo, 0);
	zassert_not_null(msg_ptr, "");
	zassert_equal(msg_ptr, &wait_msg, "");
	zassert_equal(msg_ptr->msg, FIFO_MSG_VALUE, "");
	zassert_equal(wait_events[1].tag, TAG_1, "");

	zassert_equal(wait_events[2].state, K_POLL_STATE_SIGNALED, "");
	zassert_equal(wait_signal.signaled, 1, "");
	zassert_equal(wait_signal.result, SIGNAL_RESULT, "");
	zassert_equal(wait_events[2].tag, TAG_2, "");

	/* verify events are not ready anymore */
	wait_events[0].state = K_POLL_STATE_NOT_READY;
	wait_events[1].state = K_POLL_STATE_NOT_READY;
	wait_events[2].state = K_POLL_STATE_NOT_READY;
	wait_signal.signaled = 0;

	zassert_equal(k_poll(wait_events, ARRAY_SIZE(wait_events),
			     K_SECONDS(1)), -EAGAIN, "");

	zassert_equal(wait_events[0].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(wait_events[1].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(wait_events[2].state, K_POLL_STATE_NOT_READY, "");

	/* tags should not have been touched */
	zassert_equal(wait_events[0].tag, TAG_0, "");
	zassert_equal(wait_events[1].tag, TAG_1, "");
	zassert_equal(wait_events[2].tag, TAG_2, "");

	/*
	 * Wait for 2 out of 3 non-ready events to become ready from a higher
	 * priority thread.
	 */
	k_thread_priority_set(k_current_get(), main_low_prio);

	k_thread_create(&poll_wait_helper_thread, poll_wait_helper_stack,
			K_THREAD_STACK_SIZEOF(poll_wait_helper_stack),
			poll_wait_helper,
			0, 0, 0, main_low_prio - 1, 0, 0);

	rc = k_poll(wait_events, ARRAY_SIZE(wait_events), K_SECONDS(1));

	k_thread_priority_set(k_current_get(), old_prio);

	zassert_equal(rc, 0, "");

	zassert_equal(wait_events[0].state, K_POLL_STATE_SEM_AVAILABLE, "");
	zassert_equal(k_sem_take(&wait_sem, 0), 0, "");
	zassert_equal(wait_events[0].tag, TAG_0, "");

	zassert_equal(wait_events[1].state, K_POLL_STATE_NOT_READY, "");
	msg_ptr = k_fifo_get(&wait_fifo, K_NO_WAIT);
	zassert_is_null(msg_ptr, "");
	zassert_equal(wait_events[1].tag, TAG_1, "");

	zassert_equal(wait_events[2].state, K_POLL_STATE_SIGNALED, "");
	zassert_equal(wait_signal.signaled, 1, "");
	zassert_equal(wait_signal.result, SIGNAL_RESULT, "");
	zassert_equal(wait_events[2].tag, TAG_2, "");

	/*
	 * Wait for each event to be ready from a lower priority thread, one at
	 * a time.
	 */

	wait_events[0].state = K_POLL_STATE_NOT_READY;
	wait_events[1].state = K_POLL_STATE_NOT_READY;
	wait_events[2].state = K_POLL_STATE_NOT_READY;
	wait_signal.signaled = 0;

	k_thread_create(&poll_wait_helper_thread, poll_wait_helper_stack,
			K_THREAD_STACK_SIZEOF(poll_wait_helper_stack),
			poll_wait_helper,
			(void *)1, 0, 0, old_prio + 1, 0, 0);

	/* semaphore */
	rc = k_poll(wait_events, ARRAY_SIZE(wait_events), K_SECONDS(1));

	zassert_equal(rc, 0, "");

	zassert_equal(wait_events[0].state, K_POLL_STATE_SEM_AVAILABLE, "");
	zassert_equal(k_sem_take(&wait_sem, 0), 0, "");
	zassert_equal(wait_events[0].tag, TAG_0, "");

	zassert_equal(wait_events[1].state, K_POLL_STATE_NOT_READY, "");
	msg_ptr = k_fifo_get(&wait_fifo, K_NO_WAIT);
	zassert_is_null(msg_ptr, "");
	zassert_equal(wait_events[1].tag, TAG_1, "");

	zassert_equal(wait_events[2].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(wait_events[2].tag, TAG_2, "");

	wait_events[0].state = K_POLL_STATE_NOT_READY;

	/* fifo */
	rc = k_poll(wait_events, ARRAY_SIZE(wait_events), K_SECONDS(1));

	zassert_equal(rc, 0, "");

	zassert_equal(wait_events[0].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(k_sem_take(&wait_sem, 0), -EBUSY, "");
	zassert_equal(wait_events[0].tag, TAG_0, "");

	zassert_equal(wait_events[1].state,
		      K_POLL_STATE_FIFO_DATA_AVAILABLE, "");
	msg_ptr = k_fifo_get(&wait_fifo, K_NO_WAIT);
	zassert_not_null(msg_ptr, "");
	zassert_equal(wait_events[1].tag, TAG_1, "");

	zassert_equal(wait_events[2].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(wait_events[2].tag, TAG_2, "");

	wait_events[1].state = K_POLL_STATE_NOT_READY;

	/* poll signal */
	rc = k_poll(wait_events, ARRAY_SIZE(wait_events), K_SECONDS(1));

	zassert_equal(rc, 0, "");

	zassert_equal(wait_events[0].state, K_POLL_STATE_NOT_READY, "");
	zassert_equal(k_sem_take(&wait_sem, 0), -EBUSY, "");
	zassert_equal(wait_events[0].tag, TAG_0, "");

	zassert_equal(wait_events[1].state, K_POLL_STATE_NOT_READY, "");
	msg_ptr = k_fifo_get(&wait_fifo, K_NO_WAIT);
	zassert_is_null(msg_ptr, "");
	zassert_equal(wait_events[1].tag, TAG_1, "");

	zassert_equal(wait_events[2].state, K_POLL_STATE_SIGNALED, "");
	zassert_equal(wait_signal.signaled, 1, "");
	zassert_equal(wait_signal.result, SIGNAL_RESULT, "");
	zassert_equal(wait_events[2].tag, TAG_2, "");

	wait_events[2].state = K_POLL_STATE_NOT_READY;
	wait_signal.signaled = 0;
}

/* verify -EADDRINUSE return value when object has already a poller */
static K_SEM_DEFINE(eaddrinuse_sem, 0, 1);
static K_SEM_DEFINE(eaddrinuse_reply, 0, 1);

static struct k_thread eaddrinuse_hogger_thread;
static K_THREAD_STACK_DEFINE(eaddrinuse_hogger_stack, KB(1));

static void eaddrinuse_hogger(void *p1, void *p2, void *p3)
{
	(void)p1; (void)p2; (void)p3;

	struct k_poll_event event;

	k_poll_event_init(&event, K_POLL_TYPE_SEM_AVAILABLE,
			  K_POLL_MODE_NOTIFY_ONLY, &eaddrinuse_sem);

	(void)k_poll(&event, 1, K_FOREVER);
	k_sem_take(&eaddrinuse_sem, K_FOREVER);
	k_sem_give(&eaddrinuse_reply);
}

static K_SEM_DEFINE(eaddrinuse_ready_sem, 1, 1);

void test_poll_eaddrinuse(void)
{
	int old_prio = k_thread_priority_get(k_current_get());
	const int main_low_prio = 10;
	int rc;

	struct k_poll_event events[] = {
		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
					 K_POLL_MODE_NOTIFY_ONLY,
					 &eaddrinuse_sem),
		K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
					 K_POLL_MODE_NOTIFY_ONLY,
					 &eaddrinuse_ready_sem),
	};

	k_thread_priority_set(k_current_get(), main_low_prio);

	k_thread_create(&eaddrinuse_hogger_thread, eaddrinuse_hogger_stack,
			K_THREAD_STACK_SIZEOF(eaddrinuse_hogger_stack),
			eaddrinuse_hogger, 0, 0, 0, main_low_prio - 1, 0, 0);

	rc = k_poll(events, ARRAY_SIZE(events), K_SECONDS(1));

	k_thread_priority_set(k_current_get(), old_prio);

	zassert_equal(rc, -EADDRINUSE, "");
	zassert_equal(events[0].state, K_POLL_STATE_EADDRINUSE, "");
	zassert_equal(events[1].state, K_POLL_STATE_SEM_AVAILABLE, "");

	/* free hogger, ensuring it awoken from k_poll() and got the sem */
	k_sem_give(&eaddrinuse_sem);
	rc = k_sem_take(&eaddrinuse_reply, K_SECONDS(1));

	zassert_equal(rc, 0, "");
}