summaryrefslogtreecommitdiffstats
path: root/c_user/semaphore_manager.rst
blob: 16ae2d1a5038be897509f5da269413bb6e69f544 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
.. comment SPDX-License-Identifier: CC-BY-SA-4.0

.. COMMENT: COPYRIGHT (c) 1988-2008.
.. COMMENT: On-Line Applications Research Corporation (OAR).
.. COMMENT: All rights reserved.

Semaphore Manager
#################

.. index:: semaphores
.. index:: binary semaphores
.. index:: counting semaphores
.. index:: mutual exclusion

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 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.  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 must issue the
``rtems_semaphore_release`` directive to allow another task to execute the
critical section.

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
----------------------

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 Inversion
------------------

Priority inversion is a form of indefinite postponement which is common in
multitasking, preemptive executives with shared resources.  Priority inversion
occurs when a high priority tasks requests access to shared resource which is
currently allocated to low priority task.  The high priority task must block
until the low priority task releases the resource.  This problem is exacerbated
when the low priority task is prevented from executing by one or more medium
priority tasks.  Because the low priority task is not executing, it cannot
complete its interaction with the resource and release that resource.  The high
priority task is effectively prevented from executing by lower priority tasks.


Priority Inheritance
--------------------

Priority inheritance is an algorithm that calls for the lower priority task
holding a resource to have its priority increased to that of the highest
priority task blocked waiting for that resource.  Each time a task blocks
attempting to obtain the resource, the task holding the resource may have its
priority increased.

On SMP configurations, in case the task holding the resource and the task that
blocks attempting to obtain the resource are in different scheduler instances,
the priority of the holder is raised to the pseudo-interrupt priority (priority
boosting).  The pseudo-interrupt priority is the highest priority.

RTEMS supports priority inheritance for local, binary semaphores that use the
priority task wait queue blocking discipline.  When a task of higher priority
than the task holding the semaphore blocks, the priority of the task holding
the semaphore is increased to that of the blocking task.  When the task holding
the task completely releases the binary semaphore (i.e. not for a nested
release), the holder's priority is restored to the value it had before any
higher priority was inherited.

The RTEMS implementation of the priority inheritance algorithm takes into
account the scenario in which a task holds more than one binary semaphore.  The
holding task will execute at the priority of the higher of the highest ceiling
priority or at the priority of the highest priority task blocked waiting for
any of the semaphores the task holds.  Only when the task releases ALL of the
binary semaphores it holds will its priority be restored to the normal value.

Priority Ceiling
----------------

Priority ceiling is an algorithm that calls for the lower priority task holding
a resource to have its priority increased to that of the highest priority task
which will EVER block waiting for that resource.  This algorithm addresses the
problem of priority inversion although it avoids the possibility of changing
the priority of the task holding the resource multiple times.  The priority
ceiling algorithm will only change the priority of the task holding the
resource a maximum of one time.  The ceiling priority is set at creation time
and must be the priority of the highest priority task which will ever attempt
to acquire that semaphore.

RTEMS supports priority ceiling for local, binary semaphores that use the
priority task wait queue blocking discipline.  When a task of lower priority
than the ceiling priority successfully obtains the semaphore, its priority is
raised to the ceiling priority.  When the task holding the task completely
releases the binary semaphore (i.e. not for a nested release), the holder's
priority is restored to the value it had before any higher priority was put
into effect.

The need to identify the highest priority task which will attempt to obtain a
particular semaphore can be a difficult task in a large, complicated system.
Although the priority ceiling algorithm is more efficient than the priority
inheritance algorithm with respect to the maximum number of task priority
changes which may occur while a task holds a particular semaphore, the priority
inheritance algorithm is more forgiving in that it does not require this
apriori information.

The RTEMS implementation of the priority ceiling algorithm takes into account
the scenario in which a task holds more than one binary semaphore.  The holding
task will execute at the priority of the higher of the highest ceiling priority
or at the priority of the highest priority task blocked waiting for any of the
semaphores the task holds.  Only when the task releases ALL of the binary
semaphores it holds will its priority be restored to the normal value.


