kernel: remove k_alert API

This API was used in only one place in non-test code.  See whether we
can remove it.

Closes #12232

Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
Peter A. Bigot 2018-12-27 06:14:45 -06:00 committed by Anas Nashif
commit bfad9721d2
20 changed files with 2 additions and 1266 deletions

View file

@ -109,16 +109,6 @@ with basic priority inheritance.
.. doxygengroup:: mutex_apis
:project: Zephyr
Alerts
******
Alerts enable an application to perform asynchronous signaling,
somewhat akin to Unix-style signals.
(See :ref:`alerts_v2`.)
.. doxygengroup:: alert_apis
:project: Zephyr
FIFOs
*****

View file

@ -166,12 +166,8 @@ processing to a thread.
* An ISR can signal a helper thread to do interrupt-related processing
using a kernel object, such as a fifo, lifo, or semaphore.
* An ISR can signal an alert which causes the system workqueue thread
to execute an associated alert handler function.
(See :ref:`alerts_v2`.)
* An ISR can instruct the system workqueue thread to execute a work item.
(See TBD.)
(See :ref:`workqueues_v2`.)
When an ISR offloads work to a thread, there is typically a single context
switch to that thread when the ISR completes, allowing interrupt-related

View file

@ -1,240 +0,0 @@
.. _alerts_v2:
Alerts
######
An :dfn:`alert` is a kernel object that allows an application to perform
asynchronous signaling when a condition of interest occurs.
.. contents::
:local:
:depth: 2
Concepts
********
Any number of alerts can be defined. Each alert is referenced by
its memory address.
An alert has the following key properties:
* An **alert handler**, which specifies the action to be taken
when the alert is signaled. The action may instruct the system workqueue
to execute a function to process the alert, mark the alert as pending
so it can be processed later by a thread, or ignore the alert.
* An **pending count**, which records the number of pending alerts
that have yet to be received.
* An **count limit**, which specifies the maximum number of pending alerts
that will be recorded.
An alert must be initialized before it can be used. This establishes
its alert handler and sets the pending count to zero.
Alert Lifecycle
===============
An ISR or a thread signals an alert by **sending** the alert
when a condition of interest occurs that cannot be handled by the detector.
Each time an alert is sent, the kernel examines its alert handler
to determine what action to take.
* :c:macro:`K_ALERT_IGNORE` causes the alert to be ignored.
* :c:macro:`K_ALERT_DEFAULT` causes the pending count to be incremented,
unless this would exceed the count limit.
* Any other value is assumed to be the address of an alert handler function,
and is invoked by the system workqueue thread. If the function returns
zero, the signal is deemed to have been consumed; otherwise the pending
count is incremented, unless this would exceed the count limit.
The kernel ensures that the alert handler function is executed once
for each time an alert is sent, even if the alert is sent multiple times
in rapid succession.
A thread accepts a pending alert by **receiving** the alert.
This decrements the pending count. If the pending count is currently zero,
the thread may choose to wait for the alert to become pending.
Any number of threads may wait for a pending alert simultaneously;
when the alert is pended it is accepted by the highest priority thread
that has waited longest.
.. note::
A thread must processes pending alerts one at a time. The thread
cannot receive multiple pending alerts in a single operation.
Comparison to Unix-style Signals
================================
Zephyr alerts are somewhat akin to Unix-style signals, but have a number of
significant differences. The most notable of these are:
* A Zephyr alert cannot be blocked; it is always delivered to its alert
handler immediately.
* A Zephyr alert pends *after* it has been delivered to its alert handler,
and only if an alert handler function does not consume the alert.
* Zephyr has no predefined alerts or actions. All alerts are application
defined, and all have a default action that pends the alert.
Implementation
**************
Defining an Alert
=================
An alert is defined using a variable of type :c:type:`struct k_alert`.
It must then be initialized by calling :cpp:func:`k_alert_init()`.
The following code defines and initializes an alert. The alert allows
up to 10 unreceived alert signals to pend before it begins to ignore
new pending alerts.
.. code-block:: c
extern int my_alert_handler(struct k_alert *alert);
struct k_alert my_alert;
k_alert_init(&my_alert, my_alert_handler, 10);
Alternatively, an alert can be defined and initialized at compile time
by calling :c:macro:`K_ALERT_DEFINE`.
The following code has the same effect as the code segment above.
.. code-block:: c
extern int my_alert_handler(struct k_alert *alert);
K_ALERT_DEFINE(my_alert, my_alert_handler, 10);
Signaling an Alert
==================
An alert is signaled by calling :cpp:func:`k_alert_send()`.
The following code illustrates how an ISR can signal an alert
to indicate that a key press has occurred.
.. code-block:: c
extern int my_alert_handler(struct k_alert *alert);
K_ALERT_DEFINE(my_alert, my_alert_handler, 10);
void keypress_interrupt_handler(void *arg)
{
...
k_alert_send(&my_alert);
...
}
Handling an Alert
=================
An alert handler function is used when a signaled alert should not be ignored
or immediately pended. It has the following form:
.. code-block:: c
int <function_name>(struct k_alert *alert)
{
/* catch the alert signal; return zero if the signal is consumed, */
/* or non-zero to let the alert pend */
...
}
The following code illustrates an alert handler function that processes
key presses detected by an ISR (as shown in the previous section).
.. code-block:: c
int my_alert_handler(struct k_alert *alert_id_is_unused)
{
/* determine what key was pressed */
char c = get_keypress();
/* do complex processing of the keystroke */
...
/* signaled alert has been consumed */
return 0;
}
Accepting an Alert
==================
A pending alert is accepted by a thread by calling :cpp:func:`k_alert_recv()`.
The following code is an alternative to the code in the previous section.
It uses a dedicated thread to do very complex processing
of key presses that would otherwise monopolize the system workqueue.
The alert handler function is now used only to filter out unwanted key press
alerts, allowing the dedicated thread to wake up and process key press alerts
only when a numeric key is pressed.
.. code-block:: c
int my_alert_handler(struct k_alert *alert_id_is_unused)
{
/* determine what key was pressed */
char c = get_keypress();
/* signal thread only if key pressed was a digit */
if ((c >= '0') && (c <= '9')) {
/* save key press information */
...
/* signaled alert should be pended */
return 1;
} else {
/* signaled alert has been consumed */
return 0;
}
}
void keypress_thread(void *unused1, void *unused2, void *unused3)
{
/* consume numeric key presses */
while (1) {
/* wait for a key press alert to pend */
k_alert_recv(&my_alert, K_FOREVER);
/* process saved key press, which must be a digit */
...
}
}
Suggested Uses
**************
Use an alert to minimize ISR processing by deferring interrupt-related
work to a thread to reduce the amount of time interrupts are locked.
Use an alert to allow the kernel's system workqueue to handle an alert,
rather than defining an application thread to handle it.
Use an alert to allow the kernel's system workqueue to preprocess an alert,
prior to letting an application thread handle it.
Configuration Options
*********************
Related configuration options:
* None.
APIs
****
The following alert APIs are provided by :file:`kernel.h`:
* :c:macro:`K_ALERT_DEFINE`
* :cpp:func:`k_alert_init()`
* :cpp:func:`k_alert_send()`
* :cpp:func:`k_alert_recv()`

