VxWorks Reference Manual : Wind Foundation Classes
VXWSem - semaphore classes
VXWSem::VXWSem( ) - build semaphore object from semaphore ID
VXWSem::~VXWSem( ) - delete a semaphore
VXWSem::give( ) - give a semaphore
VXWSem::take( ) - take a semaphore
VXWSem::flush( ) - unblock every task pended on a semaphore
VXWSem::id( ) - reveal underlying semaphore ID
VXWSem::info( ) - get a list of task IDs that are blocked on a semaphore
VXWSem::show( ) - show information about a semaphore
VXWCSem::VXWCSem( ) - create and initialize a counting semaphore
VXWBSem::VXWBSem( ) - create and initialize a binary semaphore
VXWMSem::VXWMSem( ) - create and initialize a mutual-exclusion semaphore
VXWMSem::giveForce( ) - give a mutual-exclusion semaphore without restrictions
Semaphores are the basis for synchronization and mutual exclusion in VxWorks. They are powerful in their simplicity and form the foundation for numerous VxWorks facilities.
Different semaphore types serve different needs, and while the behavior of the types differs, their basic interface is the same. The VXWSem class provides semaphore routines common to all VxWorks semaphore types. For all types, the two basic operations are VXWSem::take( ) and VXWSem::give( ), the acquisition or relinquishing of a semaphore.
Semaphore creation and initialization is handled by the following classes, which inherit the basic operations from VXWSem:
VXWBSem - binary semaphores
VXWCSem - counting semaphores
VXWMSem - mutual exclusion semaphoresTwo additional semaphore classes provide semaphores that operate over shared memory (with the optional product VxMP). These classes also inherit from VXWSmNameLib; they are described in vxwSmLib. The following are the class names for these shared-memory semaphores:
VXWSmBSem - shared-memory binary semaphores
VXWSmCSem - shared-memory counting semaphoresBinary semaphores offer the greatest speed and the broadest applicability.
The VXWSem class provides all other semaphore operations, including routines for semaphore control, deletion, and information.
The VXWSem::take( ) call acquires a specified semaphore, blocking the calling task or making the semaphore unavailable. All semaphore types support a timeout on the VXWSem::take( ) operation. The timeout is specified as the number of ticks to remain blocked on the semaphore. Timeouts of WAIT_FOREVER and NO_WAIT codify common timeouts. If a VXWSem::take( ) times out, it returns ERROR. Refer to the library of the specific semaphore type for the exact behavior of this operation.
The VXWSem::give( ) call relinquishes a specified semaphore, unblocking a pended task or making the semaphore available. Refer to the library of the specific semaphore type for the exact behavior of this operation.
The VXWSem::flush( ) call may be used to atomically unblock all tasks pended on a semaphore queue; that is, it unblocks all tasks before any are allowed to run. It may be thought of as a broadcast operation in synchronization applications. The state of the semaphore is unchanged by the use of VXWSem::flush( ); it is not analogous to VXWSem::give( ).
The VXWSem::~VXWSem( ) destructor terminates a semaphore and deallocates any associated memory. The deletion of a semaphore unblocks tasks pended on that semaphore; the routines which were pended return ERROR. Take care when deleting semaphores, particularly those used for mutual exclusion, to avoid deleting a semaphore out from under a task that already has taken (owns) that semaphore. Applications should adopt the protocol of only deleting semaphores that the deleting task has successfully taken.
The VXWSem::info( ) call is a useful debugging aid, reporting all tasks blocked on a specified semaphore. It provides a snapshot of the queue at the time of the call, but because semaphores are dynamic, the information may be out of date by the time it is available. As with the current state of the semaphore, use of the queue of pended tasks should be restricted to debugging uses only.
vxwSemLib.h
VXWSem, VXWTask, vxwSmLib, VxWorks Programmer's Guide: Basic OS
VXWSem::VXWSem( ) - build semaphore object from semaphore ID
VXWSem ( SEM_ID id )
Use this constructor to manipulate a semaphore that was not created using C++ interfaces. The argument id is the semaphore identifier returned and used by the C interface to the VxWorks semaphore facility.
N/A
VXWSem::~VXWSem( ) - delete a semaphore
virtual ~VXWSem ()
This destructor terminates and deallocates any memory associated with a specified semaphore. Any pended tasks unblock and return ERROR.
Take care when deleting semaphores, particularly those used for mutual exclusion, to avoid deleting a semaphore out from under a task that already has taken (owns) that semaphore. Applications should adopt the protocol of only deleting semaphores that the deleting task has successfully taken.
N/A
VXWSem, VxWorks Programmer's Guide: Basic OS
VXWSem::give( ) - give a semaphore
STATUS give ()
This routine performs the give operation on a specified semaphore. Depending on the type of semaphore, the state of the semaphore and of the pending tasks may be affected. The behavior of VXWSem::give( ) is discussed fully in the constructor description for the specific semaphore type being used.
OK.
VXWSem, VXWCSem::VXWCsem( ), VXWBSem::VXWBsem( ), VXWMSem::VXWMsem( ), VxWorks Programmer's Guide: Basic OS
VXWSem::take( ) - take a semaphore
STATUS take ( int timeout )
This routine performs the take operation on a specified semaphore. Depending on the type of semaphore, the state of the semaphore and the calling task may be affected. The behavior of VXWSem::take( ) is discussed fully in the constructor description for the specific semaphore type being used.
A timeout in ticks may be specified. If a task times out, VXWSem::take( ) returns ERROR. Timeouts of WAIT_FOREVER and NO_WAIT indicate to wait indefinitely or not to wait at all.
When VXWSem::take( ) returns due to timeout, it sets the errno to S_objLib_OBJ_TIMEOUT (defined in objLib.h).
The VXWSem::take( ) routine must not be called from interrupt service routines.
OK, or ERROR if the task timed out.
VXWSem, VXWCSem::VXWCsem( ), VXWBSem::VXWBsem( ), VXWMSem::VXWMsem( ), VxWorks Programmer's Guide: Basic OS
VXWSem::flush( ) - unblock every task pended on a semaphore
STATUS flush ()
This routine atomically unblocks all tasks pended on a specified semaphore; that is, all tasks are unblocked before any is allowed to run. The state of the underlying semaphore is unchanged. All pended tasks will enter the ready queue before having a chance to execute.
The flush operation is useful as a means of broadcast in synchronization applications. Its use is illegal for mutual-exclusion semaphores created with VXWMSem::VXWMSem( ).
OK, or ERROR if the operation is not supported.
VXWSem, VXWCSem::VXWCsem( ), VXWBSem::VXWBsem( ), VXWMSem::VXWMsem( ), VxWorks Programmer's Guide: Basic OS
VXWSem::id( ) - reveal underlying semaphore ID
SEM_ID id ()
This routine returns the semaphore ID corresponding to a semaphore object. The semaphore ID is used by the C interface to VxWorks semaphores.
Semaphore ID.
VXWSem::info( ) - get a list of task IDs that are blocked on a semaphore
STATUS info ( int idList[], int maxTasks ) const
This routine reports the tasks blocked on a specified semaphore. Up to maxTasks task IDs are copied to the array specified by idList. The array is unordered.
There is no guarantee that all listed tasks are still valid or that new tasks have not been blocked by the time VXWSem::info( ) returns.
The number of blocked tasks placed in idList.
VXWSem::show( ) - show information about a semaphore
STATUS show ( int level ) const
This routine displays (on standard output) the state and optionally the pended tasks of a semaphore.
A summary of the state of the semaphore is displayed as follows:
Semaphore Id : 0x585f2 Semaphore Type : BINARY Task Queuing : PRIORITY Pended Tasks : 1 State : EMPTY {Count if COUNTING, Owner if MUTEX}If level is 1, more detailed information is displayed. If tasks are blocked on the queue, they are displayed in the order in which they will unblock, as follows:NAME TID PRI DELAY ---------- -------- --- ----- tExcTask 3fd678 0 21 tLogTask 3f8ac0 0 611
OK or ERROR.
VXWCSem::VXWCSem( ) - create and initialize a counting semaphore
VXWCSem ( int opts, int count )
This routine allocates and initializes a counting semaphore. The semaphore is initialized to the specified initial count.
The opts parameter specifies the queuing style for blocked tasks. Tasks may be queued on a priority basis or a first-in-first-out basis. These options are SEM_Q_PRIORITY and SEM_Q_FIFO, respectively.
A counting semaphore may be viewed as a cell in memory whose contents keep track of a count. When a task takes a counting semaphore, using VXWSem::take( ), subsequent action depends on the state of the count:
- (1)
- If the count is non-zero, it is decremented and the calling task continues executing.
- (2)
- If the count is zero, the task is blocked, pending the availability of the semaphore. If a timeout is specified and the timeout expires, the pended task is removed from the queue of pended tasks and enters the ready state with an ERROR status. A pended task is ineligible for CPU allocation. Any number of tasks may be pended simultaneously on the same counting semaphore.
When a task gives a semaphore, using VXWSem::give( ), the next available task in the pend queue is unblocked. If no task is pending on this semaphore, the semaphore count is incremented. Note that if a semaphore is given, and a task is unblocked that is of higher priority than the task that called VXWSem::give( ), the unblocked task preempts the calling task.
A VXWSem::flush( ) on a counting semaphore atomically unblocks all pended tasks in the semaphore queue. Thus, all tasks are made ready before any task actually executes. The count of the semaphore remains unchanged.
Counting semaphores may be given but not taken from interrupt level.
There is no mechanism to give back or reclaim semaphores automatically when tasks are suspended or deleted. Such a mechanism, though desirable, is not currently feasible. Without explicit knowledge of the state of the guarded resource or region, reckless automatic reclamation of a semaphore could leave the resource in a partial state. Thus, if a task ceases execution unexpectedly, as with a bus error, currently owned semaphores are not given back, effectively leaving a resource permanently unavailable. The mutual-exclusion semaphores provided by VXWMSem offer protection from unexpected task deletion.
N/A
VXWBSem::VXWBSem( ) - create and initialize a binary semaphore
VXWBSem ( int opts, SEM_B_STATE iState )
This routine allocates and initializes a binary semaphore. The semaphore is initialized to the state iState: either SEM_FULL (1) or SEM_EMPTY (0).
The opts parameter specifies the queuing style for blocked tasks. Tasks can be queued on a priority basis or a first-in-first-out basis. These options are SEM_Q_PRIORITY and SEM_Q_FIFO, respectively.
Binary semaphores are the most versatile, efficient, and conceptually simple type of semaphore. They can be used to: (1) control mutually exclusive access to shared devices or data structures, or (2) synchronize multiple tasks, or task-level and interrupt-level processes. Binary semaphores form the foundation of numerous VxWorks facilities.
A binary semaphore can be viewed as a cell in memory whose contents are in one of two states, full or empty. When a task takes a binary semaphore, using VXWSem::take( ), subsequent action depends on the state of the semaphore:
- (1)
- If the semaphore is full, the semaphore is made empty, and the calling task continues executing.
- (2)
- If the semaphore is empty, the task is blocked, pending the availability of the semaphore. If a timeout is specified and the timeout expires, the pended task is removed from the queue of pended tasks and enters the ready state with an ERROR status. A pended task is ineligible for CPU allocation. Any number of tasks may be pended simultaneously on the same binary semaphore.
When a task gives a binary semaphore, using VXWSem::give( ), the next available task in the pend queue is unblocked. If no task is pending on this semaphore, the semaphore becomes full. Note that if a semaphore is given, and a task is unblocked that is of higher priority than the task that called VXWSem::give( ), the unblocked task preempts the calling task.
To use a binary semaphore as a means of mutual exclusion, first create it with an initial state of full.
Then guard a critical section or resource by taking the semaphore with VXWSem::take( ), and exit the section or release the resource by giving the semaphore with VXWSem::give( ).
While there is no restriction on the same semaphore being given, taken, or flushed by multiple tasks, it is important to ensure the proper functionality of the mutual-exclusion construct. While there is no danger in any number of processes taking a semaphore, the giving of a semaphore should be more carefully controlled. If a semaphore is given by a task that did not take it, mutual exclusion could be lost.
To use a binary semaphore as a means of synchronization, create it with an initial state of empty. A task blocks by taking a semaphore at a synchronization point, and it remains blocked until the semaphore is given by another task or interrupt service routine.
Synchronization with interrupt service routines is a particularly common need. Binary semaphores can be given, but not taken, from interrupt level. Thus, a task can block at a synchronization point with VXWSem::take( ), and an interrupt service routine can unblock that task with VXWSem::give( ).
A semFlush( ) on a binary semaphore atomically unblocks all pended tasks in the semaphore queue; that is, all tasks are unblocked at once, before any actually execute.
There is no mechanism to give back or reclaim semaphores automatically when tasks are suspended or deleted. Such a mechanism, though desirable, is not currently feasible. Without explicit knowledge of the state of the guarded resource or region, reckless automatic reclamation of a semaphore could leave the resource in a partial state. Thus, if a task ceases execution unexpectedly, as with a bus error, currently owned semaphores will not be given back, effectively leaving a resource permanently unavailable. The mutual-exclusion semaphores provided by VXWMSem offer protection from unexpected task deletion.
N/A
VXWMSem::VXWMSem( ) - create and initialize a mutual-exclusion semaphore
VXWMSem ( int opts )
This routine allocates and initializes a mutual-exclusion semaphore. The semaphore state is initialized to full.
Semaphore options include the following:
- SEM_Q_PRIORITY
- Queue pended tasks on the basis of their priority.
- SEM_Q_FIFO
- Queue pended tasks on a first-in-first-out basis.
- SEM_DELETE_SAFE
- Protect a task that owns the semaphore from unexpected deletion. This option enables an implicit taskSafe( ) for each VXWSem::take( ), and an implicit taskUnsafe( ) for each VXWSem::give( ).
- SEM_INVERSION_SAFE
- Protect the system from priority inversion. With this option, the task owning the semaphore executes at the highest priority of the tasks pended on the semaphore, if that is higher than its current priority. This option must be accompanied by the SEM_Q_PRIORITY queuing mode.
Mutual-exclusion semaphores offer convenient options suited for situations that require mutually exclusive access to resources. Typical applications include sharing devices and protecting data structures. Mutual-exclusion semaphores are used by many higher-level VxWorks facilities.
The mutual-exclusion semaphore is a specialized version of the binary semaphore, designed to address issues inherent in mutual exclusion, such as recursive access to resources, priority inversion, and deletion safety. The fundamental behavior of the mutual-exclusion semaphore is identical to the binary semaphore as described for VXWBSem::VXWBSem( ), except for the following restrictions:
- It can only be used for mutual exclusion.
- It can only be given by the task that took it.
- It may not be taken or given from interrupt level.
- The VXWSem::flush( ) operation is illegal.
These last two operations have no meaning in mutual-exclusion situations.
A special feature of the mutual-exclusion semaphore is that it may be taken "recursively;" that is, it can be taken more than once by the task that owns it before finally being released. Recursion is useful for a set of routines that need mutually exclusive access to a resource, but may need to call each other.
Recursion is possible because the system keeps track of which task currently owns a mutual-exclusion semaphore. Before being released, a mutual-exclusion semaphore taken recursively must be given the same number of times it has been taken; this is tracked by means of a count which increments with each VXWSem::take( ) and decrements with each VXWSem::give( ).
If the option SEM_INVERSION_SAFE is selected, the library adopts a priority-inheritance protocol to resolve potential occurrences of "priority inversion," a problem stemming from the use semaphores for mutual exclusion. Priority inversion arises when a higher-priority task is forced to wait an indefinite period of time for the completion of a lower-priority task.
Consider the following scenario: T1, T2, and T3 are tasks of high, medium, and low priority, respectively. T3 has acquired some resource by taking its associated semaphore. When T1 preempts T3 and contends for the resource by taking the same semaphore, it becomes blocked. If we could be assured that T1 would be blocked no longer than the time it normally takes T3 to finish with the resource, the situation would not be problematic. However, the low-priority task is vulnerable to preemption by medium-priority tasks; a preempting task, T2, could inhibit T3 from relinquishing the resource. This condition could persist, blocking T1 for an indefinite period of time.
The priority-inheritance protocol solves the problem of priority inversion by elevating the priority of T3 to the priority of T1 during the time T1 is blocked on T3. This protects T3, and indirectly T1, from preemption by T2. Stated more generally, the priority-inheritance protocol assures that a task which owns a resource executes at the priority of the highest priority task blocked on that resource. When execution is complete, the task gives up the resource and returns to its normal, or standard, priority. Hence, the "inheriting" task is protected from preemption by any intermediate-priority tasks.
The priority-inheritance protocol also takes into consideration a task's ownership of more than one mutual-exclusion semaphore at a time. Such a task will execute at the priority of the highest priority task blocked on any of the resources it owns. The task returns to its normal priority only after relinquishing all of its mutual-exclusion semaphores that have the inversion-safety option enabled.
The VXWSem::~VXWSem( ) destructor terminates a semaphore and deallocates any associated memory. The deletion of a semaphore unblocks tasks pended on that semaphore; the routines which were pended return ERROR. Take special care when deleting mutual-exclusion semaphores to avoid deleting a semaphore out from under a task that already owns (has taken) that semaphore. Applications should adopt the protocol of only deleting semaphores that the deleting task owns.
If the option SEM_DELETE_SAFE is selected, the task owning the semaphore is protected from deletion as long as it owns the semaphore. This solves another problem endemic to mutual exclusion. Deleting a task executing in a critical region can be catastrophic. The resource could be left in a corrupted state and the semaphore guarding the resource would be unavailable, effectively shutting off all access to the resource.
As discussed in taskLib, the primitives taskSafe( ) and taskUnsafe( ) offer one solution, but as this type of protection goes hand in hand with mutual exclusion, the mutual-exclusion semaphore provides the option SEM_DELETE_SAFE, which enables an implicit taskSafe( ) with each VXWSem::take( ), and a taskUnsafe( ) with each VXWSem::give( ). This convenience is also more efficient, as the resulting code requires fewer entrances to the kernel.
There is no mechanism to give back or reclaim semaphores automatically when tasks are suspended or deleted. Such a mechanism, though desirable, is not currently feasible. Without explicit knowledge of the state of the guarded resource or region, reckless automatic reclamation of a semaphore could leave the resource in a partial state. Thus if a task ceases execution unexpectedly, as with a bus error, currently owned semaphores will not be given back, effectively leaving a resource permanently unavailable. The SEM_DELETE_SAFE option partially protects an application, to the extent that unexpected deletions will be deferred until the resource is released.
N/A
VXWSem, taskSafe( ), taskUnsafe( )
VXWMSem::giveForce( ) - give a mutual-exclusion semaphore without restrictions
STATUS giveForce ()
This routine gives a mutual-exclusion semaphore, regardless of semaphore ownership. It is intended as a debugging aid only.
The routine is particularly useful when a task dies while holding some mutual-exclusion semaphore, because the semaphore can be resurrected. The routine gives the semaphore to the next task in the pend queue, or makes the semaphore full if no tasks are pending. In effect, execution continues as if the task owning the semaphore had actually given the semaphore.
Use this routine should only as a debugging aid, when the condition of the semaphore is known.
OK.
VXWSem::give( )