456 lines
22 KiB
ReStructuredText
456 lines
22 KiB
ReStructuredText
.. _microkernelObjects:
|
||
|
||
Microkernel Objects
|
||
###################
|
||
|
||
Section Scope
|
||
*************
|
||
|
||
This section provides an overview of the most important microkernel
|
||
objects, and their operation.
|
||
|
||
Each object contains a definition, a function description, and a table
|
||
of Application Program Interfaces (API) including the context that may
|
||
call them. Please refer to the API documentation for further details
|
||
regarding each object’s functionality.
|
||
|
||
Microkernel FIFO Objects
|
||
************************
|
||
|
||
Definition
|
||
==========
|
||
|
||
Tiny Mountain FIFO object is defined in
|
||
:file:`include/microkernel/fifo.h` as a simple first-in, first-out
|
||
queue that handle small amounts of fixed size data. FIFO objects have a
|
||
buffer that stores a number of data transmits, and are the most
|
||
efficient way to pass small amounts of data between tasks. FIFO objects
|
||
are suitable for asynchronously transferring small amounts of data,
|
||
such as parameters, between tasks.
|
||
|
||
Function
|
||
========
|
||
|
||
|
||
FIFO objects store data in a statically allocated buffer defined within
|
||
the project’s VPF file. The depth of the FIFO object buffer is only
|
||
limited by the available memory on the platform. Individual FIFO data
|
||
objects can be at most 40 bytes in size, and are stored in an ordered
|
||
first-come, first-serve basis, not by priority.
|
||
|
||
FIFO objects are asynchronous. When using a FIFO object, the sender can
|
||
add data even if the receiver is not ready yet. This only applies if
|
||
there is sufficient space on the buffer to store the sender's data.
|
||
|
||
FIFO objects are anonymous. The kernel object does not store the sender
|
||
or receiver identity. If the sender identification is required, it is
|
||
up to the caller to store that information in the data placed into the
|
||
FIFO. The receiving task can then check it. Alternatively, mailboxes
|
||
can be used to specify the sender and receiver identities.
|
||
|
||
FIFO objects read and write actions are always fixed-size block-based.
|
||
The width of each FIFO object block is specified in the project file.
|
||
If a task calls :c:func:`task_fifo_get()` and the call succeeds, then
|
||
the fixed number of bytes is copied from the FIFO object into the
|
||
addresses of the destination pointer.
|
||
|
||
Initialization
|
||
==============
|
||
FIFO objects are created by defining them in a project file, for example
|
||
:file:`projName.vpf`. Specify the name of the FIFO object, the width in
|
||
bytes of a single entry, the number of entries, and, if desired, the
|
||
location defined in the architecture file to be used for the FIFO. Use
|
||
the following syntax in the VPF file to define a FIFO:
|
||
|
||
.. code-block:: console
|
||
|
||
FIFO %name %depthNumEntries %widthBytes [ bufSegLocation ]
|
||
|
||
An example of a FIFO entry for use in the VPF file:
|
||
|
||
.. code-block:: console
|
||
|
||
% FIFO NAME DEPTH WIDTH
|
||
|
||
% ============================
|
||
|
||
FIFO FIFOQ 2 4
|
||
|
||
|
||
Application Program Interfaces
|
||
==============================
|
||
The FIFO object APIs allow to putting data on the queue, receiving data
|
||
from the queue, finding the number of messages in the queue, and
|
||
emptying the queue.
|
||
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| **Call** | **Description** |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_put()` | Put data on a FIFO, and fail |
|
||
| | if the FIFO is full. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_put_wait()` | Put data on a FIFO, waiting |
|
||
| | for room in the FIFO. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_put_wait_timeout()` | Put data on a FIFO, waiting |
|
||
| | for room in the FIFO, or a time out. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_get()` | Get data off a FIFO, |
|
||
| | returning immediately if no data is available. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_get_wait()` | Get data off a FIFO, |
|
||
| | waiting until data is available. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_get_wait_timeout()` | Get data off a FIFO, |
|
||
| | waiting until data is available, or a time out. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_purge()` | Empty the FIFO buffer, and |
|
||
| | signal any waiting receivers with an error. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
| :c:func:`task_fifo_size_get()` | Read the number of filled |
|
||
| | entries in a FIFO. |
|
||
+----------------------------------------+-------------------------------------------------+
|
||
|
||
Pipe Objects
|
||
************
|
||
|
||
Definition
|
||
==========
|
||
|
||
Microkernel pipes are defined in :file:`kernel/microkernel/k_pipe.c`.
|
||
Pipes allow any task to put any amount of data in or out. Pipes are
|
||
conceptually similar to FIFO objects in that they communicate
|
||
anonymously in a time-ordered, first-in, first-out manner, to exchange
|
||
data between tasks. Like FIFO objects, pipes can have a buffer, but
|
||
un-buffered operation is also possible. The main difference between
|
||
FIFO objects and pipes is that pipes handle variable-sized data.
|
||
|
||
Function
|
||
========
|
||
|
||
Pipes accept and send variable-sized data, and can be configured to work
|
||
with or without a buffer. Buffered pipes are time-ordered. The incoming
|
||
data is stored on a first-come, first-serve basis in the buffer; it is
|
||
not sorted by priority.
|
||
|
||
Pipes have no size limit. The size of the data transfer and the size of
|
||
the buffer have no limit except for the available memory. Pipes allow
|
||
senders or receivers to perform partial read and partial write
|
||
operations.
|
||
|
||
Pipes support both synchronous and asynchronous operations. If a pipe is
|
||
unbuffered, the sender can asynchronously put data into the pipe, or
|
||
wait for the data to be received, and the receiver can attempt to
|
||
remove data from the pipe, or wait on the data to be available.
|
||
Buffered pipes are synchronous by design.
|
||
|
||
Pipes are anonymous. The pipe transfer does not identify the sender or
|
||
receiver. Alternatively, mailboxes can be used to specify the sender
|
||
and receiver identities.
|
||
|
||
Initialization
|
||
==============
|
||
|
||
|
||
A target pipe has to be defined in the project file, for example
|
||
:file:`projName.vpf`. Specify the name of the pipe, the size of the
|
||
buffer in bytes, and the memory location for the pipe buffer as defined
|
||
in the linker script. The buffer’s memory is allocated on the processor
|
||
that manages the pipe. Use the following syntax in the VPF file to
|
||
define a pipe:
|
||
|
||
.. code-block:: console
|
||
|
||
PIPE %name %buffersize [%bufferSegment]
|
||
|
||
An example of a pipe entry for use in the VPF file:
|
||
|
||
.. code-block:: console
|
||
|
||
% PIPE NAME BUFFERSIZE [BUFFER_SEGMENT]
|
||
|
||
% ===================================================
|
||
|
||
PIPE PIPE_ID 256
|
||
|
||
|
||
Application Program Interfaces
|
||
==============================
|
||
|
||
The pipes APIs allow to sending and receiving data to and from a pipe.
|
||
|
||
+----------------------------------------+----------------------------------------+
|
||
| **Call** | **Description** |
|
||
+----------------------------------------+----------------------------------------+
|
||
| :c:func:`task_pipe_put()` | Put data on a pipe |
|
||
+----------------------------------------+----------------------------------------+
|
||
| :c:func:`task_pipe_put_wait()` | Put data on a pipe with a delay. |
|
||
+----------------------------------------+----------------------------------------+
|
||
| :c:func:`task_pipe_put_wait_timeout()` | Put data on a pipe with a timed delay. |
|
||
+----------------------------------------+----------------------------------------+
|
||
| :c:func:`task_pipe_get()` | Put data on a pipe. |
|
||
+----------------------------------------+----------------------------------------+
|
||
| :c:func:`task_pipe_get_wait()` | Put data on a pipe with a delay. |
|
||
+----------------------------------------+----------------------------------------+
|
||
| :c:func:`task_pipe_get_wait_timeout()` | Put data on a pipe with a timed delay. |
|
||
+----------------------------------------+----------------------------------------+
|
||
| :c:func:`task_pipe_put_async()` | Put data on a pipe asynchronously. |
|
||
+----------------------------------------+----------------------------------------+
|
||
|
||
Mailbox Objects
|
||
***************
|
||
|
||
Definition
|
||
==========
|
||
|
||
A Tiny Mountain mailbox object is defined in include
|
||
:file:`/microkernel/mail.h`. Mailboxes are a flexible way to pass data
|
||
and for tasks to exchange messages.
|
||
|
||
|
||
Function
|
||
========
|
||
|
||
Each transfer within a mailbox can vary in size. The size of a data
|
||
transfer is only limited by the available memory on the platform.
|
||
Transmitted data is not buffered in the mailbox itself. Instead, the
|
||
buffer is either allocated from a memory pool block, or in block of
|
||
memory defined by the user.
|
||
|
||
Mailboxes can work synchronously and asynchronously. Asynchronous
|
||
mailboxes require the sender to allocate a buffer from a memory pool
|
||
block, while synchronous mailboxes will copy the sender data to the
|
||
receiver buffer.
|
||
|
||
The transfer contains one word of information that identifies either the
|
||
sender, or the receiver, or both. The sender task specifies the task it
|
||
wants to send to. The receiver task specifies the task it wants to
|
||
receive from. Then the mailbox checks the identity of the sender and
|
||
receiver tasks before passing the data.
|
||
|
||
Initialization
|
||
==============
|
||
|
||
A mailbox has to be defined in the project file, for example
|
||
:file:`projName.vpf`, which will specify the object type, and the name
|
||
of the mailbox. Use the following syntax in the VPF file to define a
|
||
Mailbox:
|
||
|
||
.. code-block:: console
|
||
|
||
MAILBOX %name
|
||
|
||
An example of a mailbox entry for use in the VPF file:
|
||
|
||
.. code-block:: console
|
||
|
||
% MAILBOX NAME
|
||
|
||
% =================
|
||
|
||
MAILBOX MYMBOX
|
||
|
||
|
||
|
||
Application Program Interfaces
|
||
==============================
|
||
|
||
|
||
Mailbox APIs provide flexibility and control for transferring data
|
||
between tasks.
|
||
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| **Call** | **Description** |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_put()` | Attempt to put data in a |
|
||
| | mailbox, and fail if the receiver isn’t waiting. |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_put_wait()` | Puts data in a mailbox, |
|
||
| | and waits for it to be received. |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_put_wait_timeout()` | Puts data in a mailbox, |
|
||
| | and waits for it to be received, with a timeout. |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_put_async()` | Puts data in a mailbox |
|
||
| | asynchronously. |
|
||
| | |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_get()` | Gets k_msg message |
|
||
| | header information from a mailbox and gets mailbox data, or returns |
|
||
| | immediately if the sender isn’t ready. |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_get_wait()` | Gets k_msg message |
|
||
| | header information from a mailbox and gets mailbox data, and waits |
|
||
| | until the sender is ready with data. |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_get_wait_timeout()` | Gets k_msg message |
|
||
| | header information from a mailbox and gets mailbox data, and waits |
|
||
| | until the sender is ready with a timeout. |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_data_get()` | Gets mailbox data and |
|
||
| | puts it in a buffer specified by a pointer. |
|
||
| | |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
| :c:func:`task_mbox_data_get_async_block()` | Gets the mailbox data |
|
||
| | and puts it in a memory pool block. |
|
||
| | |
|
||
+--------------------------------------------+---------------------------------------------------------------------+
|
||
|
||
Semaphore Objects
|
||
*****************
|
||
|
||
Definition
|
||
==========
|
||
|
||
The microkernel semaphore is defined in
|
||
:file:`kernel/microkernel/k_sema.c` and are an implementation of
|
||
traditional counting semaphores. Semaphores are used to synchronize
|
||
application task activities.
|
||
|
||
Function
|
||
========
|
||
|
||
Semaphores are initialized by the system. At start the semaphore is
|
||
un-signaled and no task is waiting for it. Any task in the system can
|
||
signal a semaphore. Every signal increments the count value associated
|
||
with the semaphore. When several tasks wait for the same semaphore at
|
||
the same time, they are held in a prioritized list. If the semaphore is
|
||
signaled, the task with the highest priority is released. If more tasks
|
||
of that priority are waiting, the first one that requested the
|
||
semaphore wakes up. Other tasks can test the semaphore to see if it is
|
||
signaled. If not signaled, tasks can either wait, with or without a
|
||
timeout, until signaled or return immediately with a failed status.
|
||
|
||
Initialization
|
||
==============
|
||
|
||
A semaphore has to be defined in the project file, for example
|
||
:file:`projName.vpf`, which will specify the object type, and the name
|
||
of the semaphore. Use the following syntax in the VPF file to define a
|
||
semaphore::
|
||
|
||
.. code-block:: console
|
||
|
||
SEMA %name %node
|
||
|
||
An example of a semaphore entry for use in the VPF file:
|
||
|
||
.. code-block:: console
|
||
|
||
% SEMA NAME
|
||
|
||
% =================
|
||
|
||
SEMA SEM_TASKDONE
|
||
|
||
|
||
|
||
Application Program Interfaces
|
||
==============================
|
||
|
||
Semaphore APIs allow signaling a semaphore. They also provide means to
|
||
reset the signal count.
|
||
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| **Call** | **Description** |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`isr_sem_give()` | Signal a semaphore from an ISR. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`task_sem_give()` | Signal a semaphore from a task. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`task_sem_take()` | Test a semaphore from a task. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`task_sem_take_wait()` | Wait on a semaphore from a task. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`task_sem_take_wait_timeout()` | Wait on a semaphore, with a timeout, from a task. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`task_sem_group_reset()` | Sets a list of semaphores to zero. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`task_sem_group_give()` | Signals a list of semaphores from a task. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
| :c:func:`task_sem_reset()` | Sets a semaphore to zero. |
|
||
+----------------------------------------+---------------------------------------------------+
|
||
|
||
Event Objects
|
||
*************
|
||
|
||
Definition
|
||
==========
|
||
|
||
Event objects are microkernel synchronization objects that tasks can
|
||
signal and test. Fibers and interrupt service routines may signal
|
||
events but they cannot test or wait on them. Use event objects for
|
||
situations in which multiple signals come in but only one test is
|
||
needed to reset the event. Events do not count signals like a semaphore
|
||
does due to their binary behavior. An event needs only one signal to be
|
||
available and only needs to be tested once to become clear and
|
||
unavailable.
|
||
|
||
Function
|
||
========
|
||
|
||
Events were designed for interrupt service routines and nanokernel
|
||
fibers that need to wake up a waiting task. The event signal can be
|
||
passed to a task to trigger an event test to RC_OK. Events are the
|
||
easiest and most efficient way to wake up a task to synchronize
|
||
operations between the two levels.
|
||
|
||
A feature of events are the event handlers. Event handlers are attached
|
||
to events. They perform simple processing in the nanokernel before a
|
||
context switch is made to a blocked task. This way, signals can be
|
||
interpreted before the system requires to reschedule a fiber or task.
|
||
|
||
Only one task may wait for an event. If a second task tests the same
|
||
event the call returns a fail. Use semaphores for multiple tasks to
|
||
wait on a signal from them.
|
||
|
||
Initialization
|
||
==============
|
||
|
||
|
||
An event has to be defined in the project file, :file:`projName.vpf`.
|
||
Specify the name of the event, the name of the processor node that
|
||
manages it, and its event-handler function. Use the following syntax:
|
||
|
||
.. code-block:: console
|
||
|
||
EVENT name handler
|
||
|
||
.. note::
|
||
|
||
In the project file, you can specify the name of the event and the
|
||
event handler, but not the event's number.
|
||
|
||
Define application events in the project’s VPF file. Define the driver’s
|
||
events in either the project’s VPF file or a BSP-specific VPF file.
|
||
|
||
Application Program Interfaces
|
||
==============================
|
||
|
||
Event APIs allow signaling or testing an event (blocking or
|
||
non-blocking), and setting the event handler.
|
||
|
||
If the event is in a signaled state, the test function returns
|
||
successfully and resets the event to the non-signaled state. If the
|
||
event is not signaled at the time of the call, the test either reports
|
||
failure immediately in case of a non-blocking call, or blocks the
|
||
calling task into a until the event signal becomes available.
|
||
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| **Call** | **Description** |
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| :c:func:`fiber_event_send()` | Signal an event from a fiber. |
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| :c:func:`task_event_set_handler()` | Installs or removes an event handler function from a task. |
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| :c:func:`task_event_send()` | Signal an event from a task. |
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| :c:func:`task_event_recv()` | Waits for an event signal. |
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| :c:func:`task_event_recv_wait()` | Waits for an event signal with a delay. |
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| :c:func:`task_event_recv_wait_timeout()` | Waits for an event signal with a delay and a timeout. |
|
||
+------------------------------------------+------------------------------------------------------------+
|
||
| :c:func:`isr_event_send()` | Signal an event from an ISR |
|
||
+------------------------------------------+------------------------------------------------------------+
|