View file

@ -11,4 +11,3 @@ of different threads, or the operation of an ISR and a thread.
semaphores.rst
mutexes.rst
alerts.rst

View file

@ -20,7 +20,6 @@ extern struct k_mem_slab *_trace_list_k_mem_slab;
extern struct k_mem_pool *_trace_list_k_mem_pool;
extern struct k_sem *_trace_list_k_sem;
extern struct k_mutex *_trace_list_k_mutex;
extern struct k_alert *_trace_list_k_alert;
extern struct k_fifo *_trace_list_k_fifo;
extern struct k_lifo *_trace_list_k_lifo;
extern struct k_stack *_trace_list_k_stack;

View file

@ -115,7 +115,6 @@ typedef struct {
struct k_thread;
struct k_mutex;
struct k_sem;
struct k_alert;
struct k_msgq;
struct k_mbox;
struct k_pipe;
@ -3071,150 +3070,6 @@ static inline unsigned int _impl_k_sem_count_get(struct k_sem *sem)
/** @} */
/**
* @defgroup alert_apis Alert APIs
* @ingroup kernel_apis
* @{
*/
/**
* @typedef k_alert_handler_t
* @brief Alert handler function type.
*
* An alert's alert handler function is invoked by the system workqueue
* when the alert is signaled. The alert handler function is optional,
* and is only invoked if the alert has been initialized with one.
*
* @param alert Address of the alert.
*
* @return 0 if alert has been consumed; non-zero if alert should pend.
*/
typedef int (*k_alert_handler_t)(struct k_alert *alert);
/** @} */
/**
* @cond INTERNAL_HIDDEN
*/
#define K_ALERT_DEFAULT NULL
#define K_ALERT_IGNORE ((k_alert_handler_t)0xFFFFFFFF)
struct k_alert {
k_alert_handler_t handler;
atomic_t send_count;
struct k_work work_item;
struct k_sem sem;
_OBJECT_TRACING_NEXT_PTR(k_alert)
};
/**
* @internal
*/
extern void _alert_deliver(struct k_work *work);
#define _K_ALERT_INITIALIZER(obj, alert_handler, max_num_pending_alerts) \
{ \
.handler = (k_alert_handler_t)alert_handler, \
.send_count = ATOMIC_INIT(0), \
.work_item = _K_WORK_INITIALIZER(_alert_deliver), \
.sem = _K_SEM_INITIALIZER(obj.sem, 0, max_num_pending_alerts), \
_OBJECT_TRACING_INIT \
}
#define K_ALERT_INITIALIZER DEPRECATED_MACRO _K_ALERT_INITIALIZER
/**
* INTERNAL_HIDDEN @endcond
*/
/**
* @addtogroup alert_apis
* @{
*/
/**
* @def K_ALERT_DEFINE(name, alert_handler, max_num_pending_alerts)
*
* @brief Statically define and initialize an alert.
*
* The alert can be accessed outside the module where it is defined using:
*
* @code extern struct k_alert <name>; @endcode
*
* @param name Name of the alert.
* @param alert_handler Action to take when alert is sent. Specify either
* the address of a function to be invoked by the system workqueue
* thread, K_ALERT_IGNORE (which causes the alert to be ignored), or
* K_ALERT_DEFAULT (which causes the alert to pend).
* @param max_num_pending_alerts Maximum number of pending alerts.
*
* @req K-ALERT-001
*/
#define K_ALERT_DEFINE(name, alert_handler, max_num_pending_alerts) \
struct k_alert name \
__in_section(_k_alert, static, name) = \
_K_ALERT_INITIALIZER(name, alert_handler, \
max_num_pending_alerts)
/**
* @brief Initialize an alert.
*
* This routine initializes an alert object, prior to its first use.
*
* @param alert Address of the alert.
* @param handler Action to take when alert is sent. Specify either the address
* of a function to be invoked by the system workqueue thread,
* K_ALERT_IGNORE (which causes the alert to be ignored), or
* K_ALERT_DEFAULT (which causes the alert to pend).
* @param max_num_pending_alerts Maximum number of pending alerts.
*
* @return N/A
* @req K-ALERT-002
*/
extern void k_alert_init(struct k_alert *alert, k_alert_handler_t handler,
unsigned int max_num_pending_alerts);
/**
* @brief Receive an alert.
*
* This routine receives a pending alert for @a alert.
*
* @note Can be called by ISRs, but @a timeout must be set to K_NO_WAIT.
*
* @param alert Address of the alert.
* @param timeout Waiting period to receive the alert (in milliseconds),
* or one of the special values K_NO_WAIT and K_FOREVER.
*
* @retval 0 Alert received.
* @retval -EBUSY Returned without waiting.
* @retval -EAGAIN Waiting period timed out.
* @req K-ALERT-002
*/
__syscall int k_alert_recv(struct k_alert *alert, s32_t timeout);
/**
* @brief Signal an alert.
*
* This routine signals @a alert. The action specified for @a alert will
* be taken, which may trigger the execution of an alert handler function
* and/or cause the alert to pend (assuming the alert has not reached its
* maximum number of pending alerts).
*
* @note Can be called by ISRs.
*
* @param alert Address of the alert.
*
* @return N/A
* @req K-ALERT-002
*/
__syscall void k_alert_send(struct k_alert *alert);
/**
* @}
*/
/**
* @defgroup msgq_apis Message Queue APIs
* @ingroup kernel_apis

View file

@ -83,13 +83,6 @@
_k_mutex_list_end = .;
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
SECTION_DATA_PROLOGUE(_k_alert_area, (OPTIONAL), SUBALIGN(4))
{
_k_alert_list_start = .;
KEEP(*(SORT_BY_NAME("._k_alert.static.*")))
_k_alert_list_end = .;
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
SECTION_DATA_PROLOGUE(_k_queue_area, (OPTIONAL), SUBALIGN(4))
{
_k_queue_list_start = .;

View file

@ -1,7 +1,6 @@
# kernel is a normal CMake library and not a zephyr_library because it
# should not be --whole-archive'd
add_library(kernel
alert.c
device.c
errno.c
idle.c

View file

@ -1,110 +0,0 @@
/*
* Copyright (c) 2016 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief kernel alerts.
*/
#include <kernel.h>
#include <kernel_structs.h>
#include <debug/object_tracing_common.h>
#include <atomic.h>
#include <init.h>
#include <toolchain.h>
#include <linker/sections.h>
#include <syscall_handler.h>
#include <stdbool.h>
extern struct k_alert _k_alert_list_start[];
extern struct k_alert _k_alert_list_end[];
#ifdef CONFIG_OBJECT_TRACING
struct k_alert *_trace_list_k_alert;
/*
* Complete initialization of statically defined alerts.
*/
static int init_alert_module(struct device *dev)
{
ARG_UNUSED(dev);
struct k_alert *alert;
for (alert = _k_alert_list_start; alert < _k_alert_list_end; alert++) {
SYS_TRACING_OBJ_INIT(k_alert, alert);
}
return 0;
}
SYS_INIT(init_alert_module, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
#endif /* CONFIG_OBJECT_TRACING */
void _alert_deliver(struct k_work *work)
{
struct k_alert *alert = CONTAINER_OF(work, struct k_alert, work_item);
while (true) {
if ((alert->handler)(alert) == 0) {
/* do nothing -- handler has processed the alert */
} else {
/* pend the alert */
k_sem_give(&alert->sem);
}
if (atomic_dec(&alert->send_count) == 1) {
/* have finished delivering alerts */
break;
}
}
}
void k_alert_init(struct k_alert *alert, k_alert_handler_t handler,
unsigned int max_num_pending_alerts)
{
alert->handler = handler;
alert->send_count = ATOMIC_INIT(0);
alert->work_item = (struct k_work)_K_WORK_INITIALIZER(_alert_deliver);
k_sem_init(&alert->sem, 0, max_num_pending_alerts);
SYS_TRACING_OBJ_INIT(k_alert, alert);
_k_object_init(alert);
}
void _impl_k_alert_send(struct k_alert *alert)
{
if (alert->handler == K_ALERT_IGNORE) {
/* ignore the alert */
} else if (alert->handler == K_ALERT_DEFAULT) {
/* pend the alert */
k_sem_give(&alert->sem);
} else {
/* deliver the alert */
if (atomic_inc(&alert->send_count) == 0) {
/* add alert's work item to system work queue */
k_work_submit_to_queue(&k_sys_work_q,
&alert->work_item);
}
}
}
#ifdef CONFIG_USERSPACE
Z_SYSCALL_HANDLER1_SIMPLE_VOID(k_alert_send, K_OBJ_ALERT, struct k_alert *);
#endif
int _impl_k_alert_recv(struct k_alert *alert, s32_t timeout)
{
return k_sem_take(&alert->sem, timeout);
}
#ifdef CONFIG_USERSPACE
Z_SYSCALL_HANDLER(k_alert_recv, alert, timeout)
{
Z_OOPS(Z_SYSCALL_OBJ(alert, K_OBJ_ALERT));
return _impl_k_alert_recv((struct k_alert *)alert, timeout);
}
#endif

View file

@ -17,7 +17,6 @@ from elf_helper import ElfHelper, kobject_to_enum
# available in all configurations.
kobjects = {
"k_alert": None,
"k_mem_slab": None,
"k_msgq": None,
"k_mutex": None,

View file

@ -671,7 +671,7 @@ class SizeCalculator:
"_k_memory_pool", "exceptions", "initshell",
"_static_thread_area", "_k_timer_area",
"_k_mem_slab_area", "_k_mem_pool_area", "sw_isr_table",
"_k_sem_area", "_k_mutex_area", "_k_alert_area",
"_k_sem_area", "_k_mutex_area",
"_k_fifo_area", "_k_lifo_area", "_k_stack_area",
"_k_msgq_area", "_k_mbox_area", "_k_pipe_area",
"net_if", "net_if_dev", "net_stack", "net_l2_data",

View file

@ -1,168 +0,0 @@
/* event_b.c */
/*
* Copyright (c) 1997-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "master.h"
#ifdef EVENT_BENCH
/* #define EVENT_CHECK */
#ifdef EVENT_CHECK
static const char event_signal_err[] = "----------- Error signalling event.\n";
static const char event_test_err[] = "----------- Error testing event.\n";
static const char event_handler_err[] = "----------- Error in event handler\n";
#endif
/* global Event value */
volatile int nevent_value;
/*
* Function prototypes.
*/
int example_handler (struct k_alert *alert);
/*
* Function declarations.
*/
/**
*
* @brief Event signal speed test
*
* @return N/A
*/
void event_test(void)
{
int nreturn = 0;
int ncounter;
u32_t et; /* elapsed time */
PRINT_STRING(dashline, output_file);
et = BENCH_START();
for (ncounter = 0; ncounter < NR_OF_EVENT_RUNS; ncounter++) {
k_alert_send(&TEST_EVENT);
#ifdef EVENT_CHECK
if (nreturn != 0) {
PRINT_STRING(event_signal_err, output_file);
return; /* error */
}
#endif /* EVENT_CHECK */
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
PRINT_F(output_file, FORMAT, "Signal enabled event",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_EVENT_RUNS));
et = BENCH_START();
for (ncounter = 0; ncounter < NR_OF_EVENT_RUNS; ncounter++) {
k_alert_send(&TEST_EVENT);
#ifdef EVENT_CHECK
if (nreturn != 0) {
PRINT_STRING(event_signal_err, output_file);
k_sleep(1);
return; /* error */
}
#endif /* EVENT_CHECK */
k_alert_recv(&TEST_EVENT, K_NO_WAIT);
#ifdef EVENT_CHECK
if (nreturn != 0) {
PRINT_STRING(event_test_err, output_file);
k_sleep(1);
return; /* error */
}
#endif /* EVENT_CHECK */
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
PRINT_F(output_file, FORMAT, "Signal event & Test event",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_EVENT_RUNS));
et = BENCH_START();
for (ncounter = 0; ncounter < NR_OF_EVENT_RUNS; ncounter++) {
k_alert_send(&TEST_EVENT);
#ifdef EVENT_CHECK
if (nreturn != 0) {
PRINT_STRING(event_signal_err, output_file);
return; /* error */
}
#endif /* EVENT_CHECK */
k_alert_recv(&TEST_EVENT, K_FOREVER);
#ifdef EVENT_CHECK
if (nreturn != 0) {
PRINT_STRING(event_test_err, output_file);
return; /* error */
}
#endif /* EVENT_CHECK */
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
PRINT_F(output_file, FORMAT, "Signal event & TestW event",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_EVENT_RUNS));
PRINT_STRING("| Signal event with installed handler"
" |\n", output_file);
TEST_EVENT.handler = example_handler;
if (nreturn != 0) {
PRINT_F(output_file,
"-------- Error installing event handler.\n");
k_sleep(1);
return; /* error */
}
for (ncounter = 0; ncounter < NR_OF_EVENT_RUNS; ncounter++) {
k_alert_send(&TEST_EVENT);
#ifdef EVENT_CHECK
if (nreturn != 0) {
PRINT_STRING(event_signal_err, output_file);
k_sleep(1);
return; /* error */
}
if (nevent_value != TEST_EVENT.send_count + 1) {
PRINT_STRING(event_handler_err, output_file);
k_sleep(1);
return; /* error */
}
#endif /* EVENT_CHECK */
nevent_value = 0;
}
TEST_EVENT.handler = NULL;
if (nreturn != 0) {
PRINT_F(output_file, "Error removing event handler.\n");
k_sleep(1);
return; /* error */
}
PRINT_STRING("| Handler responds OK"
" |\n",
output_file);
return; /* success */
}
/**
*
* @brief Event handler for the tests
*
* The event handler for the test. Sets up nEventValue global variable.
* This variable is used in the main test.
*
* @return 1
*/
int example_handler (struct k_alert *alert)
{
ARG_UNUSED(alert);
nevent_value = alert->send_count + 1;
return 1;
}
#endif /* EVENT_BENCH */

View file

@ -63,8 +63,6 @@ K_PIPE_DEFINE(PIPE_BIGBUFF, 4096, 4);
K_MEM_POOL_DEFINE(DEMOPOOL, 16, 16, 1, 4);
K_ALERT_DEFINE(TEST_EVENT, NULL, 1);
/**
*
@ -138,7 +136,6 @@ void main(void)
mutex_test();
memorymap_test();
mempool_test();
event_test();
mailbox_test();
pipe_test();
PRINT_STRING("| END OF TESTS "

View file

@ -122,12 +122,6 @@ extern void pipe_test(void);
#define pipe_test dummy_test
#endif
#ifdef EVENT_BENCH
extern void event_test(void);
#else
#define event_test dummy_test
#endif
/* kernel objects needed for benchmarking */
extern struct k_mutex DEMO_MUTEX;
@ -153,8 +147,6 @@ extern struct k_pipe PIPE_BIGBUFF;
extern struct k_mem_slab MAP1;
extern struct k_alert TEST_EVENT;
extern struct k_mem_pool DEMOPOOL;

View file

@ -61,11 +61,6 @@ static pfunc func_array[] = {
(pfunc)k_mem_slab_num_free_get,
#ifdef TEST_max
/* alerts */
(pfunc)k_alert_init,
(pfunc)k_alert_send,
(pfunc)k_alert_recv,
/* message queues */
(pfunc)k_msgq_init,
(pfunc)k_msgq_put,

View file

@ -1,6 +0,0 @@
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(alert_api)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -1,2 +0,0 @@
CONFIG_ZTEST=y
CONFIG_IRQ_OFFLOAD=y

View file

@ -1,524 +0,0 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
#include <irq_offload.h>
#define TIMEOUT 100
#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
#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 = 0U;
/**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 = 0U;
/**TESTPOINT: thread-isr sync via alert*/
irq_offload(tisr_entry, NULL);
k_sleep(TIMEOUT);
alert_recv();
}
int event_handler(struct k_alert *alt)
{
return handler_val;
}
/**
* @brief Tests for the Alert kernel object
* @defgroup kernel_alert_tests Alerts
* @ingroup all_tests
* @{
*/
/**
* @brief Test thread alert default
*
* Checks k_alert_init(), k_alert_send(), k_alert_recv() Kernel APIs.
*
* Initializes an alert and creates a thread that signals an alert with
* k_alert_send() and then calls k_alert_recv() with K_NO_WAIT to receive the
* alerts. Checks if k_alert_recv() returns appropriate error values when
* alerts are not received.
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
void test_thread_alert_default(void)
{
palert = &thread_alerts[HANDLER_DEFAULT];
htype = HANDLER_DEFAULT;
thread_alert();
}
/**
* @brief Test thread alert ignore
*
* Checks k_alert_init(), k_alert_send(), k_alert_recv() Kernel APIs - creates
* a thread that signals an alert using k_alert_send() and then calls
* k_alert_recv() with TIMEOUT of 100ms which is the waiting period for
* receiving the alert.
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
void test_thread_alert_ignore(void)
{
palert = &thread_alerts[HANDLER_IGNORE];
htype = HANDLER_IGNORE;
thread_alert();
}
/**
* @brief Test thread alert consumed
*
* Checks k_alert_init(), k_alert_send(), k_alert_recv() Kernel APIs.
*
* Creates a thread that signals an alert using k_alert_send(). Now
* k_alert_send() for this case is initialized with an address of the handler
* function, which increases handler_executed count each time it is called.
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
void test_thread_alert_consumed(void)
{
/**TESTPOINT: alert handler return 0*/
palert = &thread_alerts[HANDLER_0];
htype = HANDLER_0;
thread_alert();
}
/**
* @brief Test thread alert pending
*
* Checks k_alert_init(), k_alert_send(), k_alert_recv() Kernel APIs
*
* Creates a thread that signals an alert using k_alert_send().
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
void test_thread_alert_pending(void)
{
/**TESTPOINT: alert handler return 1*/
palert = &thread_alerts[HANDLER_1];
htype = HANDLER_1;
thread_alert();
}
/**
* @brief Test default isr alert
*
* Similar to test_thread_alert_default(), but verifies kernel objects and
* APIs work correctly in interrupt context with the help of irq_offload()
* function.
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
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();
}
/**
* @brief Test isr alert ignore
*
* Similar to test_thread_alert_ignore(), but verifies kernel objects and
* APIs work correctly in interrupt context with the help of irq_offload()
* function.
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
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();
}
/**
* @brief Test isr alert consumed
*
* Similar to test_thread_alert_consumed, but verifies kernel objects
* and APIs work correctly in interrupt context with the help of irq_offload()
* function.
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
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();
}
/**
* @brief Test isr alert pending
*
* Similar to test_thread_alert_pending(), but verifies kernel objects and
* APIs work correctly in interrupt context with the help of irq_offload()
* function.
*
* @see k_alert_init(), k_alert_send(), k_alert_recv()
*/
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();
}
/**
* @brief Test thread kinit alert
*
* Tests consumed and pending thread alert cases (reference line numbers 4 and
* 5), but handles case where alert has been defined via #K_ALERT_DEFINE(x) and not
* k_alert_init()
*
* @see #K_ALERT_DEFINE(x)
*/
void test_thread_kinit_alert(void)
{
palert = &kalert_consumed;
htype = HANDLER_0;
thread_alert();
palert = &kalert_pending;
htype = HANDLER_1;
thread_alert();
}
/**
* @brief Test isr kinit alert
*
* Checks consumed and pending isr alert cases but alert has been defined via
* #K_ALERT_DEFINE(x) and not k_alert_init()
*
* @see #K_ALERT_DEFINE(x)
*/
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 k_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 (signaled from a task).
* 3. The current task must wait on the event until it is signaled
* from either another task or an ISR.
*
* @see k_alert_recv()
*/
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 k_alert_recv() against different cases
*
* This test checks k_alert_recv(K_FOREVER) against
* the following cases:
* 1. There is already an event waiting (signaled from a task and ISR).
* 2. The current task must wait on the event until it is signaled
* from either another task or an ISR.
*
* @see k_alert_recv()
*/
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);
}
}
/**
* @brief Test thread alert handler
*
* This test checks that the event handler is set up properly when
* k_alert_init() is called with an event handler. 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.
*
* @see k_alert_init()
*/
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 = 0U;
k_alert_send(palert);
k_sem_take(&sync_sema, K_FOREVER);
handler_val = 1U;
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]);
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);
}

