DOC: Split the microkernel object document into a file per object type.
Split the contents of microkernel.rst into several files. Each file contains only the information of a specific object type. Labels have been added to accomodate cross-references to each object type. Changed the tables that did not comply with a 100 character line length. Change-Id: I983bc76a89b1cf01442de53737de4f76a5262264 Signed-off-by: Rodrigo Caballero <rodrigo.caballero.abraham@intel.com>
This commit is contained in:
parent
3fddad2eda
commit
ccea9d3581
9 changed files with 1015 additions and 975 deletions
|
@ -1,4 +1,4 @@
|
|||
.. _microkernelObjects:
|
||||
.. _microkernel_objects:
|
||||
|
||||
Microkernel Objects
|
||||
###################
|
||||
|
@ -12,977 +12,19 @@ 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
|
||||
==========
|
||||
|
||||
The 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 MDEF 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.mdef`. 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 MDEF file to define a FIFO:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
FIFO %name %depthNumEntries %widthBytes [ bufSegLocation ]
|
||||
|
||||
An example of a FIFO entry for use in the MDEF 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.mdef`. 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 MDEF file to
|
||||
define a pipe:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
PIPE %name %buffersize [%bufferSegment]
|
||||
|
||||
An example of a pipe entry for use in the MDEF 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()` | Get data off a pipe. |
|
||||
+----------------------------------------+----------------------------------------+
|
||||
| :c:func:`task_pipe_get_wait()` | Get data off a pipe with a delay. |
|
||||
+----------------------------------------+----------------------------------------+
|
||||
| :c:func:`task_pipe_get_wait_timeout()` | Get data off a pipe with a timed delay.|
|
||||
+----------------------------------------+----------------------------------------+
|
||||
| :c:func:`task_pipe_put_async()` | Put data on a pipe asynchronously. |
|
||||
+----------------------------------------+----------------------------------------+
|
||||
|
||||
Mailbox Objects
|
||||
***************
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
A mailbox object is defined in include :file:`/microkernel/mailbox.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.mdef`, which will specify the object type, and the name
|
||||
of the mailbox. Use the following syntax in the MDEF file to define a
|
||||
Mailbox:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MAILBOX %name
|
||||
|
||||
An example of a mailbox entry for use in the MDEF 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_semaphore.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.mdef`, which will specify the object type, and the name
|
||||
of the semaphore. Use the following syntax in the MDEF file to define a
|
||||
semaphore::
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
SEMA %name %node
|
||||
|
||||
An example of a semaphore entry for use in the MDEF 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.mdef`.
|
||||
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 MDEF file. Define the driver’s
|
||||
events in either the project’s MDEF file or a BSP-specific MDEF 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 |
|
||||
+------------------------------------------+------------------------------------------------------------+
|
||||
|
||||
|
||||
MUTEXES
|
||||
*******
|
||||
|
||||
|
||||
This microkernel object is organized with the following sections:
|
||||
|
||||
* Concepts: what the object is and its characteristics
|
||||
|
||||
* Purpose: why you would use the object
|
||||
|
||||
* Usage: how (when and where) you use the object and examples
|
||||
|
||||
* APIs: list of object-related APIs
|
||||
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
The microkernel's mutex objects provide reentrant mutex
|
||||
capabilities with priority inheritance.
|
||||
|
||||
Each mutex allows multiple tasks to safely share an associated
|
||||
resource by ensuring mutual exclusivity while the resource is
|
||||
being accessed by a task.
|
||||
|
||||
Any number of mutexes can be defined in a microkernel system.
|
||||
Each mutex has a name that uniquely identifies it. Typically,
|
||||
the name should relate to the resource being shared, but this is
|
||||
not a requirement.
|
||||
|
||||
A task that needs to use a shared resource must first gain
|
||||
exclusive access by locking the associated mutex. When the mutex
|
||||
is already locked by another task, the requesting task may
|
||||
choose to wait for the mutex to be unlocked. After obtaining the lock,
|
||||
a task can safely use the shared resource for as long as needed.
|
||||
When the task no longer needs the resource, it must unlock the
|
||||
associated mutex to allow other tasks to use the resource.
|
||||
|
||||
Any number of tasks may wait on a locked mutex simultaneously.
|
||||
When there is more than one waiting task, the mutex locks the
|
||||
resource for the highest priority task that has waited the longest
|
||||
first.
|
||||
|
||||
Priority inheritance occurs whenever a high priority task waits
|
||||
on a mutex that is locked by a lower priority task. The priority
|
||||
of the lower priority task increases temporarily to the priority
|
||||
of the highest priority task that is waiting on a mutex held by
|
||||
the lower priority task. This allows the lower priority
|
||||
task to complete its work and unlock the mutex as quickly as
|
||||
possible. Once the mutex has been unlocked, the lower priority task
|
||||
sets its task priority to that of the highest priority task
|
||||
that is waiting on a mutex it holds. When there is no higher
|
||||
priority task waiting, the lower priority task sets its task priority
|
||||
to the task’s original priority.
|
||||
|
||||
.. note::
|
||||
|
||||
The priority of an executing task, locked by a mutex can
|
||||
be elevated repeatedly as more higher priority tasks wait on the
|
||||
mutex(es). Conversely, the priority of the task repeatedly lowers
|
||||
as mutex(es) release.
|
||||
|
||||
The microkernel also allows a task to repeatedly lock a mutex it
|
||||
already locked. This ensures that the task can access the resource
|
||||
at a point in its execution when the resource may or may not
|
||||
already be locked. A mutex that is repeatedly locked must be unlocked
|
||||
an equal number of times before the mutex releases the resource
|
||||
completely.
|
||||
|
||||
|
||||
Purpose
|
||||
=======
|
||||
Use mutexes to provide exclusive access to a resource,
|
||||
such as a physical device.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Defining a Mutex
|
||||
----------------
|
||||
|
||||
Add an entry for the mutex in the project file using the
|
||||
following syntax:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MUTEX %name
|
||||
|
||||
For example, the file :file:`projName.mdef` defines a single mutex as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% MUTEX NAME
|
||||
% ===============
|
||||
MUTEX DEVICE_X
|
||||
|
||||
|
||||
|
||||
Example: Locking a Mutex with No Conditions
|
||||
-------------------------------------------
|
||||
This code waits indefinitely for the mutex to become available if the
|
||||
mutex is in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
task_mutex_lock_wait(XYZ);
|
||||
moveto(100,100);
|
||||
lineto(200,100);
|
||||
task_mutex_unlock(XYZ);
|
||||
|
||||
|
||||
Example: Locking a Mutex with a Conditional Timeout
|
||||
---------------------------------------------------
|
||||
This code waits for a mutex to become available for a specified
|
||||
time, and gives a warning if the mutex does not become available
|
||||
in the specified amount of time.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (task_mutex_lock_wait_timeout(XYZ, 100) == RC_OK)
|
||||
{
|
||||
moveto(100,100);
|
||||
lineto(200,100);
|
||||
task_mutex_unlock(XYZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Cannot lock XYZ display\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Example: Locking a Mutex with a No Blocking Condition
|
||||
-----------------------------------------------------
|
||||
This code gives an immediate warning when a mutex is in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (task_mutex_lock(XYZ) == RC_OK);
|
||||
{
|
||||
do_something();
|
||||
task_mutex_unlock(XYZ); /* and unlock mutex*/
|
||||
}
|
||||
else
|
||||
{
|
||||
display_warning(); /* and do not unlock mutex*/
|
||||
}
|
||||
|
||||
|
||||
APIs
|
||||
====
|
||||
|
||||
The following Mutex APIs are provided by :file:`microkernel.h`.
|
||||
|
||||
+------------------------------------------+-----------------------------------+
|
||||
| Call | Description |
|
||||
+==========================================+===================================+
|
||||
| :c:func:`task_mutex_lock()` | Locks a mutex, and increments |
|
||||
| | the lock count. |
|
||||
+------------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mutex_lock_wait()` | Waits on a locked mutex until it |
|
||||
| | is unlocked, then locks the mutex |
|
||||
| | and increments the lock count. |
|
||||
+------------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mutex_lock_wait_timeout()` | Waits on a locked mutex for the |
|
||||
| | period of time defined by the |
|
||||
| | timeout parameter. If the mutex |
|
||||
| | becomes available during that |
|
||||
| | period, the function locks the |
|
||||
| | mutex, and increments the lock |
|
||||
| | count. If the timeout expires, |
|
||||
| | it returns RC_TIME. |
|
||||
+------------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mutex_unlock()` | Decrements a mutex lock count, |
|
||||
| | and unlocks the mutex when the |
|
||||
| | count reaches zero. |
|
||||
+------------------------------------------+-----------------------------------+
|
||||
|
||||
|
||||
|
||||
MEMORY MAPS
|
||||
***********
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
The microkernel's memory map objects provide dynamic allocation and
|
||||
release of fixed-size memory blocks.
|
||||
|
||||
Any number of memory maps can be defined in a microkernel system.
|
||||
Each memory map has a name that uniquely identifies it.
|
||||
In addition, a memory map defines the number of blocks it contains
|
||||
and the size of each block in bytes.
|
||||
The number of blocks and block size values cannot be zero.
|
||||
The block size must be a multiple of the word size on most processors.
|
||||
|
||||
A task that needs to use a memory block simply allocates it from
|
||||
a memory map. When all the blocks are currently in use, the task may
|
||||
choose to wait for one to become available. When the task is finished
|
||||
with a memory block, it must release the block back to the memory map
|
||||
that allocated it so that the block can be reused.
|
||||
|
||||
Any number of tasks may wait on an empty memory map simultaneously;
|
||||
when a memory block becomes available it is given to the
|
||||
highest priority task that has waited the longest.
|
||||
|
||||
The microkernel manages memory blocks in an efficient and deterministic
|
||||
manner that eliminates the risk of memory fragmentation problems
|
||||
which can arise when using variable-size blocks.
|
||||
|
||||
Unlike a heap, more than one memory map can be defined, if needed. This
|
||||
allows for a memory map with smaller blocks and others with larger-sized
|
||||
blocks. (Alternatively, a memory pool object may be used.)
|
||||
|
||||
|
||||
Purpose
|
||||
=======
|
||||
|
||||
Use a memory map to allocate and free memory in fixed-size blocks.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Defining a Memory Map
|
||||
---------------------
|
||||
|
||||
Add an entry for one or more memory maps in the project file using the
|
||||
following syntax:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MAP %name %numBlocks %blockSize
|
||||
|
||||
For example, the file :file:`projName.mdef` defines a single memory map
|
||||
as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% MAP NAME NUMBLOCKS BLOCKSIZE
|
||||
% ======================================
|
||||
MAP MYMAP 4 1024
|
||||
MAP YOURMAP 6 200
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Map with No Conditions
|
||||
----------------------------------------------------------------
|
||||
This code waits indefinitely for a memory block to become
|
||||
available if all the memory blocks are in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
task_mem_map_alloc_wait(MYMAP, &block_ptr);
|
||||
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Map with a Conditional Time-out
|
||||
-------------------------------------------------------------------------
|
||||
This code waits a specified amount of time for a memory block to become
|
||||
available and gives a warning if the memory block does not become available
|
||||
in the specified time.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
if (task_mem_map_alloc_wait_timeout(MYMAP, &block_ptr, 5) == RC_OK)) {
|
||||
/* utilize memory block */
|
||||
} else {
|
||||
printf("Memory allocation time-out");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Map with a No Blocking Condition
|
||||
--------------------------------------------------------------------------
|
||||
This code gives an immediate warning when all memory blocks are in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
if (task_mem_map_alloc(MYMAP, &block_ptr) == RC_OK) {
|
||||
/* utilize memory block */
|
||||
} else {
|
||||
display_warning(); /* and do not allocate memory block*/
|
||||
}
|
||||
|
||||
|
||||
Example: Freeing a Memory Block back to a Map
|
||||
---------------------------------------------
|
||||
This code releases a memory block back when it is no longer needed.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
task_mem_map_alloc_wait(MYMAP, &block_ptr);
|
||||
/* use memory block */
|
||||
task_mem_map_free(&block_ptr);
|
||||
|
||||
|
||||
|
||||
APIs
|
||||
====
|
||||
|
||||
The following Memory Map APIs are provided by :file:`microkernel.h`.
|
||||
|
||||
+---------------------------------------------+-----------------------------------+
|
||||
| Call | Description |
|
||||
+=============================================+===================================+
|
||||
| :c:func:`task_mem_map_alloc()` | Requests a block from a memory |
|
||||
| | map. |
|
||||
+---------------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_alloc_wait()` | Waits on a block of memory until |
|
||||
| | it is available. |
|
||||
+---------------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_alloc_wait_timeout()` | Waits on a block of memory for |
|
||||
| | the period of time defined by the |
|
||||
| | time-out parameter. |
|
||||
+---------------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_free()` | Returns a block to a memory map. |
|
||||
+---------------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_used_get()` | Returns the number of used blocks |
|
||||
| | in a memory map. |
|
||||
+---------------------------------------------+-----------------------------------+
|
||||
|
||||
MEMORY POOLS
|
||||
************
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
The microkernel's memory pool objects provide dynamic allocation and
|
||||
release of variable-size memory blocks.
|
||||
|
||||
Unlike a memory map, which only supports memory blocks of a single size,
|
||||
a memory pool has the ability to support multiple memory block sizes.
|
||||
It does this by subdividing blocks into smaller chunks whenever possible
|
||||
to more closely match the actual needs of the requesting task.
|
||||
|
||||
Any number of memory pools can be defined in a microkernel system.
|
||||
Each memory pool has a name that uniquely identifies it.
|
||||
In addition, a memory pool defines minimum and maximum memory block sizes
|
||||
(in bytes) and the number of maximum size blocks that the memory pool
|
||||
contains.
|
||||
|
||||
A task that needs to use a memory block simply allocates it from a
|
||||
memory pool. If a block of the desired size is unavailable, the task
|
||||
may choose to wait for one to become available. Following a successful
|
||||
allocation the :c:data:`pointer_to_data` field of the block descriptor
|
||||
supplied by the task indicates the starting address of the memory block.
|
||||
When the task is finished with a memory block, it must release the block
|
||||
back to the memory pool that allocated it so that the block can be
|
||||
reused.
|
||||
|
||||
Any number of tasks may wait on a memory pool simultaneously;
|
||||
when a memory block becomes available it is given to the highest
|
||||
priority task that has waited the longest.
|
||||
|
||||
When a request for memory is sufficiently smaller than an available
|
||||
memory pool block, the memory pool will automatically split the block
|
||||
block into 4 smaller blocks. The resulting smaller
|
||||
blocks can also be split repeatedly, until a block just larger
|
||||
than the needed size is available, or the minimum block size
|
||||
(as specified in the MDEF file) is reached.
|
||||
If the memory pool is unable to find an available block
|
||||
that is at least the requested size, it will attempt to create
|
||||
one by merging adjacent free blocks; if it is unable to create
|
||||
a suitable block the request fails.
|
||||
|
||||
Although a memory pool uses efficient algorithms to manage its
|
||||
blocks, splitting available blocks and merging free blocks
|
||||
takes time and increases the overhead involved in allocating
|
||||
a block. The larger the allowable number of splits, the larger
|
||||
the overhead. The minimum and maximum block size parameters
|
||||
specified for a pool can be used to control the amount of
|
||||
splitting, and thus the amount of overhead.
|
||||
|
||||
Unlike a heap, more than one memory pool can be defined, if
|
||||
needed. For example, different applications can utilize
|
||||
different memory pools so that one application does not
|
||||
allocate all of the available blocks.
|
||||
|
||||
|
||||
Purpose
|
||||
=======
|
||||
Use memory pools to allocate memory in variable-size blocks.
|
||||
|
||||
Use memory pool blocks when sending data to a mailbox
|
||||
asynchronously.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Defining a Memory Pool
|
||||
----------------------
|
||||
|
||||
The following parameters must be defined:
|
||||
|
||||
*name*
|
||||
This specifies a unique name for the memory pool.
|
||||
|
||||
*minBlockSize*
|
||||
This specifies the minimimum memory block size in bytes.
|
||||
It should be a multiple of the processor's word size.
|
||||
|
||||
*maxBlockSize*
|
||||
This specifies the maximum memory block size in bytes.
|
||||
It should be a power of 4 times larger than *minBlockSize*;
|
||||
therefore, maxBlockSize = minBlockSize * 4^n, where n>=0.
|
||||
|
||||
*numMax*
|
||||
This specifies the number of maximum size memory blocks
|
||||
available at startup.
|
||||
|
||||
|
||||
Add an entry for memory pools in the project .MDEF file using the
|
||||
following syntax:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
POOL %name %minBlockSize %maxBlockSize %numMax
|
||||
|
||||
For example, the file :file:`projName.mdef` defines two memory pools
|
||||
as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% POOL NAME MIN MAX NMAX
|
||||
% =======================================
|
||||
POOL MY_POOL 32 8192 1
|
||||
POOL SECOND_POOL_ID 64 1024 5
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Pool with No Conditions
|
||||
-----------------------------------------------------------------
|
||||
|
||||
This code waits indefinitely for an 80 byte memory block to become
|
||||
available, then fills it with zeroes.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
task_mem_pool_alloc_wait(&block, MYPOOL, 80);
|
||||
|
||||
memset(block.pointer_to_data, 0, 80);
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Pool with a Conditional Time-out
|
||||
--------------------------------------------------------------------------
|
||||
This code waits up to 5 ticks for an 80 byte memory block to become
|
||||
available and gives a warning if a suitable memory block is not obtained
|
||||
in that time.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
if (task_mem_pool_alloc_wait_timeout(&block, MYPOOL, 80, 5) == RC_OK) {
|
||||
/* use memory block */
|
||||
} else {
|
||||
printf('Memory allocation timeout');
|
||||
}
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Pool with a No Blocking Condition
|
||||
---------------------------------------------------------------------------
|
||||
This code gives an immediate warning when it can not satisfy the request for
|
||||
a memory block of 80 bytes.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
if (task_mem_pool_alloc (&block, MYPOOL, 80) == RC_OK) {
|
||||
/* use memory block */
|
||||
} else {
|
||||
printf('Memory allocation timeout');
|
||||
}
|
||||
|
||||
|
||||
Example: Freeing a Memory Block Back to a Pool
|
||||
----------------------------------------------
|
||||
This code releases a memory block back to a pool when it is no longer needed.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
task_mem_pool_alloc(&block, MYPOOL, size);
|
||||
/* use memory block */
|
||||
task_mem_pool_free(&block);
|
||||
|
||||
|
||||
Example: Manually Defragmenting a Memory Pool
|
||||
---------------------------------------------
|
||||
This code instructs the memory pool to concatenate any unused memory blocks
|
||||
that can be merged. Doing a full defragmentation of the entire memory pool
|
||||
before allocating a number of memory blocks may be more efficient
|
||||
than having to do an implicit partial defragmentation of the memory pool
|
||||
each time a memory block allocation occurs.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
task_mem_pool_defragment(MYPOOL);
|
||||
|
||||
APIs
|
||||
====
|
||||
|
||||
The following Memory Pools APIs are provided by microkernel.h.
|
||||
|
||||
+----------------------------------------------+------------------------------+
|
||||
| Call | Description |
|
||||
+==============================================+==============================+
|
||||
| :c:func:`task_mem_pool_alloc()` | Allocates a block from |
|
||||
| | a memory pool. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_alloc_wait()` | Waits for a block of memory |
|
||||
| | until it is available. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_alloc_wait_timeout()` | Waits for a block of memory |
|
||||
| | for the time period defined |
|
||||
| | by the time-out parameter. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_free()` | Returns a block of memory |
|
||||
| | to a memory pool. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_defragment()` | Defragments a memory pool. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
regarding each object's functionality.
|
||||
|
||||
Objects Documentation
|
||||
*********************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
microkernel_events
|
||||
microkernel_fifos
|
||||
microkernel_mailboxes
|
||||
microkernel_memory_maps
|
||||
microkernel_memory_pools
|
||||
microkernel_mutexes
|
||||
microkernel_pipes
|
||||
microkernel_semaphores
|
87
doc/object/microkernel_events.rst
Normal file
87
doc/object/microkernel_events.rst
Normal file
|
@ -0,0 +1,87 @@
|
|||
.. _events:
|
||||
|
||||
Events
|
||||
******
|
||||
|
||||
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.mdef`.
|
||||
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 MDEF file. Define the driver’s
|
||||
events in either the project’s MDEF file or a BSP-specific MDEF 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 |
|
||||
+---------------------------------------+-----------------------------------+
|
101
doc/object/microkernel_fifos.rst
Normal file
101
doc/object/microkernel_fifos.rst
Normal file
|
@ -0,0 +1,101 @@
|
|||
.. _microkernel_fifos:
|
||||
|
||||
Microkernel FIFOs
|
||||
*****************
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
The FIFO 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 MDEF 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.mdef`. 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 MDEF file to define a FIFO:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
FIFO %name %depthNumEntries %widthBytes [ bufSegLocation ]
|
||||
|
||||
An example of a FIFO entry for use in the MDEF 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. |
|
||||
+---------------------------------------+-----------------------------------+
|
104
doc/object/microkernel_mailboxes.rst
Normal file
104
doc/object/microkernel_mailboxes.rst
Normal file
|
@ -0,0 +1,104 @@
|
|||
.. _mailboxes:
|
||||
|
||||
Mailboxes
|
||||
*********
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
A mailbox is defined in include :file:`/microkernel/mailbox.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.mdef`, which will specify the object type, and the name
|
||||
of the mailbox. Use the following syntax in the MDEF file to define a
|
||||
Mailbox:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MAILBOX %name
|
||||
|
||||
An example of a mailbox entry for use in the MDEF 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 |
|
||||
| | 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. |
|
||||
+---------------------------------------+-----------------------------------+
|
151
doc/object/microkernel_memory_maps.rst
Normal file
151
doc/object/microkernel_memory_maps.rst
Normal file
|
@ -0,0 +1,151 @@
|
|||
.. _memory_maps:
|
||||
|
||||
MEMORY MAPS
|
||||
***********
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
The microkernel's memory map objects provide dynamic allocation and
|
||||
release of fixed-size memory blocks.
|
||||
|
||||
Any number of memory maps can be defined in a microkernel system.
|
||||
Each memory map has a name that uniquely identifies it.
|
||||
In addition, a memory map defines the number of blocks it contains
|
||||
and the size of each block in bytes.
|
||||
The number of blocks and block size values cannot be zero.
|
||||
The block size must be a multiple of the word size on most processors.
|
||||
|
||||
A task that needs to use a memory block simply allocates it from
|
||||
a memory map. When all the blocks are currently in use, the task may
|
||||
choose to wait for one to become available. When the task is finished
|
||||
with a memory block, it must release the block back to the memory map
|
||||
that allocated it so that the block can be reused.
|
||||
|
||||
Any number of tasks may wait on an empty memory map simultaneously;
|
||||
when a memory block becomes available it is given to the
|
||||
highest priority task that has waited the longest.
|
||||
|
||||
The microkernel manages memory blocks in an efficient and deterministic
|
||||
manner that eliminates the risk of memory fragmentation problems
|
||||
which can arise when using variable-size blocks.
|
||||
|
||||
Unlike a heap, more than one memory map can be defined, if needed. This
|
||||
allows for a memory map with smaller blocks and others with larger-sized
|
||||
blocks. (Alternatively, a memory pool object may be used.)
|
||||
|
||||
|
||||
Purpose
|
||||
=======
|
||||
|
||||
Use a memory map to allocate and free memory in fixed-size blocks.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Defining a Memory Map
|
||||
---------------------
|
||||
|
||||
Add an entry for one or more memory maps in the project file using the
|
||||
following syntax:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MAP %name %numBlocks %blockSize
|
||||
|
||||
For example, the file :file:`projName.mdef` defines a single memory map
|
||||
as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% MAP NAME NUMBLOCKS BLOCKSIZE
|
||||
% ======================================
|
||||
MAP MYMAP 4 1024
|
||||
MAP YOURMAP 6 200
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Map with No Conditions
|
||||
----------------------------------------------------------------
|
||||
This code waits indefinitely for a memory block to become
|
||||
available if all the memory blocks are in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
task_mem_map_alloc_wait(MYMAP, &block_ptr);
|
||||
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Map with a Conditional Time-out
|
||||
-------------------------------------------------------------------------
|
||||
This code waits a specified amount of time for a memory block to become
|
||||
available and gives a warning if the memory block does not become available
|
||||
in the specified time.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
if (task_mem_map_alloc_wait_timeout(MYMAP, &block_ptr, 5) == RC_OK)) {
|
||||
/* utilize memory block */
|
||||
} else {
|
||||
printf("Memory allocation time-out");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Map with a No Blocking Condition
|
||||
--------------------------------------------------------------------------
|
||||
This code gives an immediate warning when all memory blocks are in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
if (task_mem_map_alloc(MYMAP, &block_ptr) == RC_OK) {
|
||||
/* utilize memory block */
|
||||
} else {
|
||||
display_warning(); /* and do not allocate memory block*/
|
||||
}
|
||||
|
||||
|
||||
Example: Freeing a Memory Block back to a Map
|
||||
---------------------------------------------
|
||||
This code releases a memory block back when it is no longer needed.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *block_ptr;
|
||||
|
||||
task_mem_map_alloc_wait(MYMAP, &block_ptr);
|
||||
/* use memory block */
|
||||
task_mem_map_free(&block_ptr);
|
||||
|
||||
|
||||
|
||||
APIs
|
||||
====
|
||||
|
||||
The following Memory Map APIs are provided by :file:`microkernel.h`.
|
||||
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| Call | Description |
|
||||
+=======================================+===================================+
|
||||
| :c:func:`task_mem_map_alloc()` | Requests a block from a memory |
|
||||
| | map. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_alloc_wait()` | Waits on a block of memory until |
|
||||
| | it is available. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_alloc_wait_timeout()` | Waits on a block of memory |
|
||||
| | for the period of time |
|
||||
| | defined by the time-out |
|
||||
| | parameter. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_free()` | Returns a block to a memory map. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mem_map_used_get()` | Returns the number of used blocks |
|
||||
| | in a memory map. |
|
||||
+---------------------------------------+-----------------------------------+
|
207
doc/object/microkernel_memory_pools.rst
Normal file
207
doc/object/microkernel_memory_pools.rst
Normal file
|
@ -0,0 +1,207 @@
|
|||
.. _memory_pools:
|
||||
|
||||
MEMORY POOLS
|
||||
************
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
The microkernel's memory pool objects provide dynamic allocation and
|
||||
release of variable-size memory blocks.
|
||||
|
||||
Unlike a memory map, which only supports memory blocks of a single size,
|
||||
a memory pool has the ability to support multiple memory block sizes.
|
||||
It does this by subdividing blocks into smaller chunks whenever possible
|
||||
to more closely match the actual needs of the requesting task.
|
||||
|
||||
Any number of memory pools can be defined in a microkernel system.
|
||||
Each memory pool has a name that uniquely identifies it.
|
||||
In addition, a memory pool defines minimum and maximum memory block sizes
|
||||
(in bytes) and the number of maximum size blocks that the memory pool
|
||||
contains.
|
||||
|
||||
A task that needs to use a memory block simply allocates it from a
|
||||
memory pool. If a block of the desired size is unavailable, the task
|
||||
may choose to wait for one to become available. Following a successful
|
||||
allocation the :c:data:`pointer_to_data` field of the block descriptor
|
||||
supplied by the task indicates the starting address of the memory block.
|
||||
When the task is finished with a memory block, it must release the block
|
||||
back to the memory pool that allocated it so that the block can be
|
||||
reused.
|
||||
|
||||
Any number of tasks may wait on a memory pool simultaneously;
|
||||
when a memory block becomes available it is given to the highest
|
||||
priority task that has waited the longest.
|
||||
|
||||
When a request for memory is sufficiently smaller than an available
|
||||
memory pool block, the memory pool will automatically split the block
|
||||
block into 4 smaller blocks. The resulting smaller
|
||||
blocks can also be split repeatedly, until a block just larger
|
||||
than the needed size is available, or the minimum block size
|
||||
(as specified in the MDEF file) is reached.
|
||||
If the memory pool is unable to find an available block
|
||||
that is at least the requested size, it will attempt to create
|
||||
one by merging adjacent free blocks; if it is unable to create
|
||||
a suitable block the request fails.
|
||||
|
||||
Although a memory pool uses efficient algorithms to manage its
|
||||
blocks, splitting available blocks and merging free blocks
|
||||
takes time and increases the overhead involved in allocating
|
||||
a block. The larger the allowable number of splits, the larger
|
||||
the overhead. The minimum and maximum block size parameters
|
||||
specified for a pool can be used to control the amount of
|
||||
splitting, and thus the amount of overhead.
|
||||
|
||||
Unlike a heap, more than one memory pool can be defined, if
|
||||
needed. For example, different applications can utilize
|
||||
different memory pools so that one application does not
|
||||
allocate all of the available blocks.
|
||||
|
||||
|
||||
Purpose
|
||||
=======
|
||||
Use memory pools to allocate memory in variable-size blocks.
|
||||
|
||||
Use memory pool blocks when sending data to a mailbox
|
||||
asynchronously.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Defining a Memory Pool
|
||||
----------------------
|
||||
|
||||
The following parameters must be defined:
|
||||
|
||||
*name*
|
||||
This specifies a unique name for the memory pool.
|
||||
|
||||
*minBlockSize*
|
||||
This specifies the minimimum memory block size in bytes.
|
||||
It should be a multiple of the processor's word size.
|
||||
|
||||
*maxBlockSize*
|
||||
This specifies the maximum memory block size in bytes.
|
||||
It should be a power of 4 times larger than *minBlockSize*;
|
||||
therefore, maxBlockSize = minBlockSize * 4^n, where n>=0.
|
||||
|
||||
*numMax*
|
||||
This specifies the number of maximum size memory blocks
|
||||
available at startup.
|
||||
|
||||
|
||||
Add an entry for memory pools in the project .MDEF file using the
|
||||
following syntax:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
POOL %name %minBlockSize %maxBlockSize %numMax
|
||||
|
||||
For example, the file :file:`projName.mdef` defines two memory pools
|
||||
as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% POOL NAME MIN MAX NMAX
|
||||
% =======================================
|
||||
POOL MY_POOL 32 8192 1
|
||||
POOL SECOND_POOL_ID 64 1024 5
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Pool with No Conditions
|
||||
-----------------------------------------------------------------
|
||||
|
||||
This code waits indefinitely for an 80 byte memory block to become
|
||||
available, then fills it with zeroes.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
task_mem_pool_alloc_wait(&block, MYPOOL, 80);
|
||||
|
||||
memset(block.pointer_to_data, 0, 80);
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Pool with a Conditional Time-out
|
||||
--------------------------------------------------------------------------
|
||||
This code waits up to 5 ticks for an 80 byte memory block to become
|
||||
available and gives a warning if a suitable memory block is not obtained
|
||||
in that time.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
if (task_mem_pool_alloc_wait_timeout(&block, MYPOOL, 80, 5) == RC_OK) {
|
||||
/* use memory block */
|
||||
} else {
|
||||
printf('Memory allocation timeout');
|
||||
}
|
||||
|
||||
|
||||
Example: Requesting a Memory Block from a Pool with a No Blocking Condition
|
||||
---------------------------------------------------------------------------
|
||||
This code gives an immediate warning when it can not satisfy the request for
|
||||
a memory block of 80 bytes.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
if (task_mem_pool_alloc (&block, MYPOOL, 80) == RC_OK) {
|
||||
/* use memory block */
|
||||
} else {
|
||||
printf('Memory allocation timeout');
|
||||
}
|
||||
|
||||
|
||||
Example: Freeing a Memory Block Back to a Pool
|
||||
----------------------------------------------
|
||||
This code releases a memory block back to a pool when it is no longer needed.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct k_block block;
|
||||
|
||||
task_mem_pool_alloc(&block, MYPOOL, size);
|
||||
/* use memory block */
|
||||
task_mem_pool_free(&block);
|
||||
|
||||
|
||||
Example: Manually Defragmenting a Memory Pool
|
||||
---------------------------------------------
|
||||
This code instructs the memory pool to concatenate any unused memory blocks
|
||||
that can be merged. Doing a full defragmentation of the entire memory pool
|
||||
before allocating a number of memory blocks may be more efficient
|
||||
than having to do an implicit partial defragmentation of the memory pool
|
||||
each time a memory block allocation occurs.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
task_mem_pool_defragment(MYPOOL);
|
||||
|
||||
APIs
|
||||
====
|
||||
|
||||
The following Memory Pools APIs are provided by microkernel.h.
|
||||
|
||||
+----------------------------------------------+------------------------------+
|
||||
| Call | Description |
|
||||
+==============================================+==============================+
|
||||
| :c:func:`task_mem_pool_alloc()` | Allocates a block from |
|
||||
| | a memory pool. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_alloc_wait()` | Waits for a block of memory |
|
||||
| | until it is available. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_alloc_wait_timeout()` | Waits for a block of memory |
|
||||
| | for the time period defined |
|
||||
| | by the time-out parameter. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_free()` | Returns a block of memory |
|
||||
| | to a memory pool. |
|
||||
+----------------------------------------------+------------------------------+
|
||||
| :c:func:`task_mem_pool_defragment()` | Defragments a memory pool. |
|
||||
+----------------------------------------------+------------------------------+
|
181
doc/object/microkernel_mutexes.rst
Normal file
181
doc/object/microkernel_mutexes.rst
Normal file
|
@ -0,0 +1,181 @@
|
|||
.. _mutexes:
|
||||
|
||||
MUTEXES
|
||||
*******
|
||||
|
||||
|
||||
This microkernel object is organized with the following sections:
|
||||
|
||||
* Concepts: what the object is and its characteristics
|
||||
|
||||
* Purpose: why you would use the object
|
||||
|
||||
* Usage: how (when and where) you use the object and examples
|
||||
|
||||
* APIs: list of object-related APIs
|
||||
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
The microkernel's mutex objects provide reentrant mutex
|
||||
capabilities with priority inheritance.
|
||||
|
||||
Each mutex allows multiple tasks to safely share an associated
|
||||
resource by ensuring mutual exclusivity while the resource is
|
||||
being accessed by a task.
|
||||
|
||||
Any number of mutexes can be defined in a microkernel system.
|
||||
Each mutex has a name that uniquely identifies it. Typically,
|
||||
the name should relate to the resource being shared, but this is
|
||||
not a requirement.
|
||||
|
||||
A task that needs to use a shared resource must first gain
|
||||
exclusive access by locking the associated mutex. When the mutex
|
||||
is already locked by another task, the requesting task may
|
||||
choose to wait for the mutex to be unlocked. After obtaining the lock,
|
||||
a task can safely use the shared resource for as long as needed.
|
||||
When the task no longer needs the resource, it must unlock the
|
||||
associated mutex to allow other tasks to use the resource.
|
||||
|
||||
Any number of tasks may wait on a locked mutex simultaneously.
|
||||
When there is more than one waiting task, the mutex locks the
|
||||
resource for the highest priority task that has waited the longest
|
||||
first.
|
||||
|
||||
Priority inheritance occurs whenever a high priority task waits
|
||||
on a mutex that is locked by a lower priority task. The priority
|
||||
of the lower priority task increases temporarily to the priority
|
||||
of the highest priority task that is waiting on a mutex held by
|
||||
the lower priority task. This allows the lower priority
|
||||
task to complete its work and unlock the mutex as quickly as
|
||||
possible. Once the mutex has been unlocked, the lower priority task
|
||||
sets its task priority to that of the highest priority task
|
||||
that is waiting on a mutex it holds. When there is no higher
|
||||
priority task waiting, the lower priority task sets its task priority
|
||||
to the task’s original priority.
|
||||
|
||||
.. note::
|
||||
|
||||
The priority of an executing task, locked by a mutex can
|
||||
be elevated repeatedly as more higher priority tasks wait on the
|
||||
mutex(es). Conversely, the priority of the task repeatedly lowers
|
||||
as mutex(es) release.
|
||||
|
||||
The microkernel also allows a task to repeatedly lock a mutex it
|
||||
already locked. This ensures that the task can access the resource
|
||||
at a point in its execution when the resource may or may not
|
||||
already be locked. A mutex that is repeatedly locked must be unlocked
|
||||
an equal number of times before the mutex releases the resource
|
||||
completely.
|
||||
|
||||
|
||||
Purpose
|
||||
=======
|
||||
Use mutexes to provide exclusive access to a resource,
|
||||
such as a physical device.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Defining a Mutex
|
||||
----------------
|
||||
|
||||
Add an entry for the mutex in the project file using the
|
||||
following syntax:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MUTEX %name
|
||||
|
||||
For example, the file :file:`projName.mdef` defines a single mutex as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% MUTEX NAME
|
||||
% ===============
|
||||
MUTEX DEVICE_X
|
||||
|
||||
|
||||
|
||||
Example: Locking a Mutex with No Conditions
|
||||
-------------------------------------------
|
||||
This code waits indefinitely for the mutex to become available if the
|
||||
mutex is in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
task_mutex_lock_wait(XYZ);
|
||||
moveto(100,100);
|
||||
lineto(200,100);
|
||||
task_mutex_unlock(XYZ);
|
||||
|
||||
|
||||
Example: Locking a Mutex with a Conditional Timeout
|
||||
---------------------------------------------------
|
||||
This code waits for a mutex to become available for a specified
|
||||
time, and gives a warning if the mutex does not become available
|
||||
in the specified amount of time.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (task_mutex_lock_wait_timeout(XYZ, 100) == RC_OK)
|
||||
{
|
||||
moveto(100,100);
|
||||
lineto(200,100);
|
||||
task_mutex_unlock(XYZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Cannot lock XYZ display\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Example: Locking a Mutex with a No Blocking Condition
|
||||
-----------------------------------------------------
|
||||
This code gives an immediate warning when a mutex is in use.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (task_mutex_lock(XYZ) == RC_OK);
|
||||
{
|
||||
do_something();
|
||||
task_mutex_unlock(XYZ); /* and unlock mutex*/
|
||||
}
|
||||
else
|
||||
{
|
||||
display_warning(); /* and do not unlock mutex*/
|
||||
}
|
||||
|
||||
|
||||
APIs
|
||||
====
|
||||
|
||||
The following Mutex APIs are provided by :file:`microkernel.h`.
|
||||
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| Call | Description |
|
||||
+=======================================+===================================+
|
||||
| :c:func:`task_mutex_lock()` | Locks a mutex, and increments |
|
||||
| | the lock count. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mutex_lock_wait()` | Waits on a locked mutex until it |
|
||||
| | is unlocked, then locks the mutex |
|
||||
| | and increments the lock count. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mutex_lock_wait_timeout()` | Waits on a locked mutex for |
|
||||
| | the period of time defined by |
|
||||
| | the timeout parameter. If the |
|
||||
| | mutex becomes available during |
|
||||
| | that period, the function |
|
||||
| | locks the mutex, and |
|
||||
| | increments the lock count. |
|
||||
| | If the timeout expires, it |
|
||||
| | returns RC_TIME. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_mutex_unlock()` | Decrements a mutex lock count, |
|
||||
| | and unlocks the mutex when the |
|
||||
| | count reaches zero. |
|
||||
+---------------------------------------+-----------------------------------+
|
89
doc/object/microkernel_pipes.rst
Normal file
89
doc/object/microkernel_pipes.rst
Normal file
|
@ -0,0 +1,89 @@
|
|||
.. _pipes:
|
||||
|
||||
Pipes
|
||||
*****
|
||||
|
||||
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.mdef`. 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 MDEF file to
|
||||
define a pipe:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
PIPE %name %buffersize [%bufferSegment]
|
||||
|
||||
An example of a pipe entry for use in the MDEF 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()` | Get data off a pipe. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_pipe_get_wait()` | Get data off a pipe with a delay. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_pipe_get_wait_timeout()` | Get data off a pipe with a timed |
|
||||
| | delay. |
|
||||
+---------------------------------------+-----------------------------------+
|
||||
| :c:func:`task_pipe_put_async()` | Put data on a pipe asynchronously. |
|
||||
+---------------------------------------+-----------------------------------+
|
78
doc/object/microkernel_semaphores.rst
Normal file
78
doc/object/microkernel_semaphores.rst
Normal file
|
@ -0,0 +1,78 @@
|
|||
.. _microkernel_semaphores:
|
||||
|
||||
Semaphores
|
||||
**********
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
The microkernel semaphore is defined in
|
||||
:file:`kernel/microkernel/k_semaphore.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.mdef`, which will specify the object type, and the name
|
||||
of the semaphore. Use the following syntax in the MDEF file to define a
|
||||
semaphore::
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
SEMA %name %node
|
||||
|
||||
An example of a semaphore entry for use in the MDEF 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. |
|
||||
+---------------------------------------+-----------------------------------+
|
Loading…
Add table
Add a link
Reference in a new issue