Multiprocessor Resource Sharing Protocol
----------------------------------------

The Multiprocessor Resource Sharing Protocol (MrsP) is defined in *A.  Burns
and A.J.  Wellings, A Schedulability Compatible Multiprocessor Resource Sharing
Protocol - MrsP, Proceedings of the 25th Euromicro Conference on Real-Time
Systems (ECRTS 2013), July 2013*.  It is a generalization of the Priority
Ceiling Protocol to SMP systems.  Each MrsP semaphore uses a ceiling priority
per scheduler instance.  These ceiling priorities can be specified with
``rtems_semaphore_set_priority()``.  A task obtaining or owning a MrsP
semaphore will execute with the ceiling priority for its scheduler instance as
specified by the MrsP semaphore object.  Tasks waiting to get ownership of a
MrsP semaphore will not relinquish the processor voluntarily.  In case the
owner of a MrsP semaphore gets preempted it can ask all tasks waiting for this
semaphore to help out and temporarily borrow the right to execute on one of
their assigned processors.

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
--------------------------------------

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
--------------------

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
-----------------------

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
---------------------

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
---------------------

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 sre 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
--------------------

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
==========

This section details the semaphore manager's directives.  A subsection is
dedicated to each of this manager's directives and describes the calling
sequence, related constants, usage, and status codes.

.. _rtems_semaphore_create:

SEMAPHORE_CREATE - Create a semaphore
-------------------------------------
.. index:: create a semaphore

**CALLING SEQUENCE:**

.. index:: rtems_semaphore_create

