Intertask and Interprocess Communication
EVENTS_INTERRUPTIBLE
Signals unpend RTP tasks that are pended on events.
7.9.2 About Event Flags and the Task Events Register
Each task has 32 event flags, bit-wise encoded in a 32-bit word (bits 25 to 32 are reserved for Wind River use), which is referred to as an event register. The event register is used to store the events that the task receives from tasks, ISRs, semaphores, and message queues.
Note that an event flag itself has no intrinsic meaning. The significance of each of the 32 event flags depends entirely on how any given task is coded to respond to a specific bit being set. There is no mechanism for recording how many times any given event has been received by a task. Once a flag has been set, its being set again by the same or a different sender is essentially an invisible operation.
A a task cannot access the contents of its events registry directly; the
eventReceive( ) routine copies the contents of the events register to the variable specified by its *pEventsReceived parameter.
The VxWorks event flag macros and values that can be used by Wind River customers are listed in Table 7-5VxWorks Event Flags, p.138.
! CAUTION: Event flags VXEV25 (0x01000000) through VXEV32 (0x80000000) are reserved for Wind River use only, and should not be used by customers.
Table 7-5 VxWorks Event Flags
Macro Value VXEV01 0x00000001 VXEV02 0x00000002 VXEV03 0x00000004 VXEV04 0x00000008 VXEV05 0x00000010 VXEV06 0x00000020 VXEV07 0x00000040 VXEV08 0x00000080 VXEV09 0x00000100 VXEV10 0x00000200 VXEV11 0x00000400 VXEV12 0x00000800 VXEV13 0x00001000 VXEV14 0x00002000 VXEV15 0x00004000
7 Intertask and Interprocess Communication 7.9 VxWorks Events
The routines that affect the contents of the events register are described in Table 7-6.
7.9.3 Receiving Events
A task can pend on one or more events, or simply check on which events have been received, with a call to eventReceive( ). Events are specified by using the value the relevant event flags for the routine’s events parameter (see 7.9.2 About Event Flags and the Task Events Register, p.138). The routine provides options for waiting for one or all of those events, as well as options for how to manage unsolicited events, and for checking which events have been received prior to the full set being received.
When the events specified with an eventReceive( ) call have been received and the VXEV16 0x00008000
VXEV17 0x00010000 VXEV18 0x00020000 VXEV19 0x00040000 VXEV20 0x00080000 VXEV21 0x00100000 VXEV22 0x00200000 VXEV23 0x00400000 VXEV24 0x00800000
Table 7-5 VxWorks Event Flags Macro Value
Table 7-6 Routines That Modify the Task Events Register
Routine Effect on the Task Events Register
eventReceive( ) Clears or leaves the contents of the task’s events register intact, depending on the options selected.
eventClear( ) Clears the contents of the task’s events register.
eventSend( ) Writes events to a tasks’s events register.
semGive( ) Writes events to the tasks’s events register, if the task is registered with the semaphore.
msgQSend( ) Writes events to a task’s events register, if the task is registered with the message queue.
receives—the contents of the events variable can be checked to determine which event caused the task to unpend.
Additional Steps for Receiving Events from Semaphores and Message Queues
In order for a task to receive events when a semaphore or a message queue is free (as opposed to simply another task), it must first register with the specific object, using semEvStart( ) for a semaphore or msgQEvStart( ) for a message queue. Only one task can be registered with any given semaphore or message queue at a time.
The semEvStart( ) routine identifies the semaphore and the events that should be sent to the task when the semaphore is free. It also provides a set of options to specify whether the events are sent only the first time the semaphore is free, or each time; whether to send events if the semaphore is free at the time of registration; and whether a subsequent semEvStart( ) call from another task is allowed to take effect (and to unregister the previously registered task).
Once a task has registered with a semaphore, every time the semaphore is released with semGive( ), and as long as no other tasks are pending on it, events are sent to the registered task.
To request that event-sending be stopped, the registered task calls semEvStop( ).
Registration with a message queue is similar to registration with a semaphore. The msgQEvStart( ) routine identifies the message queue and the events that should be sent to the task when a message arrives and no tasks are pending on it. It provides a set of options to specify whether the events are sent only the first time a message is available, or each time; and whether a subsequent call to msgQEvStart( ) from another task is allowed to take effect (and to unregister the previously registered task).
Once a task has registered with a message queue, every time the message queue receives a message and there are no tasks pending on it, events are sent to the registered task.
To request that event-sending be stopped, the registered task calls msgQEvStop( ).
7.9.4 Sending Events
Tasks and ISRs can send specific events to a task explicitly using eventSend( ), whether or not the receiving task is prepared to make use of them. Events are specified by using the value the relevant event flags for the routine’s events parameter (see 7.9.2 About Event Flags and the Task Events Register, p.138).
Events are sent automatically to tasks that have registered for notification when semaphores and message queues are free—with semEvStart( ) or msgQEvStart( ), respectively. The conditions under which objects are free are as follows:
Mutex Semaphore
A mutex semaphore is considered free when it no longer has an owner and no task is pending on it. For example, following a call to semGive( ), events are not sent if another task is pending on a semTake( ) for the same semaphore.
Binary Semaphore
A binary semaphore is considered free when no task owns it and no task is waiting for it.
7 Intertask and Interprocess Communication 7.9 VxWorks Events
Counting Semaphore
A counting semaphore is considered free when its count is nonzero and no task is pending on it. Events cannot, therefore, be used as a mechanism to compute the number of times a semaphore is released or given.
Message Queue
A message queue is considered free when a message is present in the queue and no task is pending for the arrival of a message in that queue. Events cannot, therefore, be used as a mechanism to compute the number of messages sent to a message queue.
Note that just because an object has been released does not mean that it is free. For example, if a semaphore is given, it is released; but it is not free if another task is waiting for it at the time it is released. When two or more tasks are constantly exchanging ownership of an object, it is therefore possible that the object never becomes free, and never sends events.
Also note that when an event is sent to a task to indicate that a semaphore or message queue is free, it does not mean that the object is in any way reserved for the task. A task waiting for events from an object unpends when the resource becomes free, but the object may be taken in the interval between notification and
unpending. The object could be taken by a higher priority task if the task receiving the event was pended in eventReceive( ). Or a lower priority task might steal the object: if the task receiving the event was pended in some routine other than eventReceive( ), a low priority task could execute and (for example) perform a semTake( ) after the event is sent, but before the receiving task unpends from the blocking call. There is, therefore, no guarantee that the resource will still be available when the task subsequently attempts to take ownership of it.
Events and Object Deletion
If a semaphore or message queue is deleted while a task is waiting for events from it, the task is automatically unpended by the semDelete( ) or msgQDelete( ) implementation. This prevents the task from pending indefinitely while waiting for events from an object that has been deleted. The pending task then returns to the ready state (just as if it were pending on the semaphore itself) and receives an ERROR return value from the eventReceive( ) call that caused it to pend initially.
If, however, the object is deleted between a tasks’ registration call and its eventReceive( ) call, the task pends anyway. For example, if a semaphore is deleted while the task is between the semEvStart( ) and eventReceive( ) calls, the task pends in eventReceive( ), but the event is never sent. It is important, therefore, to use a timeout other than WAIT_FOREVER when object deletion is expected.
! WARNING: Because events cannot be reserved for an application in any way, care should be taken to ensure that events are used uniquely and unambiguously. Note that events 25 to 32 (VXEV25 to VXEV32) are reserved for Wind River’s use, and should not be used by customers. Third parties should be sure to document their use of events so that their customers do not use the same ones for their
applications.
It can, however, be useful for an application that created an object to be informed when events were not received by the (now absent) task that registered for them.
In this case, semaphores and message queues can be created with an option that causes an error to be returned if event delivery fails (the
SEM_EVENTSEND_ERROR_NOTIFY and MSG_Q_EVENTSEND_ERROR_NOTIFY options, respectively). The semGive( ) or msgQSend( ) call then returns ERROR when the object becomes free.
The error does not mean the semaphore was not given or that the message was not properly delivered. It simply means that events could not be sent to the registered task. Note that a failure to send a message or give a semaphore takes precedence over an events failure.
7.9.5 Inter-Process Communication With Events
For events to be used in inter-process communication, the objects involved in communication (tasks, semaphores, and message queues) must be public. For more information, see 7.10 Inter-Process Communication With Public Objects, p.143.
7.9.6 Events Routines
The routines used for working with events are listed in Table 7-7.
For more information about these routines, see the VxWorks API references for eventLib, semEvLib, and msgQEvLib.
7.9.7 Code Example
For a code example illustrating how events can be used, see the eventLib API reference entry.
Table 7-7 Events Routines
Routine Description
eventSend( ) Sends specified events to a task.
eventReceive( ) Pends a task until the specified events have been received. Can also be used to check what events have been received in the interim.
eventClear( ) Clears the calling task’s event register.
semEvStart( ) Registers a task to be notified of semaphore availability.
semEvStop( ) Unregisters a task that had previously registered for notification of semaphore availability.
msgQEvStart( ) Registers a task to be notified of message arrival on a message queue when no recipients are pending.
msgQEvStop( ) Unregisters a task that had previously registered for notification of message arrival on a message queue.
7 Intertask and Interprocess Communication 7.10 Inter-Process Communication With Public Objects
7.9.8 Show Routines and Events
For the purpose of debugging systems that make use of events, the taskShow, semShow, and msgQShow libraries display event information.
The taskShow library displays the following information:
■ the contents of the event register
■ the desired events
■ the options specified when eventReceive( ) was called
The semShow and msgQShow libraries display the following information:
■ the task registered to receive events
■ the events the resource is meant to send to that task
■ the options passed to semEvStart( ) or msgQEvStart( )
7.10 Inter-Process Communication With Public Objects
Kernel objects such as semaphores and message queues can be created as either private or public objects. This provides control over the scope of their
accessibility—which can be limited to a virtual memory context by defining them as private, or extended to the entire system by defining them as public. Public objects are visible from all processes and the kernel, and can therefore be used for interprocess (and kernel-process) communication. There is no difference in performance between a public and a private object.
An object can only be defined as public or private when it is created—the designation cannot be changed thereafter. Public objects must be named when they are created, and the name must begin with a forward slash; for example, /foo.
Private objects do not need to be named.
For information about naming tasks in addition to that provided in this section, see 6.5.2 Task Names and IDs, p.96.
Creating and Naming Public and Private Objects
Public objects are always named, and the name must begin with a forward-slash.
Private objects can be named or unnamed. If they are named, the name must not begin with a forward-slash.
Only one public object of a given class and name can be created. That is, there can be only one public semaphore with the name /foo. But there may be a public semaphore named /foo and a public message queue named /foo. Obviously, more distinctive naming is preferable (such as /fooSem and /fooMQ).
The system allows creation of only one private object of a given class and name in
■ However, process B could create a private semaphore named bar, as long as it did not already own one with that same name.
Note that private tasks are an exception to this rule—duplicate names are permitted for private tasks; see 6.5.2 Task Names and IDs, p.96.
To create a named object, the appropriate xyzOpen( ) API must be used, such as semOpen( ). When the routine specifies a name that starts with a forward slash, the object will be public.
To delete public objects, the xyzDelete( ) API cannot be used (it can only be used with private objects). Instead, the xyzClose( ) and xyzUnlink( ) APIs must be used in accordance with the POSIX standard. That is, they must be unlinked from the name space, and then the last close operation will delete the object (for example, using the semUnlink( ) and semClose( ) APIs for a public semaphore).
Alternatively, all close operations can be performed first, and then the unlink operation, after which the object is deleted. Note that if an object is created with the OM_DELETE_ON_LAST_CLOSE flag, it is be deleted with the last close operation, regardless of whether or not it was unlinked.
For detailed information about the APIs used to created public kernel objects, see the msgQOpen, semOpen, taskOpen, and timerOpen entries in the VxWorks Kernel API Reference.
7.11 Object Ownership and Resource Reclamation
All objects (such as semaphores) are owned by the process to which the creator task belongs, or by the kernel if the creator task is a kernel task. When ownership must be changed, for example on a process creation hook, the objOwnerSet( ) can be used. However, its use is restricted—the new owner must be a process or the kernel.
All objects that are owned by a process are automatically destroyed when the process dies.
All objects that are children of another object are automatically destroyed when the parent object is destroyed.
Processes can share public objects through an object lookup-by-name capability (with the xyzOpen( ) set of routines). Sharing objects between processes can only be done by name.
When a process terminates, all the private objects that it owns are deleted, regardless of whether or not they are named. All references to public objects in the process are closed (an xyzClose( ) operation is performed). Therefore, any public object is deleted during resource reclamation, regardless of which process created them, if there are no more outstanding xyzOpen( ) calls against it (that is, no other process or the kernel has a reference to it), and the object was already unlinked or was created with the OM_DELETE_ON_LAST_CLOSE option. The exception to this rule is tasks, which are always reclaimed when its creator process dies.
When the creator process of a public object dies, but the object survives because it hasn't been unlinked or because another process has a reference to it, ownership of the object is assigned to the kernel.
7 Intertask and Interprocess Communication 7.11 Object Ownership and Resource Reclamation
The objShowAll( ) show routine can be used to display information about ownership relations between objects.