[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