227 lines
6.4 KiB
ReStructuredText
227 lines
6.4 KiB
ReStructuredText
.. _microkernel_events:
|
|
|
|
Events
|
|
######
|
|
|
|
Concepts
|
|
********
|
|
|
|
The microkernel's event objects are an implementation of traditional
|
|
binary semaphores.
|
|
|
|
Any number of events can be defined in a microkernel system. Each event
|
|
has a name that uniquely identifies it.
|
|
|
|
An event is typically *sent* by a task, fiber, or ISR and *received*
|
|
by a task, which then takes some action in response. Events are the easiest
|
|
and most efficient way to synchronize operations between two different
|
|
execution contexts.
|
|
|
|
Each event starts off in the *clear* state. Once an event has been sent
|
|
it is placed into the *set* state, and remains in that state until it is
|
|
received; the event's state then reverts back to clear. Sending an event
|
|
that is already set is permitted, but does not affect the event's state
|
|
and does not allow the receiving task to recognize that the event has been sent
|
|
more than once.
|
|
|
|
The receiving task may test an event's state in either a non-blocking or
|
|
blocking manner. The kernel allows only a single receiving task to wait
|
|
for a given event; if a second task attempts to wait its receive operation
|
|
immediately returns a failure indication.
|
|
|
|
Each event has an optional *event handler* function, which is executed
|
|
by the microkernel server fiber when the event is sent. This function
|
|
allows an event to be processed more quickly, without requiring the kernel
|
|
to schedule a receiving task. If the event handler determines that the event
|
|
can be ignored, or it is able to process the event without the assistance
|
|
of a task, the event handler returns a value of zero and the event's state
|
|
is left unchanged. If the event handler determines that additional processing
|
|
is required it returns a non-zero value and the event's state is changed
|
|
to set (if it isn't already set).
|
|
|
|
An event handler function can be used to improve the efficiency of event
|
|
processing by the receiving task, and can even eliminate the need for the
|
|
receiving task entirely is some situations. Any event that does not require
|
|
an event handler can specify the :c:macro:`NULL` function. The event handler
|
|
function is passed the name of the event being sent each time it is invoked,
|
|
allowing the same function to be shared by multiple events. An event's event
|
|
handler function is specified at compile-time, but can be changed subsequently
|
|
at run-time.
|
|
|
|
Purpose
|
|
*******
|
|
|
|
Use an event to signal a task to take action in response to a condition
|
|
detected by another task, a fiber, or an ISR.
|
|
|
|
Use an event handler to allow the microkernel server fiber to handle an event,
|
|
prior to (or instead of) letting a task handle the event.
|
|
|
|
Usage
|
|
*****
|
|
|
|
Defining an Event
|
|
=================
|
|
|
|
The following parameters must be defined:
|
|
|
|
*name*
|
|
This specifies a unique name for the event.
|
|
|
|
*handler*
|
|
This specifies the name of the event handler function,
|
|
which should have the following form:
|
|
|
|
.. code-block:: c
|
|
|
|
int <entry_point>(int event)
|
|
{
|
|
/* start handling event; return zero if all done, */
|
|
/* or non-zero to let receiving task handle event */
|
|
...
|
|
}
|
|
|
|
If no event handler is required specify :c:macro:`NULL`.
|
|
|
|
Public Event
|
|
------------
|
|
|
|
Define the event in the application's MDEF using the following syntax:
|
|
|
|
.. code-block:: console
|
|
|
|
EVENT name handler
|
|
|
|
For example, the file :file:`projName.mdef` defines two events
|
|
as follows:
|
|
|
|
.. code-block:: console
|
|
|
|
% EVENT NAME ENTRY
|
|
% ==========================================
|
|
EVENT KEYPRESS validate_keypress
|
|
EVENT BUTTONPRESS NULL
|
|
|
|
A public event can be referenced by name from any source file that includes
|
|
the file :file:`zephyr.h`.
|
|
|
|
Private Event
|
|
-------------
|
|
|
|
Define the event in a source file using the following syntax:
|
|
|
|
.. code-block:: c
|
|
|
|
DEFINE_EVENT(name, handler);
|
|
|
|
For example, the following code defines a private event named ``PRIV_EVENT``,
|
|
which has no associated event handler function.
|
|
|
|
.. code-block:: c
|
|
|
|
DEFINE_EVENT(PRIV_EVENT, NULL);
|
|
|
|
To utilize this event from a different source file use the following syntax:
|
|
|
|
.. code-block:: c
|
|
|
|
extern const kevent_t PRIV_EVENT;
|
|
|
|
Example: Signaling an Event from an ISR
|
|
========================================
|
|
|
|
This code signals an event during the processing of an interrupt.
|
|
|
|
.. code-block:: c
|
|
|
|
void keypress_interrupt_handler(void *arg)
|
|
{
|
|
...
|
|
isr_event_signal(KEYPRESS);
|
|
...
|
|
}
|
|
|
|
Example: Consuming an Event using a Task
|
|
========================================
|
|
|
|
This code processes events of a single type using a task.
|
|
|
|
.. code-block:: c
|
|
|
|
void keypress_task(void)
|
|
{
|
|
/* consume key presses */
|
|
while (1) {
|
|
|
|
/* wait for a key press to be signalled */
|
|
task_event_recv(KEYPRESS, TICKS_NONE);
|
|
|
|
/* determine what key was pressed */
|
|
char c = get_keypress();
|
|
|
|
/* process key press */
|
|
...
|
|
}
|
|
}
|
|
|
|
Example: Filtering Event Signals using an Event Handler
|
|
=======================================================
|
|
|
|
This code registers an event handler that filters out unwanted events
|
|
so that the receiving task only wakes up when needed.
|
|
|
|
.. code-block:: c
|
|
|
|
int validate_keypress(int event_id_is_unused)
|
|
{
|
|
/* determine what key was pressed */
|
|
char c = get_keypress();
|
|
|
|
/* signal task only if key pressed was a digit */
|
|
if ((c >= '0') && (c <= '9')) {
|
|
/* save key press information */
|
|
...
|
|
/* event is signalled to task */
|
|
return 1;
|
|
} else {
|
|
/* event is not signalled to task */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void keypress_task(void)
|
|
{
|
|
/* register the filtering routine */
|
|
task_event_handler_set(KEYPRESS, validate_keypress);
|
|
|
|
/* consume key presses */
|
|
while (1) {
|
|
|
|
/* wait for a key press to be signalled */
|
|
task_event_recv(KEYPRESS, TICKS_NONE);
|
|
|
|
/* process saved key press, which must be a digit */
|
|
...
|
|
}
|
|
}
|
|
|
|
APIs
|
|
****
|
|
|
|
The following Event APIs are provided by :file:`microkernel.h`:
|
|
|
|
:cpp:func:`isr_event_send()`
|
|
Signal an event from an ISR.
|
|
|
|
:cpp:func:`fiber_event_send()`
|
|
Signal an event from a fiber.
|
|
|
|
:cpp:func:`task_event_send()`
|
|
Signal an event from a task.
|
|
|
|
:c:func:`task_event_recv()`
|
|
Waits for an event signal for a specified time period.
|
|
|
|
:cpp:func:`task_event_handler_set()`
|
|
Registers an event handler function for an event.
|