blob: 10bb49676c0374afa6c6e140b0641046af3d2359 [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Verify zephyr alert send/recv across different contexts
*/
/**
* @brief Tests for the Alert kernel object
* @defgroup kernel.alerts
* @{
*/
#include <ztest.h>
#include <irq_offload.h>
#define TIMEOUT 100
#define STACK_SIZE 512
#define PENDING_MAX 2
#define SEM_INITIAL 0
#define SEM_LIMIT 1
K_SEM_DEFINE(sync_sema, SEM_INITIAL, SEM_LIMIT);
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);
static K_THREAD_STACK_DEFINE(sync_tstack, STACK_SIZE);
__kernel struct k_thread tdata;
__kernel struct k_thread sync_tdata;
__kernel struct k_alert thread_alerts[4];
static struct k_alert *palert;
static enum handle_type htype;
static volatile u32_t handler_executed;
static volatile u32_t handler_val;
/*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 sync_entry(void *p)
{
k_alert_send(palert);
}
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();
}
/**
* @brief Test alert_recv(timeout)
*
* This test checks alert_recv(timeout) against the following cases:
* 1. The current task times out while waiting for the event.
* 2. There is already an event waiting (signalled from a task).
* 3. The current task must wait on the event until it is signalled
* from either another task or an ISR.
*/
void test_thread_alert_timeout(void)
{
/**TESTPOINT: alert handler ignore*/
struct k_alert alert;
int ret, i;
/**TESTPOINT: init via k_alert_init*/
k_alert_init(&alert, K_ALERT_DEFAULT, PENDING_MAX);
palert = &alert;
ret = k_alert_recv(&alert, TIMEOUT);
zassert_equal(ret, -EAGAIN, NULL);
k_alert_send(&alert);
ret = k_alert_recv(&alert, TIMEOUT);
zassert_equal(ret, 0, NULL);
k_sem_give(&sync_sema);
for (i = 0; i < 2; i++) {
ret = k_alert_recv(&alert, TIMEOUT);
zassert_equal(ret, 0, NULL);
}
}
/**
* @brief Test alert_recv() against different cases
*
* This test checks alert_recv(K_FOREVER) against
* the following cases:
* 1. There is already an event waiting (signalled from a task and ISR).
* 2. The current task must wait on the event until it is signalled
* from either another task or an ISR.
*/
void test_thread_alert_wait(void)
{
/**TESTPOINT: alert handler ignore*/
struct k_alert alert;
int ret, i;
/**TESTPOINT: init via k_alert_init*/
k_alert_init(&alert, K_ALERT_DEFAULT, PENDING_MAX);
palert = &alert;
k_alert_send(&alert);
ret = k_alert_recv(&alert, K_FOREVER);
zassert_equal(ret, 0, NULL);
irq_offload(sync_entry, NULL);
ret = k_alert_recv(&alert, K_FOREVER);
zassert_equal(ret, 0, NULL);
k_sem_give(&sync_sema);
for (i = 0; i < 2; i++) {
ret = k_alert_recv(&alert, K_FOREVER);
zassert_equal(ret, 0, NULL);
}
}
int event_handler(struct k_alert *alt)
{
return handler_val;
}
/**
* @brief Test thread alert handler
*
* This test checks that the event handler is set up properly when
* alert_event_handler_set() is called. It shows that event handlers
* are tied to the specified event and that the return value from the
* handler affects whether the event wakes a task waiting upon that
* event.
*/
void test_thread_alert_handler(void)
{
/**TESTPOINT: alert handler ignore*/
struct k_alert alert;
int ret;
/**TESTPOINT: init via k_alert_init*/
k_alert_init(&alert, event_handler, PENDING_MAX);
palert = &alert;
k_sem_give(&sync_sema);
ret = k_alert_recv(&alert, TIMEOUT);
zassert_equal(ret, -EAGAIN, NULL);
k_sem_give(&sync_sema);
ret = k_alert_recv(&alert, TIMEOUT);
zassert_equal(ret, 0, NULL);
}
/**
* Signal various events to a waiting task
*/
void signal_task(void *p1, void *p2, void *p3)
{
k_sem_init(&sync_sema, 0, 1);
k_sem_take(&sync_sema, K_FOREVER);
k_alert_send(palert);
irq_offload(sync_entry, NULL);
k_sem_take(&sync_sema, K_FOREVER);
k_alert_send(palert);
irq_offload(sync_entry, NULL);
k_sem_take(&sync_sema, K_FOREVER);
handler_val = 0;
k_alert_send(palert);
k_sem_take(&sync_sema, K_FOREVER);
handler_val = 1;
k_alert_send(palert);
}
/*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);
/**TESTPOINT: thread-thread sync via alert*/
k_thread_create(&sync_tdata, sync_tstack, STACK_SIZE,
signal_task, NULL, NULL, NULL,
K_PRIO_PREEMPT(0), 0, 0);
ztest_test_suite(alert_api,
ztest_unit_test(test_thread_alert_timeout),
ztest_unit_test(test_thread_alert_wait),
ztest_unit_test(test_thread_alert_handler),
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(alert_api);
}
/**
* @}
*/