c-user: Split up semaphore manager

This makes it easier to automatically generate parts of the manager
documentation in the future.

Update #3993.
This commit is contained in:
Sebastian Huber 2020-06-16 14:16:09 +02:00
parent bd8185a7dd
commit 16ee8cf45b
6 changed files with 329 additions and 310 deletions

View File

@ -35,7 +35,7 @@ RTEMS Classic API Guide (|version|).
clock_manager
timer_manager
rate_monotonic_manager
semaphore_manager
semaphore/index
barrier_manager
message_manager
event_manager

View File

@ -0,0 +1,180 @@
.. SPDX-License-Identifier: CC-BY-SA-4.0
.. Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
Background
==========
A semaphore can be viewed as a protected variable whose value can be modified
only with the ``rtems_semaphore_create``, ``rtems_semaphore_obtain``, and
``rtems_semaphore_release`` directives. RTEMS supports both binary and
counting semaphores. A binary semaphore is restricted to values of zero or one,
while a counting semaphore can assume any non-negative integer value.
A binary semaphore (not a simple binary semaphore) can be used to control
access to a single resource. In particular, it can be used to enforce mutual
exclusion for a critical section in user code (mutex). In this instance, the
semaphore would be created with an initial count of one to indicate that no
task is executing the critical section of code. Upon entry to the critical
section, a task must issue the ``rtems_semaphore_obtain`` directive to prevent
other tasks from entering the critical section. Upon exit from the critical
section, the task that obtained the binary semaphore must issue the
``rtems_semaphore_release`` directive to allow another task to execute the
critical section. A binary semaphore must be released by the task that
obtained it.
A counting semaphore can be used to control access to a pool of two or more
resources. For example, access to three printers could be administered by a
semaphore created with an initial count of three. When a task requires access
to one of the printers, it issues the ``rtems_semaphore_obtain`` directive to
obtain access to a printer. If a printer is not currently available, the task
can wait for a printer to become available or return immediately. When the
task has completed printing, it should issue the ``rtems_semaphore_release``
directive to allow other tasks access to the printer.
Task synchronization may be achieved by creating a semaphore with an initial
count of zero. One task waits for the arrival of another task by issuing a
``rtems_semaphore_obtain`` directive when it reaches a synchronization point.
The other task performs a corresponding ``rtems_semaphore_release`` operation
when it reaches its synchronization point, thus unblocking the pending task.
.. _Nested Resource Access:
Nested Resource Access
----------------------
Deadlock occurs when a task owning a binary semaphore attempts to acquire that
same semaphore and blocks as result. Since the semaphore is allocated to a
task, it cannot be deleted. Therefore, the task that currently holds the
semaphore and is also blocked waiting for that semaphore will never execute
again.
RTEMS addresses this problem by allowing the task holding the binary semaphore
to obtain the same binary semaphore multiple times in a nested manner. Each
``rtems_semaphore_obtain`` must be accompanied with a
``rtems_semaphore_release``. The semaphore will only be made available for
acquisition by other tasks when the outermost ``rtems_semaphore_obtain`` is
matched with a ``rtems_semaphore_release``.
Simple binary semaphores do not allow nested access and so can be used for task
synchronization.
.. _Priority Inheritance:
Priority Inheritance
--------------------
RTEMS supports :ref:`priority inheritance <PriorityInheritance>` for local,
binary semaphores that use the priority task wait queue blocking discipline.
In SMP configurations, the :ref:`OMIP` is used instead.
.. _Priority Ceiling:
Priority Ceiling
----------------
RTEMS supports :ref:`priority ceiling <PriorityCeiling>` for local, binary
semaphores that use the priority task wait queue blocking discipline.
.. _Multiprocessor Resource Sharing Protocol:
Multiprocessor Resource Sharing Protocol
----------------------------------------
RTEMS supports the :ref:`MrsP` for local, binary semaphores that use the
priority task wait queue blocking discipline. In uniprocessor configurations,
the :ref:`PriorityCeiling` is used instead.
.. _Building a Semaphore Attribute Set:
Building a Semaphore Attribute Set
----------------------------------
In general, an attribute set is built by a bitwise OR of the desired attribute
components. The following table lists the set of valid semaphore attributes:
.. list-table::
:class: rtems-table
* - ``RTEMS_FIFO``
- tasks wait by FIFO (default)
* - ``RTEMS_PRIORITY``
- tasks wait by priority
* - ``RTEMS_BINARY_SEMAPHORE``
- restrict values to 0 and 1
* - ``RTEMS_COUNTING_SEMAPHORE``
- no restriction on values (default)
* - ``RTEMS_SIMPLE_BINARY_SEMAPHORE``
- restrict values to 0 and 1, do not allow nested access, allow deletion of
locked semaphore.
* - ``RTEMS_NO_INHERIT_PRIORITY``
- do not use priority inheritance (default)
* - ``RTEMS_INHERIT_PRIORITY``
- use priority inheritance
* - ``RTEMS_NO_PRIORITY_CEILING``
- do not use priority ceiling (default)
* - ``RTEMS_PRIORITY_CEILING``
- use priority ceiling
* - ``RTEMS_NO_MULTIPROCESSOR_RESOURCE_SHARING``
- do not use Multiprocessor Resource Sharing Protocol (default)
* - ``RTEMS_MULTIPROCESSOR_RESOURCE_SHARING``
- use Multiprocessor Resource Sharing Protocol
* - ``RTEMS_LOCAL``
- local semaphore (default)
* - ``RTEMS_GLOBAL``
- global semaphore
Attribute values are specifically designed to be mutually exclusive, therefore
bitwise OR and addition operations are equivalent as long as each attribute
appears exactly once in the component list. An attribute listed as a default
is not required to appear in the attribute list, although it is a good
programming practice to specify default attributes. If all defaults are
desired, the attribute ``RTEMS_DEFAULT_ATTRIBUTES`` should be specified on this
call.
This example demonstrates the attribute_set parameter needed to create a local
semaphore with the task priority waiting queue discipline. The attribute_set
parameter passed to the ``rtems_semaphore_create`` directive could be either
``RTEMS_PRIORITY`` or ``RTEMS_LOCAL | RTEMS_PRIORITY``. The attribute_set
parameter can be set to ``RTEMS_PRIORITY`` because ``RTEMS_LOCAL`` is the
default for all created tasks. If a similar semaphore were to be known
globally, then the attribute_set parameter would be ``RTEMS_GLOBAL |
RTEMS_PRIORITY``.
Some combinatinos of these attributes are invalid. For example, priority
ordered blocking discipline must be applied to a binary semaphore in order to
use either the priority inheritance or priority ceiling functionality. The
following tree figure illustrates the valid combinations.
.. figure:: ../../images/c_user/semaphore_attributes.png
:width: 90%
:align: center
:alt: Semaphore Attributes
.. _Building a SEMAPHORE_OBTAIN Option Set:
Building a SEMAPHORE_OBTAIN Option Set
--------------------------------------
In general, an option is built by a bitwise OR of the desired option
components. The set of valid options for the ``rtems_semaphore_obtain``
directive are listed in the following table:
.. list-table::
:class: rtems-table
* - ``RTEMS_WAIT``
- task will wait for semaphore (default)
* - ``RTEMS_NO_WAIT``
- task should not wait
Option values are specifically designed to be mutually exclusive, therefore
bitwise OR and addition operations are equivalent as long as each attribute
appears exactly once in the component list. An option listed as a default is
not required to appear in the list, although it is a good programming practice
to specify default options. If all defaults are desired, the option
``RTEMS_DEFAULT_OPTIONS`` should be specified on this call.
This example demonstrates the option parameter needed to poll for a semaphore.
The option parameter passed to the ``rtems_semaphore_obtain`` directive should
be ``RTEMS_NO_WAIT``.

