|
|
|
ef_util
- Event Flag UtilitiesThe functions in this file implement VMS-like event flags under VxWorks. Applications can
An event flag cluster can be accessed by any task on a CPU; when the utilities are built with the "VxMP" CPP symbol defined, clusters can be shared across CPUs.
Event flag clusters are implemented by storing the name of the cluster in the named object database (which is implemented using the system symbol table or the VxMP shared name database). The value of the named object is the address of a cluster structure allocated on the heap (or from shared memory under VxMP). The cluster structure contains an N-bit long word whose bits represent event flags 0 through N-1 of the cluster. The structure also contains the IDs of two semaphores (shared under VxMP): a mutual exclusion semaphore used to prevent multiple tasks from modifying the event flags at the same time, and a change semaphore used to signal waiting tasks that the state of the event flags has changed.
Before accessing the event flags in a cluster, a task must "create" the cluster:
#include "ef_util.h" -- Event flag definitions. EfCluster cluster ; ... ef_create ("name", 0, debug, &cluster) ;
The first task to call ef_create()
actually creates the
cluster; later tasks simply "attach" to the cluster. To guard against name
conflicts, the cluster name has _efc
appended to it before
being entered into the named object database.
Event flags can be set or reset by calling ef_change()
. For
example, the following call simultaneously sets event flags 2 and 4 and
clears event flags 3 and 5:
long flags = 0x0000003C ; long state = 0x00000014 ; ... ef_change (cluster, flags, state) ;
Alternatively, you can use the macros ef_set()
and
ef_clear
(defined in ef_util.h
):
ef_set (cluster, 0x00000014) ; -- Set event flags 2 and 4. ef_clear (cluster, 0x00000028) ; -- Clear event flags 3 and 5.
The current state of the events flags in a cluster can be polled with the
ef_read()
function. The following example tests if event flag
2 is set and 3 is clear:
long state ; ... ef_read (cluster, &state) ; if ((state & 0x00000004) && -- Event flag 2 is set? !(state & 0x00000008)) -- Event flag 3 is clear? ...
There are two means of waiting on event flags. First, a task can wait for all of the selected event flags to reach the desired states. In the following example, the task waits for event flags 2 and 4 to be set and event flags 3 and 5 to be clear:
long flags = 0x0000003C ; long state = 0x00000014 ; ... ef_wait_all (cluster, flags, state, -1.0) ;
Second, a task can wait for any of the selected event flags to reach their desired states. For example, the following call suspends its task until event flag 2 or 4 is set or event flag 3 or 5 is clear:
long flags = 0x0000003C ; long state = 0x00000014 ; ... ef_wait_any (cluster, flags, state, -1.0) ;
The event flag waits are implemented by suspending the task on the cluster's change semaphore. Whenever the event flags are modified, the change semaphore is flushed, awakening any task waiting on the event flags in the cluster. These tasks then check the state of the flags; if the flags are not yet in the desired state, the tasks suspend on the semaphore again.
When a task terminates, it should "delete" the cluster:
ef_delete (cluster) ;
The cluster isn't actually deleted from the system until the last process using it deletes it.
Richard Neitzel of the National Center for Atmospheric Research wrote a C++ class (available in the VxWorks archive there) that uses somewhat the same approach to implementing event flags.
There is a possible timing problem in the ef_wait_xxx()
functions. These functions check the event flags immediately before
waiting on a cluster's change semaphore. Suppose a task were interrupted
after checking the flags but before waiting on the change semaphore. If
the "signalling" task manages to change the event flags and flush any tasks
waiting on the change semaphore before the first task has a chance to
resume execution, the first task will miss the change and potentially wait
forever (if another change never comes). To catch one such "straggler",
the signalling task signals the change semaphore after flushing any pending
tasks. However, could there be more than one straggler?
The name/cluster mappings and reference counts are stored in the named
object database (see nob_util.c
).
Processes should delete all clusters before exiting; if a process exits
prematurely, the named object database could be left in an inconsistent state.
ef_change()
- modifies (sets or clears) one or more event flags in a cluster.ef_clear()
- clears one or more event flags in a cluster.ef_create()
- creates a cluster of event flags.ef_delete()
- deletes a cluster of event flags.ef_read()
- reads the current state of the event flags in a cluster.ef_set()
- sets one or more event flags in a cluster.ef_wait()
- waits for one event flag in a cluster to be set.ef_wait_all()
- waits on all of a selected group of event flags in a cluster.ef_wait_any()
- waits on any of a selected group of event flags in a cluster.ef_util.c
ef_util.h