View file

@ -1,3 +0,0 @@
tests:
kernel.alert:
tags: kernel userspace

View file

@ -13,7 +13,6 @@ enum obj_name {
MEM_SLAB,
SEM,
MUTEX,
ALERT,
STACK,
MSGQ,
MBOX,
@ -30,16 +29,10 @@ static inline void stop_dummy_fn(struct k_timer *timer)
ARG_UNUSED(timer);
}
static inline void alert_handler_dummy(struct k_alert *alert)
{
ARG_UNUSED(alert);
}
K_TIMER_DEFINE(ktimer, expiry_dummy_fn, stop_dummy_fn);
K_MEM_SLAB_DEFINE(kmslab, 4, 2, 4);
K_SEM_DEFINE(ksema, 0, 1);
K_MUTEX_DEFINE(kmutex);
K_ALERT_DEFINE(kalert, alert_handler_dummy, 1);
K_STACK_DEFINE(kstack, 512);
K_MSGQ_DEFINE(kmsgq, 4, 2, 4);
K_MBOX_DEFINE(kmbox);
@ -50,7 +43,6 @@ static struct k_timer timer;
static struct k_mem_slab mslab;
static struct k_sem sema;
static struct k_mutex mutex;
static struct k_alert alert;
static struct k_stack stack;
static struct k_msgq msgq;
static struct k_mbox mbox;
@ -142,23 +134,6 @@ static void get_obj_count(int obj_type)
}
zassert_equal(obj_found, 2, "Didn't find mutex objects");
break;
case ALERT:
k_alert_init(&alert, K_ALERT_IGNORE, 1);
obj_list = SYS_TRACING_HEAD(struct k_alert, k_alert);
while (obj_list != NULL) {
if (obj_list == &kalert || obj_list == &alert) {
obj_found++;
if (obj_found == 2) {
TC_PRINT("Found alert objects\n");
break;
}
}
obj_list = SYS_TRACING_NEXT(struct k_alert, k_alert,
obj_list);
}
zassert_equal(obj_found, 2, "Didn't find alert objects");
break;
case STACK:
k_stack_init(&stack, sdata, NUM_BLOCKS);