View File

@ -2,315 +2,6 @@
.. Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
.. index:: semaphores
.. index:: binary semaphores
.. index:: counting semaphores
.. index:: mutual exclusion
Semaphore Manager
*****************
Introduction
============
The semaphore manager utilizes standard Dijkstra
counting semaphores to provide synchronization and mutual
exclusion capabilities. The directives provided by the
semaphore manager are:
- rtems_semaphore_create_ - Create a semaphore
- rtems_semaphore_ident_ - Get ID of a semaphore
- rtems_semaphore_delete_ - Delete a semaphore
- rtems_semaphore_obtain_ - Acquire a semaphore
- rtems_semaphore_release_ - Release a semaphore
- rtems_semaphore_flush_ - Unblock all tasks waiting on a semaphore
- rtems_semaphore_set_priority_ - Set priority by scheduler for a semaphore
Background
==========
A semaphore can be viewed as a protected variable whose value can be modified
only with the ``rtems_semaphore_create``, ``rtems_semaphore_obtain``, and
``rtems_semaphore_release`` directives. RTEMS supports both binary and
counting semaphores. A binary semaphore is restricted to values of zero or one,
while a counting semaphore can assume any non-negative integer value.
A binary semaphore (not a simple binary semaphore) can be used to control
access to a single resource. In particular, it can be used to enforce mutual
exclusion for a critical section in user code (mutex). In this instance, the
semaphore would be created with an initial count of one to indicate that no
task is executing the critical section of code. Upon entry to the critical
section, a task must issue the ``rtems_semaphore_obtain`` directive to prevent
other tasks from entering the critical section. Upon exit from the critical
section, the task that obtained the binary semaphore must issue the
``rtems_semaphore_release`` directive to allow another task to execute the
critical section. A binary semaphore must be released by the task that
obtained it.
A counting semaphore can be used to control access to a pool of two or more
resources. For example, access to three printers could be administered by a
semaphore created with an initial count of three. When a task requires access
to one of the printers, it issues the ``rtems_semaphore_obtain`` directive to
obtain access to a printer. If a printer is not currently available, the task
can wait for a printer to become available or return immediately. When the
task has completed printing, it should issue the ``rtems_semaphore_release``
directive to allow other tasks access to the printer.
Task synchronization may be achieved by creating a semaphore with an initial
count of zero. One task waits for the arrival of another task by issuing a
``rtems_semaphore_obtain`` directive when it reaches a synchronization point.
The other task performs a corresponding ``rtems_semaphore_release`` operation
when it reaches its synchronization point, thus unblocking the pending task.
.. _Nested Resource Access:
Nested Resource Access
----------------------
Deadlock occurs when a task owning a binary semaphore attempts to acquire that
same semaphore and blocks as result. Since the semaphore is allocated to a
task, it cannot be deleted. Therefore, the task that currently holds the
semaphore and is also blocked waiting for that semaphore will never execute
again.
RTEMS addresses this problem by allowing the task holding the binary semaphore
to obtain the same binary semaphore multiple times in a nested manner. Each
``rtems_semaphore_obtain`` must be accompanied with a
``rtems_semaphore_release``. The semaphore will only be made available for
acquisition by other tasks when the outermost ``rtems_semaphore_obtain`` is
matched with a ``rtems_semaphore_release``.
Simple binary semaphores do not allow nested access and so can be used for task
synchronization.
.. _Priority Inheritance:
Priority Inheritance
--------------------
RTEMS supports :ref:`priority inheritance <PriorityInheritance>` for local,
binary semaphores that use the priority task wait queue blocking discipline.
In SMP configurations, the :ref:`OMIP` is used instead.
.. _Priority Ceiling:
Priority Ceiling
----------------
RTEMS supports :ref:`priority ceiling <PriorityCeiling>` for local, binary
semaphores that use the priority task wait queue blocking discipline.
.. _Multiprocessor Resource Sharing Protocol:
Multiprocessor Resource Sharing Protocol
----------------------------------------
RTEMS supports the :ref:`MrsP` for local, binary semaphores that use the
priority task wait queue blocking discipline. In uniprocessor configurations,
the :ref:`PriorityCeiling` is used instead.
.. _Building a Semaphore Attribute Set:
Building a Semaphore Attribute Set
----------------------------------
In general, an attribute set is built by a bitwise OR of the desired attribute
components. The following table lists the set of valid semaphore attributes:
.. list-table::
:class: rtems-table
* - ``RTEMS_FIFO``
- tasks wait by FIFO (default)
* - ``RTEMS_PRIORITY``
- tasks wait by priority
* - ``RTEMS_BINARY_SEMAPHORE``
- restrict values to 0 and 1
* - ``RTEMS_COUNTING_SEMAPHORE``
- no restriction on values (default)
* - ``RTEMS_SIMPLE_BINARY_SEMAPHORE``
- restrict values to 0 and 1, do not allow nested access, allow deletion of
locked semaphore.
* - ``RTEMS_NO_INHERIT_PRIORITY``
- do not use priority inheritance (default)
* - ``RTEMS_INHERIT_PRIORITY``
- use priority inheritance
* - ``RTEMS_NO_PRIORITY_CEILING``
- do not use priority ceiling (default)
* - ``RTEMS_PRIORITY_CEILING``
- use priority ceiling
* - ``RTEMS_NO_MULTIPROCESSOR_RESOURCE_SHARING``
- do not use Multiprocessor Resource Sharing Protocol (default)
* - ``RTEMS_MULTIPROCESSOR_RESOURCE_SHARING``
- use Multiprocessor Resource Sharing Protocol
* - ``RTEMS_LOCAL``
- local semaphore (default)
* - ``RTEMS_GLOBAL``
- global semaphore
Attribute values are specifically designed to be mutually exclusive, therefore
bitwise OR and addition operations are equivalent as long as each attribute
appears exactly once in the component list. An attribute listed as a default
is not required to appear in the attribute list, although it is a good
programming practice to specify default attributes. If all defaults are
desired, the attribute ``RTEMS_DEFAULT_ATTRIBUTES`` should be specified on this
call.
This example demonstrates the attribute_set parameter needed to create a local
semaphore with the task priority waiting queue discipline. The attribute_set
parameter passed to the ``rtems_semaphore_create`` directive could be either
``RTEMS_PRIORITY`` or ``RTEMS_LOCAL | RTEMS_PRIORITY``. The attribute_set
parameter can be set to ``RTEMS_PRIORITY`` because ``RTEMS_LOCAL`` is the
default for all created tasks. If a similar semaphore were to be known
globally, then the attribute_set parameter would be ``RTEMS_GLOBAL |
RTEMS_PRIORITY``.
Some combinatinos of these attributes are invalid. For example, priority
ordered blocking discipline must be applied to a binary semaphore in order to
use either the priority inheritance or priority ceiling functionality. The
following tree figure illustrates the valid combinations.
.. figure:: ../images/c_user/semaphore_attributes.png
:width: 90%
:align: center
:alt: Semaphore Attributes
.. _Building a SEMAPHORE_OBTAIN Option Set:
Building a SEMAPHORE_OBTAIN Option Set
--------------------------------------
In general, an option is built by a bitwise OR of the desired option
components. The set of valid options for the ``rtems_semaphore_obtain``
directive are listed in the following table:
.. list-table::
:class: rtems-table
* - ``RTEMS_WAIT``
- task will wait for semaphore (default)
* - ``RTEMS_NO_WAIT``
- task should not wait
Option values are specifically designed to be mutually exclusive, therefore
bitwise OR and addition operations are equivalent as long as each attribute
appears exactly once in the component list. An option listed as a default is
not required to appear in the list, although it is a good programming practice
to specify default options. If all defaults are desired, the option
``RTEMS_DEFAULT_OPTIONS`` should be specified on this call.
This example demonstrates the option parameter needed to poll for a semaphore.
The option parameter passed to the ``rtems_semaphore_obtain`` directive should
be ``RTEMS_NO_WAIT``.
Operations
==========
.. _Creating a Semaphore:
Creating a Semaphore
--------------------
The ``rtems_semaphore_create`` directive creates a binary or counting semaphore
with a user-specified name as well as an initial count. If a binary semaphore
is created with a count of zero (0) to indicate that it has been allocated,
then the task creating the semaphore is considered the current holder of the
semaphore. At create time the method for ordering waiting tasks in the
semaphore's task wait queue (by FIFO or task priority) is specified.
Additionally, the priority inheritance or priority ceiling algorithm may be
selected for local, binary semaphores that use the priority task wait queue
blocking discipline. If the priority ceiling algorithm is selected, then the
highest priority of any task which will attempt to obtain this semaphore must
be specified. RTEMS allocates a Semaphore Control Block (SMCB) from the SMCB
free list. This data structure is used by RTEMS to manage the newly created
semaphore. Also, a unique semaphore ID is generated and returned to the
calling task.
.. _Obtaining Semaphore IDs:
Obtaining Semaphore IDs
-----------------------
When a semaphore is created, RTEMS generates a unique semaphore ID and assigns
it to the created semaphore until it is deleted. The semaphore ID may be
obtained by either of two methods. First, as the result of an invocation of
the ``rtems_semaphore_create`` directive, the semaphore ID is stored in a user
provided location. Second, the semaphore ID may be obtained later using the
``rtems_semaphore_ident`` directive. The semaphore ID is used by other
semaphore manager directives to access this semaphore.
.. _Acquiring a Semaphore:
Acquiring a Semaphore
---------------------
The ``rtems_semaphore_obtain`` directive is used to acquire the
specified semaphore. A simplified version of the ``rtems_semaphore_obtain``
directive can be described as follows:
If the semaphore's count is greater than zero then decrement the
semaphore's count else wait for release of semaphore then return
SUCCESSFUL.
When the semaphore cannot be immediately acquired, one of the following
situations applies:
- By default, the calling task will wait forever to acquire the semaphore.
- Specifying ``RTEMS_NO_WAIT`` forces an immediate return with an error status
code.
- Specifying a timeout limits the interval the task will wait before returning
with an error status code.
If the task waits to acquire the semaphore, then it is placed in the
semaphore's task wait queue in either FIFO or task priority order. If the task
blocked waiting for a binary semaphore using priority inheritance and the
task's priority is greater than that of the task currently holding the
semaphore, then the holding task will inherit the priority of the blocking
task. All tasks waiting on a semaphore are returned an error code when the
semaphore is deleted.
When a task successfully obtains a semaphore using priority ceiling and the
priority ceiling for this semaphore is greater than that of the holder, then
the holder's priority will be elevated.
.. _Releasing a Semaphore:
Releasing a Semaphore
---------------------
The ``rtems_semaphore_release`` directive is used to release the specified
semaphore. A simplified version of the ``rtems_semaphore_release`` directive
can be described as follows:
If there are no tasks are waiting on this semaphore then increment the
semaphore's count else assign semaphore to a waiting task and return
SUCCESSFUL.
If this is the outermost release of a binary semaphore that uses priority
inheritance or priority ceiling and the task does not currently hold any other
binary semaphores, then the task performing the ``rtems_semaphore_release``
will have its priority restored to its normal value.
.. _Deleting a Semaphore:
Deleting a Semaphore
--------------------
The ``rtems_semaphore_delete`` directive removes a semaphore from the system
and frees its control block. A semaphore can be deleted by any local task that
knows the semaphore's ID. As a result of this directive, all tasks blocked
waiting to acquire the semaphore will be readied and returned a status code
which indicates that the semaphore was deleted. Any subsequent references to
the semaphore's name and ID are invalid.
Directives
==========

View File

@ -0,0 +1,18 @@
.. SPDX-License-Identifier: CC-BY-SA-4.0
.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
.. index:: semaphores
.. index:: binary semaphores
.. index:: counting semaphores
.. index:: mutual exclusion
Semaphore Manager
*****************
.. toctree::
introduction
background
operations
directives

View File

@ -0,0 +1,25 @@
.. SPDX-License-Identifier: CC-BY-SA-4.0
.. Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
Introduction
============
The semaphore manager utilizes standard Dijkstra
counting semaphores to provide synchronization and mutual
exclusion capabilities. The directives provided by the
semaphore manager are:
- :ref:`rtems_semaphore_create`
- :ref:`rtems_semaphore_ident`
- :ref:`rtems_semaphore_delete`
- :ref:`rtems_semaphore_obtain`
- :ref:`rtems_semaphore_release`
- :ref:`rtems_semaphore_flush`
- :ref:`rtems_semaphore_set_priority`

View File

@ -0,0 +1,105 @@
.. SPDX-License-Identifier: CC-BY-SA-4.0
.. Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
Operations
==========
.. _Creating a Semaphore:
Creating a Semaphore
--------------------
The ``rtems_semaphore_create`` directive creates a binary or counting semaphore
with a user-specified name as well as an initial count. If a binary semaphore
is created with a count of zero (0) to indicate that it has been allocated,
then the task creating the semaphore is considered the current holder of the
semaphore. At create time the method for ordering waiting tasks in the
semaphore's task wait queue (by FIFO or task priority) is specified.
Additionally, the priority inheritance or priority ceiling algorithm may be
selected for local, binary semaphores that use the priority task wait queue
blocking discipline. If the priority ceiling algorithm is selected, then the
highest priority of any task which will attempt to obtain this semaphore must
be specified. RTEMS allocates a Semaphore Control Block (SMCB) from the SMCB
free list. This data structure is used by RTEMS to manage the newly created
semaphore. Also, a unique semaphore ID is generated and returned to the
calling task.
.. _Obtaining Semaphore IDs:
Obtaining Semaphore IDs
-----------------------
When a semaphore is created, RTEMS generates a unique semaphore ID and assigns
it to the created semaphore until it is deleted. The semaphore ID may be
obtained by either of two methods. First, as the result of an invocation of
the ``rtems_semaphore_create`` directive, the semaphore ID is stored in a user
provided location. Second, the semaphore ID may be obtained later using the
``rtems_semaphore_ident`` directive. The semaphore ID is used by other
semaphore manager directives to access this semaphore.
.. _Acquiring a Semaphore:
Acquiring a Semaphore
---------------------
The ``rtems_semaphore_obtain`` directive is used to acquire the
specified semaphore. A simplified version of the ``rtems_semaphore_obtain``
directive can be described as follows:
If the semaphore's count is greater than zero then decrement the
semaphore's count else wait for release of semaphore then return
SUCCESSFUL.
When the semaphore cannot be immediately acquired, one of the following
situations applies:
- By default, the calling task will wait forever to acquire the semaphore.
- Specifying ``RTEMS_NO_WAIT`` forces an immediate return with an error status
code.
- Specifying a timeout limits the interval the task will wait before returning
with an error status code.
If the task waits to acquire the semaphore, then it is placed in the
semaphore's task wait queue in either FIFO or task priority order. If the task
blocked waiting for a binary semaphore using priority inheritance and the
task's priority is greater than that of the task currently holding the
semaphore, then the holding task will inherit the priority of the blocking
task. All tasks waiting on a semaphore are returned an error code when the
semaphore is deleted.
When a task successfully obtains a semaphore using priority ceiling and the
priority ceiling for this semaphore is greater than that of the holder, then
the holder's priority will be elevated.
.. _Releasing a Semaphore:
Releasing a Semaphore
---------------------
The ``rtems_semaphore_release`` directive is used to release the specified
semaphore. A simplified version of the ``rtems_semaphore_release`` directive
can be described as follows:
If there are no tasks are waiting on this semaphore then increment the
semaphore's count else assign semaphore to a waiting task and return
SUCCESSFUL.
If this is the outermost release of a binary semaphore that uses priority
inheritance or priority ceiling and the task does not currently hold any other
binary semaphores, then the task performing the ``rtems_semaphore_release``
will have its priority restored to its normal value.
.. _Deleting a Semaphore:
Deleting a Semaphore
--------------------
The ``rtems_semaphore_delete`` directive removes a semaphore from the system
and frees its control block. A semaphore can be deleted by any local task that
knows the semaphore's ID. As a result of this directive, all tasks blocked
waiting to acquire the semaphore will be readied and returned a status code
which indicates that the semaphore was deleted. Any subsequent references to
the semaphore's name and ID are invalid.