.. code-block:: c

    rtems_status_code rtems_semaphore_create(
        rtems_name           name,
        uint32_t             count,
        rtems_attribute      attribute_set,
        rtems_task_priority  priority_ceiling,
        rtems_id            *id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - semaphore created successfully
 * - ``RTEMS_INVALID_NAME``
   - invalid semaphore name
 * - ``RTEMS_INVALID_ADDRESS``
   - ``id`` is NULL
 * - ``RTEMS_TOO_MANY``
   - too many semaphores created
 * - ``RTEMS_NOT_DEFINED``
   - invalid attribute set
 * - ``RTEMS_INVALID_NUMBER``
   - invalid starting count for binary semaphore
 * - ``RTEMS_MP_NOT_CONFIGURED``
   - multiprocessing not configured
 * - ``RTEMS_TOO_MANY``
   - too many global objects

**DESCRIPTION:**

This directive creates a semaphore which resides on the local node. The created
semaphore has the user-defined name specified in name and the initial count
specified in count.  For control and maintenance of the semaphore, RTEMS
allocates and initializes a SMCB.  The RTEMS-assigned semaphore id is returned
in id.  This semaphore id is used with other semaphore related directives to
access the semaphore.

Specifying PRIORITY in attribute_set causes tasks waiting for a semaphore to be
serviced according to task priority.  When FIFO is selected, tasks are serviced
in First In-First Out order.

**NOTES:**

This directive will not cause the calling task to be preempted.

The priority inheritance and priority ceiling algorithms are only supported for
local, binary semaphores that use the priority task wait queue blocking
discipline.

The following semaphore attribute constants are
defined by RTEMS:

.. 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, block on 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

Semaphores should not be made global unless remote tasks must interact with the
created semaphore.  This is to avoid the system overhead incurred by the
creation of a global semaphore.  When a global semaphore is created, the
semaphore's name and id must be transmitted to every node in the system for
insertion in the local copy of the global object table.

Note that some combinations of attributes are not valid.  See the earlier
discussion on this.

The total number of global objects, including semaphores, is limited by the
maximum_global_objects field in the Configuration Table.

It is not allowed to create an initially locked MrsP semaphore and the
``RTEMS_INVALID_NUMBER`` status code will be returned on SMP configurations in
this case.  This prevents lock order reversal problems with the allocator
mutex.

.. _rtems_semaphore_ident:

SEMAPHORE_IDENT - Get ID of a semaphore
---------------------------------------
.. index:: get ID of a semaphore
.. index:: obtain ID of a semaphore

**CALLING SEQUENCE:**

.. index:: rtems_semaphore_ident

.. code-block:: c

    rtems_status_code rtems_semaphore_ident(
        rtems_name  name,
        uint32_t    node,
        rtems_id   *id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - semaphore identified successfully
 * - ``RTEMS_INVALID_NAME``
   - semaphore name not found
 * - ``RTEMS_INVALID_NODE``
   - invalid node id

**DESCRIPTION:**

This directive obtains the semaphore id associated with the semaphore name.  If
the semaphore name is not unique, then the semaphore id will match one of the
semaphores with that name.  However, this semaphore id is not guaranteed to
correspond to the desired semaphore.  The semaphore id is used by other
semaphore related directives to access the semaphore.

**NOTES:**

This directive will not cause the running task to be preempted.

If node is ``RTEMS_SEARCH_ALL_NODES``, all nodes are searched with the local
node being searched first.  All other nodes are searched with the lowest
numbered node searched first.

If node is a valid node number which does not represent the local node, then
only the semaphores exported by the designated node are searched.

This directive does not generate activity on remote nodes.  It accesses only
the local copy of the global object table.

.. _rtems_semaphore_delete:

SEMAPHORE_DELETE - Delete a semaphore
-------------------------------------
.. index:: delete a semaphore

**CALLING SEQUENCE:**

.. index:: rtems_semaphore_delete

.. code-block:: c

    rtems_status_code rtems_semaphore_delete(
    rtems_id id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - semaphore deleted successfully
 * - ``RTEMS_INVALID_ID``
   - invalid semaphore id
 * - ``RTEMS_RESOURCE_IN_USE``
   - binary semaphore is in use
 * - ``RTEMS_ILLEGAL_ON_REMOTE_OBJECT``
   - cannot delete remote semaphore

**DESCRIPTION:**

This directive deletes the semaphore specified by ``id``.  All tasks blocked
waiting to acquire the semaphore will be readied and returned a status code
which indicates that the semaphore was deleted.  The SMCB for this semaphore is
reclaimed by RTEMS.

**NOTES:**

The calling task will be preempted if it is enabled by the task's execution
mode and a higher priority local task is waiting on the deleted semaphore.  The
calling task will NOT be preempted if all of the tasks that are waiting on the
semaphore are remote tasks.

The calling task does not have to be the task that created the semaphore.  Any
local task that knows the semaphore id can delete the semaphore.

When a global semaphore is deleted, the semaphore id must be transmitted to
every node in the system for deletion from the local copy of the global object
table.

The semaphore must reside on the local node, even if the semaphore was created
with the ``RTEMS_GLOBAL`` option.

Proxies, used to represent remote tasks, are reclaimed when the semaphore is
deleted.

.. _rtems_semaphore_obtain:

SEMAPHORE_OBTAIN - Acquire a semaphore
--------------------------------------
.. index:: obtain a semaphore
.. index:: lock a semaphore

**CALLING SEQUENCE:**

.. index:: rtems_semaphore_obtain

.. code-block:: c

    rtems_status_code rtems_semaphore_obtain(
        rtems_id        id,
        rtems_option    option_set,
        rtems_interval  timeout
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - semaphore obtained successfully
 * - ``RTEMS_UNSATISFIED``
   - semaphore not available
 * - ``RTEMS_TIMEOUT``
   - timed out waiting for semaphore
 * - ``RTEMS_OBJECT_WAS_DELETED``
   - semaphore deleted while waiting
 * - ``RTEMS_INVALID_ID``
   - invalid semaphore id

**DESCRIPTION:**

This directive acquires the semaphore specified by id.  The ``RTEMS_WAIT`` and
``RTEMS_NO_WAIT`` components of the options parameter indicate whether the
calling task wants to wait for the semaphore to become available or return
immediately if the semaphore is not currently available.  With either
``RTEMS_WAIT`` or ``RTEMS_NO_WAIT``, if the current semaphore count is
positive, then it is decremented by one and the semaphore is successfully
acquired by returning immediately with a successful return code.

If the calling task chooses to return immediately and the current semaphore
count is zero or negative, then a 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 or negative, then it is decremented by
one and the calling task is placed on the semaphore's wait queue and blocked.
If the semaphore was created with the ``RTEMS_PRIORITY`` attribute, then the
calling task is inserted into the queue according to its priority.  However, if
the semaphore was created with the ``RTEMS_FIFO`` attribute, then the calling
task is placed at the rear of the wait queue.  If the binary semaphore was
created with the ``RTEMS_INHERIT_PRIORITY`` attribute, then the priority of the
task currently holding the binary semaphore is guaranteed to be greater than or
equal to that of the blocking task.  If the binary semaphore was created with
the ``RTEMS_PRIORITY_CEILING`` 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 obtaining the semaphore is
elevated to that of the ceiling.

The timeout parameter specifies the maximum interval the calling task is
willing to be blocked waiting for the semaphore.  If it is set to
``RTEMS_NO_TIMEOUT``, then the calling task will wait forever.  If the
semaphore is available or the ``RTEMS_NO_WAIT`` option component is set, then
timeout is ignored.

Deadlock situations are detected for MrsP semaphores and the
``RTEMS_UNSATISFIED`` status code will be returned on SMP configurations in
this case.

**NOTES:**

The following semaphore acquisition option constants are defined by RTEMS:

.. list-table::
 :class: rtems-table

 * - ``RTEMS_WAIT``
   - task will wait for semaphore (default)
 * - ``RTEMS_NO_WAIT``
   - task should not wait

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 ``RTEMS_NO_WAIT`` 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.

A clock tick is required to support the timeout functionality of this
directive.

It is not allowed to obtain a MrsP semaphore more than once by one task at a
time (nested access) and the ``RTEMS_UNSATISFIED`` status code will be returned
on SMP configurations in this case.

.. _rtems_semaphore_release:

SEMAPHORE_RELEASE - Release a semaphore
---------------------------------------
.. index:: release a semaphore
.. index:: unlock a semaphore

**CALLING SEQUENCE:**

.. index:: rtems_semaphore_release

.. code-block:: c

    rtems_status_code rtems_semaphore_release(
        rtems_id id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - semaphore released successfully
 * - ``RTEMS_INVALID_ID``
   - invalid semaphore id
 * - ``RTEMS_NOT_OWNER_OF_RESOURCE``
   - calling task does not own semaphore
 * - ``RTEMS_INCORRECT_STATE``
   - invalid unlock order

**DESCRIPTION:**

This directive releases the semaphore specified by id.  The semaphore count is
incremented by one.  If the count is zero or negative, then the first task on
this semaphore's wait queue is removed and unblocked.  The unblocked task may
preempt the running task if the running task's preemption mode is enabled and
the unblocked task has a higher priority than the running task.

**NOTES:**

The calling task may be preempted if it causes a higher priority task to be
made ready for execution.

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.

The outermost release of a local, binary, priority inheritance or priority
ceiling semaphore may result in the calling task having its priority lowered.
This will occur if the calling task holds no other binary semaphores and it has
inherited a higher priority.

The MrsP semaphores must be released in the reversed obtain order, otherwise
the ``RTEMS_INCORRECT_STATE`` status code will be returned on SMP
configurations in this case.

.. _rtems_semaphore_flush:

SEMAPHORE_FLUSH - Unblock all tasks waiting on a semaphore
----------------------------------------------------------
.. index:: flush a semaphore
.. index:: unblock all tasks waiting on a semaphore

**CALLING SEQUENCE:**

.. index:: rtems_semaphore_flush

.. code-block:: c

    rtems_status_code rtems_semaphore_flush(
        rtems_id id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - semaphore released successfully
 * - ``RTEMS_INVALID_ID``
   - invalid semaphore id
 * - ``RTEMS_NOT_DEFINED``
   - operation not defined for the protocol ofthe semaphore
 * - ``RTEMS_ILLEGAL_ON_REMOTE_OBJECT``
   - not supported for remote semaphores

**DESCRIPTION:**

This directive unblocks all tasks waiting on the semaphore specified by id.
Since there are tasks blocked on the semaphore, the semaphore's count is not
changed by this directive and thus is zero before and after this directive is
executed.  Tasks which are unblocked as the result of this directive will
return from the ``rtems_semaphore_obtain`` directive with a status code of
``RTEMS_UNSATISFIED`` to indicate that the semaphore was not obtained.

This directive may unblock any number of tasks.  Any of the unblocked tasks may
preempt the running task if the running task's preemption mode is enabled and
an unblocked task has a higher priority than the running task.

**NOTES:**

The calling task may be preempted if it causes a higher priority task to be
made ready for execution.

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 MrsP semaphore and the ``RTEMS_NOT_DEFINED``
status code will be returned on SMP configurations in this case.

.. _rtems_semaphore_set_priority:

SEMAPHORE_SET_PRIORITY - Set priority by scheduler for a semaphore
------------------------------------------------------------------
.. index:: set priority by scheduler for a semaphore

**CALLING SEQUENCE:**

.. index:: rtems_semaphore_set_priority

.. code-block:: c

    rtems_status_code rtems_semaphore_set_priority(
        rtems_id             semaphore_id,
        rtems_id             scheduler_id,
        rtems_task_priority  new_priority,
        rtems_task_priority *old_priority
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - successful operation
 * - ``RTEMS_INVALID_ID``
   - invalid semaphore or scheduler id
 * - ``RTEMS_INVALID_ADDRESS``
   - ``old_priority`` is NULL
 * - ``RTEMS_INVALID_PRIORITY``
   - invalid new priority value
 * - ``RTEMS_NOT_DEFINED``
   - operation not defined for the protocol ofthe semaphore
 * - ``RTEMS_ILLEGAL_ON_REMOTE_OBJECT``
   - not supported for remote semaphores

**DESCRIPTION:**

This directive sets the priority value with respect to the specified scheduler
of a semaphore.

The special priority value ``RTEMS_CURRENT_PRIORITY`` can be used to get the
current priority value without changing it.

The interpretation of the priority value depends on the protocol of the
semaphore object.

- The Multiprocessor Resource Sharing Protocol needs a ceiling priority per
  scheduler instance.  This operation can be used to specify these priority
  values.

- For the Priority Ceiling Protocol the ceiling priority is used with this
  operation.

- For other protocols this operation is not defined.

**EXAMPLE:**

.. code-block:: c
    :linenos:

    #include <assert.h>
    #include <stdlib.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;

        /* 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 MrsP semaphore object */
        sc = rtems_semaphore_create(
            rtems_build_name('M', 'R', 'S', 'P'),
            1,
            RTEMS_MULTIPROCESSOR_RESOURCE_SHARING | RTEMS_BINARY_SEMAPHORE,
            1,
            &semaphore_id
        );
        assert(sc == RTEMS_SUCCESSFUL);

        /*
         * The ceiling priority values per scheduler are equal to the value specified
         * for object 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);
        exit(0);
    }

    #define CONFIGURE_SMP_APPLICATION
    #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_MRSP_SEMAPHORES 1
    #define CONFIGURE_SMP_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_CONTROLS \
              RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, SCHED_A), \
              RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(b, SCHED_B)
    #define CONFIGURE_SMP_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>