unified: rename 'events' to 'alerts'
Event is such an overloaded and generic term (event logger, *kernel* event logger, "protocol" events in other subsystems, etc.), that it is confusing for the name an object. Events are kinda like signals, but not exactly, so we chose not to name them 'signals' to prevent further confusion. "Alerts" felt like a good fit, since they are used to "alert" an application that something of significance should be addressed and because an "alert handler" can be proactively registered with an alert. Change-Id: Ibfeb5eaf0e6e62702ac3fec281d17f8a63145fa1 Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
This commit is contained in:
parent
7ef0f624a7
commit
31a3f6a70e
11 changed files with 356 additions and 356 deletions
|
@ -100,11 +100,11 @@ The nanokernel semaphore and microkernel semaphore object types have been
|
|||
merged into a single type. The new type can now be used as a binary semaphore,
|
||||
as well as a counting semaphore.
|
||||
|
||||
The microkernel event object type is now presented as a relative to Unix-style
|
||||
signalling. Due to improvements to the implementation of semaphores, events
|
||||
are now less efficient to use for basic synchronization than semaphores;
|
||||
consequently, events should now be reserved for scenarios requiring the use
|
||||
of a callback function.
|
||||
The microkernel event object type is renamed to "alert" and is now presented as
|
||||
a relative to Unix-style signalling. Due to improvements to the implementation
|
||||
of semaphores, alerts are now less efficient to use for basic synchronization
|
||||
than semaphores; consequently, alerts should now be reserved for scenarios
|
||||
requiring the use of a callback function.
|
||||
|
||||
Data Passing
|
||||
************
|
||||
|
|
236
doc/kernel_v2/synchronization/alerts.rst
Normal file
236
doc/kernel_v2/synchronization/alerts.rst
Normal file
|
@ -0,0 +1,236 @@
|
|||
.. _alerts_v2:
|
||||
|
||||
Alerts
|
||||
######
|
||||
|
||||
An :dfn:`alert` is a kernel object that allows an application to perform
|
||||
asynchronous signalling 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 signalled. 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 **alert pending flag**, which is set if the alert is signalled
|
||||
and an alert handler function has not processed the signal.
|
||||
|
||||
An alert must be initialized before it can be used. This establishes
|
||||
its alert handler and clears the alert pending flag.
|
||||
|
||||
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 alert pending flag to be set.
|
||||
|
||||
* 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 alert
|
||||
pending flag is set.
|
||||
|
||||
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.
|
||||
|
||||
An alert whose alert pending flag becomes set remains pending until
|
||||
the alert is accepted by a thread. This clears the alert pending flag.
|
||||
|
||||
A thread accepts a pending alert by **receiving** the alert.
|
||||
If the alert's pending flag is currently clear, 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 that accepts an alert cannot directly determine how many times
|
||||
the alert pending flag was set since the alert was last accepted.
|
||||
|
||||
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 pre-defined 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.
|
||||
|
||||
.. 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);
|
||||
|
||||
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);
|
||||
|
||||
Signaling an Alert
|
||||
==================
|
||||
|
||||
An alert is signalled 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);
|
||||
|
||||
void keypress_interrupt_handler(void *arg)
|
||||
{
|
||||
...
|
||||
k_alert_send(&my_alert);
|
||||
...
|
||||
}
|
||||
|
||||
Handling an Alert
|
||||
=================
|
||||
|
||||
An alert handler function is used when a signalled 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 */
|
||||
...
|
||||
|
||||
/* signalled 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 */
|
||||
...
|
||||
/* signalled alert should be pended */
|
||||
return 1;
|
||||
} else {
|
||||
/* signalled 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 pre-process 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`:
|
||||
|
||||
* :cpp:func:`k_alert_handler_set()`
|
||||
* :cpp:func:`k_alert_send()`
|
||||
* :cpp:func:`k_alert_recv()`
|
|
@ -1,236 +0,0 @@
|
|||
.. _events_v2:
|
||||
|
||||
Events
|
||||
######
|
||||
|
||||
An :dfn:`event` is a kernel object that allows an application to perform
|
||||
asynchronous signalling when a condition of interest occurs.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
Concepts
|
||||
********
|
||||
|
||||
Any number of events can be defined. Each event is referenced by
|
||||
its memory address.
|
||||
|
||||
An event has the following key properties:
|
||||
|
||||
* An **event handler**, which specifies the action to be taken
|
||||
when the event is signalled. The action may instruct the system workqueue
|
||||
to execute a function to process the event, mark the event as pending
|
||||
so it can be later processed by a thread, or ignore the event.
|
||||
|
||||
* An **event pending flag**, which is set if the event is signalled
|
||||
and an event handler function does not consume the signal.
|
||||
|
||||
An event must be initialized before it can be used. This establishes
|
||||
its event handler and clears the event pending flag.
|
||||
|
||||
Event Lifecycle
|
||||
===============
|
||||
|
||||
An ISR or a thread signals an event by **sending** the event
|
||||
when a condition of interest occurs that cannot be handled by the detector.
|
||||
|
||||
Each time an event is sent, the kernel examines its event handler
|
||||
to determine what action to take.
|
||||
|
||||
* :c:macro:`K_EVT_IGNORE` causes the event to be ignored.
|
||||
|
||||
* :c:macro:`K_EVT_DEFAULT` causes the event pending flag to be set.
|
||||
|
||||
* Any other value is assumed to be the address of an event 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 event
|
||||
pending flag is set.
|
||||
|
||||
The kernel ensures that the event handler function is executed once
|
||||
for each time an event is sent, even if the event is sent multiple times
|
||||
in rapid succession.
|
||||
|
||||
An event whose event pending flag becomes set remains pending until
|
||||
the event is accepted by a thread. This clears the event pending flag.
|
||||
|
||||
A thread accepts a pending event by **receiving** the event.
|
||||
If the event's pending flag is currently clear, the thread may choose
|
||||
to wait for the event to become pending.
|
||||
Any number of threads may wait for a pending event simultaneously;
|
||||
when the event is pended it is accepted by the highest priority thread
|
||||
that has waited longest.
|
||||
|
||||
.. note::
|
||||
A thread that accepts an event cannot directly determine how many times
|
||||
the event pending flag was set since the event was last accepted.
|
||||
|
||||
Comparison to Unix-style Signals
|
||||
================================
|
||||
|
||||
Zephyr events are somewhat akin to Unix-style signals, but have a number of
|
||||
significant differences. The most notable of these are listed below:
|
||||
|
||||
* A Zephyr event cannot be blocked --- it is always delivered to its event
|
||||
handler immediately.
|
||||
|
||||
* A Zephyr event pends *after* it has been delivered to its event handler,
|
||||
and only if an event handler function does not consume the event.
|
||||
|
||||
* Zephyr has no pre-defined events or actions. All events are application
|
||||
defined, and all have a default action that pends the event.
|
||||
|
||||
Implementation
|
||||
**************
|
||||
|
||||
Defining an Event
|
||||
=================
|
||||
|
||||
An event is defined using a variable of type :c:type:`struct k_event`.
|
||||
It must then be initialized by calling :cpp:func:`k_event_init()`.
|
||||
|
||||
The following code defines and initializes an event.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
extern int my_event_handler(struct k_event *event);
|
||||
|
||||
struct k_event my_event;
|
||||
|
||||
k_event_init(&my_event, my_event_handler);
|
||||
|
||||
Alternatively, an event can be defined and initialized at compile time
|
||||
by calling :c:macro:`K_EVENT_DEFINE()`.
|
||||
|
||||
The following code has the same effect as the code segment above.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
extern int my_event_handler(struct k_event *event);
|
||||
|
||||
K_EVENT_DEFINE(my_event, my_event_handler);
|
||||
|
||||
Signaling an Event
|
||||
==================
|
||||
|
||||
An event is signalled by calling :cpp:func:`k_event_send()`.
|
||||
|
||||
The following code illustrates how an ISR can signal an event
|
||||
to indicate that a key press has occurred.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
extern int my_event_handler(struct k_event *event);
|
||||
|
||||
K_EVENT_DEFINE(my_event, my_event_handler);
|
||||
|
||||
void keypress_interrupt_handler(void *arg)
|
||||
{
|
||||
...
|
||||
k_event_send(&my_event);
|
||||
...
|
||||
}
|
||||
|
||||
Handling an Event
|
||||
=================
|
||||
|
||||
An event handler function is used when a signalled event should not be ignored
|
||||
or immediately pended. It has the following form:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int <function_name>(struct k_event *event)
|
||||
{
|
||||
/* catch the event signal; return zero if the signal is consumed, */
|
||||
/* or non-zero to let the event pend */
|
||||
...
|
||||
}
|
||||
|
||||
The following code illustrates an event handler function that processes
|
||||
key presses detected by an ISR (as shown in the previous section).
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int my_event_handler(struct k_event *event_id_is_unused)
|
||||
{
|
||||
/* determine what key was pressed */
|
||||
char c = get_keypress();
|
||||
|
||||
/* do complex processing of the keystroke */
|
||||
...
|
||||
|
||||
/* signalled event has been consumed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
Accepting an Event
|
||||
==================
|
||||
|
||||
A pending event is accepted by a thread by calling :cpp:func:`k_event_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 event handler function is now used only to filter out unwanted key press
|
||||
events, allowing the dedicated thread to wake up and process key press events
|
||||
only when a numeric key is pressed.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int my_event_handler(struct k_event *event_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 */
|
||||
...
|
||||
/* signalled event should be pended */
|
||||
return 1;
|
||||
} else {
|
||||
/* signalled event 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 event to pend */
|
||||
k_event_recv(&my_event, K_FOREVER);
|
||||
|
||||
/* process saved key press, which must be a digit */
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
Suggested Uses
|
||||
**************
|
||||
|
||||
Use an event to minimize ISR processing by deferring interrupt-related
|
||||
work to a thread to reduce the amount of time interrupts are locked.
|
||||
|
||||
Use an event to allow the kernel's system workqueue to handle an event,
|
||||
rather than defining an application thread to handle it.
|
||||
|
||||
Use an event to allow the kernel's system workqueue to pre-process an event,
|
||||
prior to letting an application thread handle it.
|
||||
|
||||
Configuration Options
|
||||
*********************
|
||||
|
||||
Related configuration options:
|
||||
|
||||
* None.
|
||||
|
||||
APIs
|
||||
****
|
||||
|
||||
The following event APIs are provided by :file:`kernel.h`:
|
||||
|
||||
* :cpp:func:`k_event_handler_set()`
|
||||
* :cpp:func:`k_event_send()`
|
||||
* :cpp:func:`k_event_recv()`
|
|
@ -12,4 +12,4 @@ of different threads, or the operation of an ISR and a thread.
|
|||
semaphores.rst
|
||||
semaphore_groups.rst
|
||||
mutexes.rst
|
||||
events.rst
|
||||
alerts.rst
|
||||
|
|
|
@ -125,23 +125,23 @@ Using a Timer Expiry Function
|
|||
|
||||
The following code uses a timer to perform a non-trivial action on a periodic
|
||||
basis. Since the required work cannot be done at interrupt level,
|
||||
the timer's expiry function uses a :ref:`kernel event object <events_v2>`
|
||||
the timer's expiry function uses a :ref:`kernel alert object <alerts_v2>`
|
||||
to do the work in the context of the system workqueue.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int my_event_handler(struct k_event *dummy)
|
||||
int my_alert_handler(struct k_alert *dummy)
|
||||
{
|
||||
/* do the processing that needs to be done periodically */
|
||||
...
|
||||
return 0;
|
||||
}
|
||||
|
||||
K_EVENT_DEFINE(my_event, my_event_handler);
|
||||
K_ALERT_DEFINE(my_alert, my_alert_handler);
|
||||
|
||||
void my_timer_handler(struct k_timer *dummy)
|
||||
{
|
||||
k_event_send(&my_event);
|
||||
k_alert_send(&my_alert);
|
||||
}
|
||||
|
||||
K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);
|
||||
|
|
|
@ -81,7 +81,7 @@ typedef sys_dlist_t _wait_q_t;
|
|||
struct tcs;
|
||||
struct k_mutex;
|
||||
struct k_sem;
|
||||
struct k_event;
|
||||
struct k_alert;
|
||||
struct k_msgq;
|
||||
struct k_mbox;
|
||||
struct k_pipe;
|
||||
|
@ -923,41 +923,41 @@ extern void k_sem_group_reset(struct k_sem *sem_array[]);
|
|||
struct k_sem name = \
|
||||
K_SEM_INITIALIZER(name, initial_count, count_limit)
|
||||
|
||||
/* events */
|
||||
/* alerts */
|
||||
|
||||
#define K_EVT_DEFAULT NULL
|
||||
#define K_EVT_IGNORE ((void *)(-1))
|
||||
#define K_ALERT_DEFAULT NULL
|
||||
#define K_ALERT_IGNORE ((void *)(-1))
|
||||
|
||||
typedef int (*k_event_handler_t)(struct k_event *);
|
||||
typedef int (*k_alert_handler_t)(struct k_alert *);
|
||||
|
||||
struct k_event {
|
||||
k_event_handler_t handler;
|
||||
struct k_alert {
|
||||
k_alert_handler_t handler;
|
||||
atomic_t send_count;
|
||||
struct k_work work_item;
|
||||
struct k_sem sem;
|
||||
|
||||
_DEBUG_TRACING_KERNEL_OBJECTS_NEXT_PTR(k_event);
|
||||
_DEBUG_TRACING_KERNEL_OBJECTS_NEXT_PTR(k_alert);
|
||||
};
|
||||
|
||||
extern void _k_event_deliver(struct k_work *work);
|
||||
extern void _alert_deliver(struct k_work *work);
|
||||
|
||||
#define K_EVENT_INITIALIZER(obj, event_handler) \
|
||||
#define K_ALERT_INITIALIZER(obj, alert_handler) \
|
||||
{ \
|
||||
.handler = (k_event_handler_t)event_handler, \
|
||||
.handler = (k_alert_handler_t)alert_handler, \
|
||||
.send_count = ATOMIC_INIT(0), \
|
||||
.work_item = K_WORK_INITIALIZER(_k_event_deliver), \
|
||||
.work_item = K_WORK_INITIALIZER(_alert_deliver), \
|
||||
.sem = K_SEM_INITIALIZER(obj.sem, 0, 1), \
|
||||
_DEBUG_TRACING_KERNEL_OBJECTS_INIT \
|
||||
}
|
||||
|
||||
#define K_EVENT_DEFINE(name, event_handler) \
|
||||
struct k_event name \
|
||||
__in_section(_k_event_list, event, name) = \
|
||||
K_EVENT_INITIALIZER(name, event_handler)
|
||||
#define K_ALERT_DEFINE(name, alert_handler) \
|
||||
struct k_alert name \
|
||||
__in_section(_k_event_list, alert, name) = \
|
||||
K_ALERT_INITIALIZER(name, alert_handler)
|
||||
|
||||
extern void k_event_init(struct k_event *event, k_event_handler_t handler);
|
||||
extern int k_event_recv(struct k_event *event, int32_t timeout);
|
||||
extern void k_event_send(struct k_event *event);
|
||||
extern void k_alert_init(struct k_alert *alert, k_alert_handler_t handler);
|
||||
extern int k_alert_recv(struct k_alert *alert, int32_t timeout);
|
||||
extern void k_alert_send(struct k_alert *alert);
|
||||
|
||||
/**
|
||||
* data transfers (complex)
|
||||
|
|
|
@ -360,7 +360,7 @@ static inline int nano_delayed_work_submit_to_queue(struct nano_workqueue *wq,
|
|||
|
||||
/* events */
|
||||
|
||||
#define kevent_t const struct k_event *
|
||||
#define kevent_t const struct k_alert *
|
||||
typedef int (*kevent_handler_t)(int event);
|
||||
|
||||
#define isr_event_send task_event_send
|
||||
|
@ -369,32 +369,32 @@ typedef int (*kevent_handler_t)(int event);
|
|||
static inline int task_event_handler_set(kevent_t legacy_event,
|
||||
kevent_handler_t handler)
|
||||
{
|
||||
struct k_event *event = (struct k_event *)legacy_event;
|
||||
struct k_alert *alert = (struct k_alert *)legacy_event;
|
||||
|
||||
if ((event->handler != NULL) && (handler != NULL)) {
|
||||
if ((alert->handler != NULL) && (handler != NULL)) {
|
||||
/* can't overwrite an existing event handler */
|
||||
return RC_FAIL;
|
||||
}
|
||||
|
||||
event->handler = (k_event_handler_t)handler;
|
||||
alert->handler = (k_alert_handler_t)handler;
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static inline int task_event_send(kevent_t legacy_event)
|
||||
{
|
||||
k_event_send((struct k_event *)legacy_event);
|
||||
k_alert_send((struct k_alert *)legacy_event);
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static inline int task_event_recv(kevent_t legacy_event, int32_t timeout)
|
||||
{
|
||||
return _error_to_rc(k_event_recv((struct k_event *)legacy_event,
|
||||
return _error_to_rc(k_alert_recv((struct k_alert *)legacy_event,
|
||||
_ticks_to_ms(timeout)));
|
||||
}
|
||||
|
||||
#define DEFINE_EVENT(name, event_handler) \
|
||||
K_EVENT_DEFINE(_k_event_obj_##name, event_handler); \
|
||||
struct k_event * const name = &(_k_event_obj_##name)
|
||||
K_ALERT_DEFINE(_k_event_obj_##name, event_handler); \
|
||||
struct k_alert * const name = &(_k_event_obj_##name)
|
||||
|
||||
/* memory maps */
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ lib-y += $(strip \
|
|||
msg_q.o \
|
||||
mailbox.o \
|
||||
mem_pool.o \
|
||||
event.o \
|
||||
alert.o \
|
||||
pipes.o \
|
||||
legacy_offload.o \
|
||||
errno.o \
|
||||
|
|
78
kernel/unified/alert.c
Normal file
78
kernel/unified/alert.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Wind River Systems, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief kernel alerts.
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <nano_private.h>
|
||||
#include <misc/debug/object_tracing_common.h>
|
||||
#include <atomic.h>
|
||||
#include <toolchain.h>
|
||||
#include <sections.h>
|
||||
|
||||
void _alert_deliver(struct k_work *work)
|
||||
{
|
||||
struct k_alert *alert = CONTAINER_OF(work, struct k_alert, work_item);
|
||||
|
||||
while (1) {
|
||||
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)
|
||||
{
|
||||
const struct k_work my_work_item = { NULL, _alert_deliver, { 1 } };
|
||||
|
||||
alert->handler = handler;
|
||||
alert->send_count = ATOMIC_INIT(0);
|
||||
alert->work_item = my_work_item;
|
||||
k_sem_init(&alert->sem, 0, 1);
|
||||
SYS_TRACING_OBJ_INIT(micro_event, alert);
|
||||
}
|
||||
|
||||
void 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int k_alert_recv(struct k_alert *alert, int32_t timeout)
|
||||
{
|
||||
return k_sem_take(&alert->sem, timeout);
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Wind River Systems, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief kernel events.
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <nano_private.h>
|
||||
#include <misc/debug/object_tracing_common.h>
|
||||
#include <atomic.h>
|
||||
#include <toolchain.h>
|
||||
#include <sections.h>
|
||||
|
||||
void _k_event_deliver(struct k_work *work)
|
||||
{
|
||||
struct k_event *event = CONTAINER_OF(work, struct k_event, work_item);
|
||||
|
||||
while (1) {
|
||||
if ((event->handler)(event) == 0) {
|
||||
/* do nothing -- handler has processed the event */
|
||||
} else {
|
||||
/* pend the event */
|
||||
k_sem_give(&event->sem);
|
||||
}
|
||||
if (atomic_dec(&event->send_count) == 1) {
|
||||
/* have finished delivering events */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void k_event_init(struct k_event *event, k_event_handler_t handler)
|
||||
{
|
||||
const struct k_work my_work_item = { NULL, _k_event_deliver, { 1 } };
|
||||
|
||||
event->handler = handler;
|
||||
event->send_count = ATOMIC_INIT(0);
|
||||
event->work_item = my_work_item;
|
||||
k_sem_init(&event->sem, 0, 1);
|
||||
SYS_TRACING_OBJ_INIT(event, event);
|
||||
}
|
||||
|
||||
void k_event_send(struct k_event *event)
|
||||
{
|
||||
if (event->handler == K_EVT_IGNORE) {
|
||||
/* ignore the event */
|
||||
} else if (event->handler == K_EVT_DEFAULT) {
|
||||
/* pend the event */
|
||||
k_sem_give(&event->sem);
|
||||
} else {
|
||||
/* deliver the event */
|
||||
if (atomic_inc(&event->send_count) == 0) {
|
||||
/* add event's work item to system work queue */
|
||||
k_work_submit_to_queue(&k_sys_work_q,
|
||||
&event->work_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int k_event_recv(struct k_event *event, int32_t timeout)
|
||||
{
|
||||
return k_sem_take(&event->sem, timeout);
|
||||
}
|
|
@ -583,7 +583,7 @@ def kernel_main_c_events():
|
|||
if kernel_type == 'micro':
|
||||
event_type = 'int'
|
||||
else:
|
||||
event_type = 'struct k_event *'
|
||||
event_type = 'struct k_alert *'
|
||||
|
||||
# event descriptors
|
||||
|
||||
|
@ -608,7 +608,7 @@ def kernel_main_c_events():
|
|||
if kernel_type == 'micro':
|
||||
kernel_main_c_out("DEFINE_EVENT(%s, %s);\n" % (event[0], event[1]))
|
||||
else:
|
||||
kernel_main_c_out("K_EVENT_DEFINE(_k_event_obj_%s, %s);\n" %
|
||||
kernel_main_c_out("K_ALERT_DEFINE(_k_event_obj_%s, %s);\n" %
|
||||
(event[0], event[1]))
|
||||
|
||||
def kernel_main_c_mutexes():
|
||||
|
@ -1132,7 +1132,7 @@ def generate_sysgen_h_obj_ids():
|
|||
fifo_type = 'struct k_msgq *'
|
||||
mbox_struct = 'k_mbox'
|
||||
mbox_type = 'struct k_mbox *'
|
||||
event_type = 'struct k_event *'
|
||||
event_type = 'struct k_alert *'
|
||||
mem_pool_type = 'struct k_mem_pool'
|
||||
# add missing object types
|
||||
|
||||
|
@ -1221,7 +1221,7 @@ def generate_sysgen_h_obj_ids():
|
|||
sysgen_h_data += "extern const %s %s;\n" % (event_type, name)
|
||||
elif (kernel_type == 'unified'):
|
||||
sysgen_h_data += \
|
||||
"extern struct k_event _k_event_obj_%s;\n" % (name)
|
||||
"extern struct k_alert _k_event_obj_%s;\n" % (name)
|
||||
sysgen_h_data += \
|
||||
"#define %s (&_k_event_obj_%s)\n\n" % (name, name)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue