[rtems-central commit] spec: Document semaphore directives
Sebastian Huber
sebh at rtems.org
Thu Feb 4 13:29:01 UTC 2021
Module: rtems-central
Branch: master
Commit: 9e2cad71018c0d65b6fa2aa77fbb8fac6c6baf21
Changeset: http://git.rtems.org/rtems-central/commit/?id=9e2cad71018c0d65b6fa2aa77fbb8fac6c6baf21
Author: Sebastian Huber <sebastian.huber at embedded-brains.de>
Date: Tue Jan 19 07:30:00 2021 +0100
spec: Document semaphore directives
---
spec/rtems/sem/constraint/max.yml | 11 +++
spec/rtems/sem/if/flush.yml | 89 ++++++++++++++++++--
spec/rtems/sem/if/group.yml | 14 ++++
spec/rtems/sem/if/obtain.yml | 132 ++++++++++++++++++++++++++++--
spec/rtems/sem/if/release.yml | 58 +++++++++++--
spec/rtems/sem/if/set-priority.yml | 163 ++++++++++++++++++++++++++++++++++---
6 files changed, 434 insertions(+), 33 deletions(-)
diff --git a/spec/rtems/sem/constraint/max.yml b/spec/rtems/sem/constraint/max.yml
new file mode 100644
index 0000000..f80d82a
--- /dev/null
+++ b/spec/rtems/sem/constraint/max.yml
@@ -0,0 +1,11 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+links: []
+rationale: null
+scope: user
+text: |
+ The number of semaphores available to the application is configured through
+ the ${/acfg/if/max-semaphores:/name} application configuration option.
+type: constraint
diff --git a/spec/rtems/sem/if/flush.yml b/spec/rtems/sem/if/flush.yml
index 3091569..6665a1e 100644
--- a/spec/rtems/sem/if/flush.yml
+++ b/spec/rtems/sem/if/flush.yml
@@ -1,7 +1,8 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
-brief: '%'
+brief: |
+ Flushes the semaphore.
copyrights:
-- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
- Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
definition:
default:
@@ -11,9 +12,17 @@ definition:
- ${../../type/if/id:/name} ${.:/params[0]/name}
return: ${../../status/if/code:/name}
variants: []
-description: null
+description: |
+ This directive unblocks all tasks waiting on the semaphore specified by
+ ${.:/params[0]/name}. The semaphore's count is not changed by this
+ directive. Tasks which are unblocked as the result of this directive will
+ return from the ${obtain:/name} directive with a status code of
+ ${../../status/if/unsatisfied:/name} to indicate that the semaphore was not
+ acquired.
enabled-by: true
-index-entries: []
+index-entries:
+- flush a semaphore
+- unblock all tasks waiting on a semaphore
interface-type: function
links:
- role: interface-placement
@@ -21,12 +30,78 @@ links:
- role: interface-ingroup
uid: group
name: rtems_semaphore_flush
-notes: null
+notes: |
+ This directive may unblock any number of tasks. Any of the unblocked tasks
+ may preempt the calling task if the calling task's preemption mode is
+ enabled and an unblocked task has a higher priority than the calling task.
+
+ If the task to be unblocked resides on a different node from the semaphore,
+ then the waiting task is unblocked, and the proxy used to represent the
+ task is reclaimed.
+
+ It is not allowed to flush a local, binary semaphore using the MrsP locking
+ protocol and any attempt to do this will just return the
+ ${../../status/if/not-defined:/name} status code. This error can only happen
+ in SMP configurations.
+
+ For barrier synchronization, the ${../../barrier/if/group:/name} offers a
+ cleaner alternative to using the ${flush:/name} directive. Unlike POSIX
+ barriers, they have a manual release option.
+
+ Using the ${flush:/name} directive for condition synchronization in concert
+ with another semaphore may be subject to the lost wake-up problem. The
+ following attempt to implement a condition variable is broken.
+
+ .. code-block:: c
+ :linenos:
+
+ #include <rtems.h>
+ #include <assert.h>
+
+ void cnd_wait( rtems_id cnd, rtems_id mtx )
+ {
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_release( mtx );
+ assert( sc == RTEMS_SUCCESSFUL );
+
+ // Here, a higher priority task may run and satisfy the condition.
+ // We may never wake up from the next semaphore obtain.
+
+ sc = rtems_semaphore_obtain( cnd, RTEMS_WAIT, RTEMS_NO_TIMEOUT );
+ assert( sc == RTEMS_UNSATISFIED );
+
+ sc = rtems_semaphore_obtain( mtx, RTEMS_WAIT, RTEMS_NO_TIMEOUT );
+ assert( sc == RTEMS_SUCCESSFUL );
+ }
+
+ void cnd_broadcast( rtems_id cnd )
+ {
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_flush( cnd );
+ assert( sc == RTEMS_SUCCESSFUL );
+ }
params:
-- description: '%'
+- description: |
+ is the semaphore identifier.
dir: null
name: id
return:
return: null
- return-values: []
+ return-values:
+ - description: |
+ The requested operation was successful.
+ value: ${../../status/if/successful:/name}
+ - description: |
+ There was no semaphore associated with the identifier specified by
+ ${.:/params[0]/name}.
+ value: ${../../status/if/invalid-id:/name}
+ - description: |
+ The semaphore resided on a remote node.
+ value: ${../../status/if/illegal-on-remote-object:/name}
+ - description: |
+ Flushing a semaphore using the MrsP locking protocol is undefined
+ behaviour.
+ value: ${../../status/if/not-defined:/name}
type: interface
diff --git a/spec/rtems/sem/if/group.yml b/spec/rtems/sem/if/group.yml
index 053c09b..d898bdd 100644
--- a/spec/rtems/sem/if/group.yml
+++ b/spec/rtems/sem/if/group.yml
@@ -14,6 +14,20 @@ links:
uid: header
- role: interface-ingroup
uid: ../../if/group
+- role: placement-order
+ uid: create
+- role: placement-order
+ uid: ident
+- role: placement-order
+ uid: delete
+- role: placement-order
+ uid: obtain
+- role: placement-order
+ uid: release
+- role: placement-order
+ uid: flush
+- role: placement-order
+ uid: set-priority
name: Semaphore Manager
text: |
The Classic API shall provide an interface to the Semaphore Manager.
diff --git a/spec/rtems/sem/if/obtain.yml b/spec/rtems/sem/if/obtain.yml
index ab3e5fe..b7deb37 100644
--- a/spec/rtems/sem/if/obtain.yml
+++ b/spec/rtems/sem/if/obtain.yml
@@ -1,5 +1,6 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
-brief: '%'
+brief: |
+ Obtains the semaphore.
copyrights:
- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
- Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
@@ -13,28 +14,143 @@ definition:
- ${../../type/if/interval:/name} ${.:/params[2]/name}
return: ${../../status/if/code:/name}
variants: []
-description: null
+description: |
+ This directive obtains the semaphore specified by ${.:/params[0]/name}.
+
+ The **option set** specified in ${.:/params[1]/name} is built through a
+ *bitwise or* of the option constants described below. Not all combinations
+ of options are allowed. Some options are mutually exclusive. If mutually
+ exclusive options are combined, the behaviour is undefined. Options not
+ mentioned below are not evaluated by this directive and have no effect.
+ Default options can be selected by using the ${../../option/if/default:/name}
+ constant.
+
+ The calling task can **wait** or **try to obtain** the semaphore according
+ to the mutually exclusive ${../../option/if/wait:/name} and
+ ${../../option/if/no-wait:/name} options.
+
+ * **Waiting to obtain** the semaphore is the default and can be emphasized
+ through the use of the ${../../option/if/wait:/name} option. The
+ ${.:/params[2]/name} parameter defines how long the calling task is willing
+ to wait. Use ${../../type/if/no-timeout:/name} to wait potentially
+ forever, otherwise set a timeout interval in clock ticks.
+
+ * **Trying to obtain** the semaphore is selected by the
+ ${../../option/if/no-wait:/name} option. If this option is defined, then
+ the ${.:/params[2]/name} parameter is ignored. When the semaphore cannot
+ be immediately obtained, then the ${../../status/if/unsatisfied:/name}
+ status is returned.
+
+ With either ${../../option/if/wait:/name} or ${../../option/if/no-wait:/name}
+ if the current semaphore count is positive, then it is decremented by one and
+ the semaphore is successfully obtained by returning immediately with the
+ ${../../status/if/successful:/name} status code.
+
+ If the calling task chooses to return immediately and the current semaphore
+ count is zero, then the ${../../status/if/unsatisfied:/name} status code is
+ returned indicating that the semaphore is not available.
+
+ If the calling task chooses to wait for a semaphore and the current semaphore
+ count is zero, then the calling task is placed on the semaphore's wait queue
+ and blocked. If a local, binary semaphore was created with the
+ ${../../attr/if/inherit-priority:/name} attribute, then the priority of the
+ task currently holding the binary semaphore will inherit the current priority
+ set of the blocking task. The priority inheritance is carried out
+ recursively. This means, that if the task currently holding the binary
+ semaphore is blocked on another local, binary semaphore using the priority
+ inheritance locking protocol, then the owner of this semaphore will inherit
+ the current priority sets of both tasks, and so on. A task has a current
+ priority for each scheduler.
enabled-by: true
-index-entries: []
+index-entries:
+- obtain a semaphore
+- lock a semaphore
interface-type: function
links:
- role: interface-placement
uid: header
- role: interface-ingroup
uid: group
+- role: constraint
+ uid: /constraint/directive-ctx-task
+- role: constraint
+ uid: /constraint/clock-tick
name: rtems_semaphore_obtain
-notes: null
+notes: |
+ If a local, binary semaphore was created with the
+ ${../../attr/if/priority-ceiling:/name} or
+ ${../../attr/if/multiprocessor-resource-sharing:/name} attribute, a task
+ successfully obtains the semaphore, and the priority of that task is greater
+ than the ceiling priority for this semaphore, then the priority of the task
+ acquiring the semaphore is elevated to that of the ceiling.
+
+ Deadlock situations are detected for local, binary semaphores. If a deadlock
+ is detected, then the directive immediately returns the
+ ${../../status/if/incorrect-state:/name} status code.
+
+ It is not allowed to recursively obtain (nested access) a local, binary
+ semaphore using the MrsP locking protocol and any attempt to do this will
+ just return the ${../../status/if/incorrect-state:/name} status code. This
+ error can only happen in SMP configurations.
+
+ If the semaphore was created with the ${../../attr/if/priority:/name}
+ attribute, then the calling task is inserted into the wait queue according to
+ its priority. However, if the semaphore was created with the
+ ${../../attr/if/fifo:/name} attribute, then the calling task is placed at the
+ rear of the wait queue.
+
+ Attempting to obtain a global semaphore which does not reside on the local
+ node will generate a request to the remote node to access the semaphore. If
+ the semaphore is not available and ${../../option/if/no-wait:/name} was not
+ specified, then the task must be blocked until the semaphore is released. A
+ proxy is allocated on the remote node to represent the task until the
+ semaphore is released.
params:
-- description: '%'
+- description: |
+ is the semaphore identifier.
dir: null
name: id
-- description: '%'
+- description: |
+ is the option set.
dir: null
name: option_set
-- description: '%'
+- description: |
+ is the timeout in clock ticks if the ${../../option/if/wait:/name} option
+ is set. Use ${../../type/if/no-timeout:/name} to wait potentially
+ forever.
dir: null
name: timeout
return:
return: null
- return-values: []
+ return-values:
+ - description: |
+ The requested operation was successful.
+ value: ${../../status/if/successful:/name}
+ - description: |
+ There was no semaphore associated with the identifier specified by
+ ${.:/params[0]/name}.
+ value: ${../../status/if/invalid-id:/name}
+ - description: |
+ The semaphore could not be obtained immediately.
+ value: ${../../status/if/unsatisfied:/name}
+ - description: |
+ Acquiring of the local, binary semaphore by the calling task would have
+ cased a deadlock.
+ value: ${../../status/if/incorrect-state:/name}
+ - description: |
+ The calling task attempted to recursively obtain a local, binary
+ semaphore using the MrsP locking protocol.
+ value: ${../../status/if/incorrect-state:/name}
+ - description: |
+ The semaphore was flushed while the calling task was waiting to obtain
+ the semaphore.
+ value: ${../../status/if/unsatisfied:/name}
+ - description: |
+ The timeout happened while the calling task was waiting to obtain the
+ semaphore.
+ value: ${../../status/if/timeout:/name}
+ - description: |
+ The semaphore was deleted while the calling task was waiting to obtain
+ the semaphore.
+ value: ${../../status/if/object-was-deleted:/name}
type: interface
diff --git a/spec/rtems/sem/if/release.yml b/spec/rtems/sem/if/release.yml
index 18dff3e..0861cfc 100644
--- a/spec/rtems/sem/if/release.yml
+++ b/spec/rtems/sem/if/release.yml
@@ -1,7 +1,8 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
-brief: '%'
+brief: |
+ Releases the semaphore.
copyrights:
-- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
- Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
definition:
default:
@@ -11,9 +12,19 @@ definition:
- ${../../type/if/id:/name} ${.:/params[0]/name}
return: ${../../status/if/code:/name}
variants: []
-description: null
+description: |
+ This directive releases the semaphore specified by ${.:/params[0]/name}. If
+ the semaphore's wait queue is not empty, then
+
+ * the first task on the wait queue is removed and unblocked, the semaphore's
+ count is not changed, otherwise
+
+ * the semaphore's count is incremented by one for counting semaphores and set
+ to one for binary and simple binary semaphores.
enabled-by: true
-index-entries: []
+index-entries:
+- release a semaphore
+- unlock a semaphore
interface-type: function
links:
- role: interface-placement
@@ -21,12 +32,45 @@ links:
- role: interface-ingroup
uid: group
name: rtems_semaphore_release
-notes: null
+notes: |
+ The calling task may be preempted if it causes a higher priority task to be
+ made ready for execution.
+
+ The outermost release of a local, binary semaphore using the priority
+ inheritance, priority ceiling, or MrsP locking protocol may result
+ in the calling task having its priority lowered. This will occur if the
+ highest priority of the calling task was available due to the ownership of
+ the released semaphore. If a task was on the semaphore's wait queue, then
+ the priority associated with the semaphore will be transferred to the new
+ owner.
+
+ Releasing a global semaphore which does not reside on the local node will
+ generate a request telling the remote node to release the semaphore.
+
+ If the task to be unblocked resides on a different node from the semaphore,
+ then the semaphore allocation is forwarded to the appropriate node, the
+ waiting task is unblocked, and the proxy used to represent the task is
+ reclaimed.
params:
-- description: '%'
+- description: |
+ is the semaphore identifier.
dir: null
name: id
return:
return: null
- return-values: []
+ return-values:
+ - description: |
+ The requested operation was successful.
+ value: ${../../status/if/successful:/name}
+ - description: |
+ There was no semaphore associated with the identifier specified by
+ ${.:/params[0]/name}.
+ value: ${../../status/if/invalid-id:/name}
+ - description: |
+ The calling task was not the owner of the semaphore.
+ value: ${../../status/if/not-owner-of-resource:/name}
+ - description: |
+ The semaphore's count already had the maximum value of
+ ${/c/if/uint32_max:/name}.
+ value: ${../../status/if/internal-error:/name}
type: interface
diff --git a/spec/rtems/sem/if/set-priority.yml b/spec/rtems/sem/if/set-priority.yml
index 269302c..f7532a5 100644
--- a/spec/rtems/sem/if/set-priority.yml
+++ b/spec/rtems/sem/if/set-priority.yml
@@ -1,7 +1,8 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
-brief: '%'
+brief: |
+ Sets the priority by scheduler for the semaphore.
copyrights:
-- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
- Copyright (C) 1988, 2008 On-Line Applications Research Corporation (OAR)
definition:
default:
@@ -14,9 +15,28 @@ definition:
- ${../../task/if/priority:/name} *${.:/params[3]/name}
return: ${../../status/if/code:/name}
variants: []
-description: null
+description: |
+ This directive sets the priority of the semaphore specified by
+ ${.:/params[0]/name}. The priority corresponds to the scheduler specified by
+ ${.:/params[1]/name}.
+
+ The special priority value ${../../task/if/current-priority:/name} can be
+ used to get the current priority without changing it.
+
+ The availability and use of a priority depends on the class and locking
+ protocol of the semaphore:
+
+ * For local, binary semaphores using the MrsP locking protocol, the ceiling
+ priority for each scheduler can be set by this directive.
+
+ * For local, binary semaphores using the priority ceiling protocol, the
+ ceiling priority can be set by this directive.
+
+ * For other semaphore classes and locking protocols, setting a priority is
+ undefined behaviour.
enabled-by: true
-index-entries: []
+index-entries:
+- set priority by scheduler for a semaphore
interface-type: function
links:
- role: interface-placement
@@ -24,21 +44,142 @@ links:
- role: interface-ingroup
uid: group
name: rtems_semaphore_set_priority
-notes: null
+notes: |
+ Please have a look at the following example:
+
+ .. code-block:: c
+ :linenos:
+
+ #include <assert.h>
+ #include <rtems.h>
+
+ #define SCHED_A rtems_build_name( ' ', ' ', ' ', 'A' )
+ #define SCHED_B rtems_build_name( ' ', ' ', ' ', 'B' )
+
+ static void Init( rtems_task_argument arg )
+ {
+ rtems_status_code sc;
+ rtems_id semaphore_id;
+ rtems_id scheduler_a_id;
+ rtems_id scheduler_b_id;
+ rtems_task_priority prio;
+
+ (void) arg;
+
+ // Get the scheduler identifiers
+ sc = rtems_scheduler_ident( SCHED_A, &scheduler_a_id );
+ assert( sc == RTEMS_SUCCESSFUL );
+ sc = rtems_scheduler_ident( SCHED_B, &scheduler_b_id );
+ assert( sc == RTEMS_SUCCESSFUL );
+
+ // Create a local, binary semaphore using the MrsP locking protocol
+ sc = rtems_semaphore_create(
+ rtems_build_name( 'M', 'R', 'S', 'P' ),
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING,
+ 1,
+ &semaphore_id
+ );
+ assert( sc == RTEMS_SUCCESSFUL );
+
+ // The ceiling priority for each scheduler is equal to the priority
+ // specified for the semaphore creation.
+ prio = RTEMS_CURRENT_PRIORITY;
+ sc = rtems_semaphore_set_priority( semaphore_id, scheduler_a_id, prio, &prio );
+ assert( sc == RTEMS_SUCCESSFUL );
+ assert( prio == 1 );
+
+ // Check the old value and set a new ceiling priority for scheduler B
+ prio = 2;
+ sc = rtems_semaphore_set_priority( semaphore_id, scheduler_b_id, prio, &prio );
+ assert( sc == RTEMS_SUCCESSFUL );
+ assert( prio == 1 );
+
+ // Check the ceiling priority values
+ prio = RTEMS_CURRENT_PRIORITY;
+ sc = rtems_semaphore_set_priority( semaphore_id, scheduler_a_id, prio, &prio );
+ assert( sc == RTEMS_SUCCESSFUL );
+ assert( prio == 1 );
+ prio = RTEMS_CURRENT_PRIORITY;
+ sc = rtems_semaphore_set_priority( semaphore_id, scheduler_b_id, prio, &prio );
+ assert( sc == RTEMS_SUCCESSFUL );
+ assert( prio == 2 );
+
+ sc = rtems_semaphore_delete( semaphore_id );
+ assert( sc == RTEMS_SUCCESSFUL );
+
+ rtems_shutdown_executive( 0 );
+ }
+
+ #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+ #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+ #define CONFIGURE_MAXIMUM_TASKS 1
+ #define CONFIGURE_MAXIMUM_SEMAPHORES 1
+ #define CONFIGURE_MAXIMUM_PROCESSORS 2
+
+ #define CONFIGURE_SCHEDULER_SIMPLE_SMP
+
+ #include <rtems/scheduler.h>
+
+ RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP( a );
+ RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP( b );
+
+ #define CONFIGURE_SCHEDULER_TABLE_ENTRIES \
+ RTEMS_SCHEDULER_TABLE_SIMPLE_SMP( a, SCHED_A ), \
+ RTEMS_SCHEDULER_TABLE_SIMPLE_SMP( b, SCHED_B )
+
+ #define CONFIGURE_SCHEDULER_ASSIGNMENTS \
+ RTEMS_SCHEDULER_ASSIGN( 0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY ), \
+ RTEMS_SCHEDULER_ASSIGN( 1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY )
+
+ #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+ #define CONFIGURE_INIT
+
+ #include <rtems/confdefs.h>
params:
-- description: '%'
+- description: |
+ is the semaphore identifier.
dir: null
name: semaphore_id
-- description: '%'
+- description: |
+ is the identifier of the scheduler corresponding to the new priority.
dir: null
name: scheduler_id
-- description: '%'
+- description: |
+ is the new priority corresponding to the specified scheduler.
dir: null
name: new_priority
-- description: '%'
- dir: null
+- description: |
+ is the pointer to a task priority variable. The old priority of the
+ semaphore corresponding to the specified scheduler will be stored in this
+ variable, in case of a successful operation.
+ dir: out
name: old_priority
return:
return: null
- return-values: []
+ return-values:
+ - description: |
+ The requested operation was successful.
+ value: ${../../status/if/successful:/name}
+ - description: |
+ The ${.:/params[3]/name} parameter was ${/c/if/null:/name}.
+ value: ${../../status/if/invalid-address:/name}
+ - description: |
+ There was no scheduler associated with the identifier specified by
+ ${.:/params[1]/name}.
+ value: ${../../status/if/invalid-id:/name}
+ - description: |
+ There was no semaphore associated with the identifier specified by
+ ${.:/params[0]/name}.
+ value: ${../../status/if/invalid-id:/name}
+ - description: |
+ The semaphore resided on a remote node.
+ value: ${../../status/if/illegal-on-remote-object:/name}
+ - description: |
+ The ${.:/params[2]/name} parameter was invalid.
+ value: ${../../status/if/invalid-priority:/name}
+ - description: |
+ Setting a priority for the class or locking protocol of the semaphore is
+ undefined behaviour.
+ value: ${../../status/if/not-defined:/name}
type: interface
More information about the vc
mailing list