Linux Audio

Check our new training course

Loading...
/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @addtogroup t_alert_api
 * @{
 * @defgroup t_alert_context test_alert_send_recv_context
 * @brief TestPurpose: verify zephyr alert send/recv across different contexts
 */

#include <ztest.h>
#include <irq_offload.h>

#define TIMEOUT 100
#define STACK_SIZE 512
#define PENDING_MAX 2
static int alert_handler0(struct k_alert *);
static int alert_handler1(struct k_alert *);

/**TESTPOINT: init via K_ALERT_DEFINE*/
K_ALERT_DEFINE(kalert_pending, alert_handler1, PENDING_MAX);
K_ALERT_DEFINE(kalert_consumed, alert_handler0, PENDING_MAX);

enum handle_type {
	HANDLER_IGNORE,
	HANDLER_DEFAULT,
	HANDLER_0,
	HANDLER_1
};

static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
__kernel struct k_thread tdata;
__kernel struct k_alert thread_alerts[4];
static struct k_alert *palert;
static enum handle_type htype;
static volatile int handler_executed;

/*handlers*/
static int alert_handler0(struct k_alert *alt)
{
	handler_executed++;
	return 0;
}

static int alert_handler1(struct k_alert *alt)
{
	handler_executed++;
	return 1;
}

static void alert_send(void)
{
	/**TESTPOINT: alert send*/
	for (int i = 0; i < PENDING_MAX; i++) {
		k_alert_send(palert);
	}
}

static void alert_recv(void)
{
	int ret;

	switch (htype) {
	case HANDLER_0:
		zassert_equal(handler_executed, PENDING_MAX, NULL);
		/* Fall through */
	case HANDLER_IGNORE:
		ret = k_alert_recv(palert, TIMEOUT);
		zassert_equal(ret, -EAGAIN, NULL);
		break;
	case HANDLER_1:
		zassert_equal(handler_executed, PENDING_MAX, NULL);
		/* Fall through */
	case HANDLER_DEFAULT:
		for (int i = 0; i < PENDING_MAX; i++) {
			/**TESTPOINT: alert recv*/
			ret = k_alert_recv(palert, K_NO_WAIT);
			zassert_false(ret, NULL);
		}
		/**TESTPOINT: alert recv -EAGAIN*/
		ret = k_alert_recv(palert, TIMEOUT);
		zassert_equal(ret, -EAGAIN, NULL);
		/**TESTPOINT: alert recv -EBUSY*/
		ret = k_alert_recv(palert, K_NO_WAIT);
		zassert_equal(ret, -EBUSY, NULL);
	}
}

static void thread_entry(void *p1, void *p2, void *p3)
{
	alert_recv();
}

static void thread_alert(void)
{
	handler_executed = 0;
	/**TESTPOINT: thread-thread sync via alert*/
	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
				      thread_entry, NULL, NULL, NULL,
				      K_PRIO_PREEMPT(0),
				      K_USER | K_INHERIT_PERMS,
				      0);
	alert_send();
	k_sleep(TIMEOUT);
	k_thread_abort(tid);
}

static void tisr_entry(void *p)
{
	alert_send();
}

static void isr_alert(void)
{
	handler_executed = 0;
	/**TESTPOINT: thread-isr sync via alert*/
	irq_offload(tisr_entry, NULL);
	k_sleep(TIMEOUT);
	alert_recv();
}

/*test cases*/
void test_thread_alert_default(void)
{
	palert = &thread_alerts[HANDLER_DEFAULT];
	htype = HANDLER_DEFAULT;
	thread_alert();
}

void test_thread_alert_ignore(void)
{
	palert = &thread_alerts[HANDLER_IGNORE];
	htype = HANDLER_IGNORE;
	thread_alert();
}

void test_thread_alert_consumed(void)
{
	/**TESTPOINT: alert handler return 0*/
	palert = &thread_alerts[HANDLER_0];
	htype = HANDLER_0;
	thread_alert();
}

void test_thread_alert_pending(void)
{
	/**TESTPOINT: alert handler return 1*/
	palert = &thread_alerts[HANDLER_1];
	htype = HANDLER_1;
	thread_alert();
}

void test_isr_alert_default(void)
{
	struct k_alert alert;

	/**TESTPOINT: init via k_alert_init*/
	k_alert_init(&alert, K_ALERT_DEFAULT, PENDING_MAX);

	/**TESTPOINT: alert handler default*/
	palert = &alert;
	htype = HANDLER_DEFAULT;
	isr_alert();
}

void test_isr_alert_ignore(void)
{
	/**TESTPOINT: alert handler ignore*/
	struct k_alert alert;

	/**TESTPOINT: init via k_alert_init*/
	k_alert_init(&alert, K_ALERT_IGNORE, PENDING_MAX);
	palert = &alert;
	htype = HANDLER_IGNORE;
	isr_alert();
}

void test_isr_alert_consumed(void)
{
	struct k_alert alert;

	/**TESTPOINT: init via k_alert_init*/
	k_alert_init(&alert, alert_handler0, PENDING_MAX);

	/**TESTPOINT: alert handler return 0*/
	palert = &alert;
	htype = HANDLER_0;
	isr_alert();
}

void test_isr_alert_pending(void)
{
	struct k_alert alert;

	/**TESTPOINT: init via k_alert_init*/
	k_alert_init(&alert, alert_handler1, PENDING_MAX);

	/**TESTPOINT: alert handler return 0*/
	palert = &alert;
	htype = HANDLER_1;
	isr_alert();
}

void test_thread_kinit_alert(void)
{
	palert = &kalert_consumed;
	htype = HANDLER_0;
	thread_alert();
	palert = &kalert_pending;
	htype = HANDLER_1;
	thread_alert();
}

void test_isr_kinit_alert(void)
{
	palert = &kalert_consumed;
	htype = HANDLER_0;
	isr_alert();
	palert = &kalert_pending;
	htype = HANDLER_1;
	isr_alert();
}

/*test case main entry*/
void test_main(void)
{
	k_thread_access_grant(k_current_get(), &kalert_pending,
			      &kalert_consumed, &tdata, &tstack,
			      &thread_alerts[HANDLER_DEFAULT],
			      &thread_alerts[HANDLER_IGNORE],
			      &thread_alerts[HANDLER_0],
			      &thread_alerts[HANDLER_1], NULL);

	k_alert_init(&thread_alerts[HANDLER_DEFAULT], K_ALERT_DEFAULT,
		     PENDING_MAX);
	k_alert_init(&thread_alerts[HANDLER_IGNORE], K_ALERT_IGNORE,
		     PENDING_MAX);
	k_alert_init(&thread_alerts[HANDLER_0], alert_handler0, PENDING_MAX);
	k_alert_init(&thread_alerts[HANDLER_1], alert_handler1, PENDING_MAX);

	ztest_test_suite(test_alert_api,
			 ztest_user_unit_test(test_thread_alert_default),
			 ztest_user_unit_test(test_thread_alert_ignore),
			 ztest_user_unit_test(test_thread_alert_consumed),
			 ztest_user_unit_test(test_thread_alert_pending),
			 ztest_unit_test(test_isr_alert_default),
			 ztest_unit_test(test_isr_alert_ignore),
			 ztest_unit_test(test_isr_alert_consumed),
			 ztest_unit_test(test_isr_alert_pending),
			 ztest_user_unit_test(test_thread_kinit_alert),
			 ztest_unit_test(test_isr_kinit_alert));
	ztest_run_test_suite(test_alert_api);
}