 |
HP OpenVMS Programming Concepts Manual
6.8.6.1 Using the name Argument with SYS$ASCEFC
The name argument to the Associate Common Event Flag
Cluster (SYS$ASCEFC) system service identifies the cluster that the
process is creating or associating with. The name
argument specifies a descriptor pointing to a character string.
Translation of the name argument proceeds in the
following manner:
- CEF$ is prefixed to the current name string, and the result is
subjected to logical name translation.
- If the result is a logical name, step 1 is repeated until
translation does not succeed or until the number of translations
performed exceeds the number 10.
- The CEF$ prefix is stripped from the current name string that could
not be translated. This current string is the cluster name.
For example, assume that you have made the following logical name
assignment:
$ DEFINE CEF$CLUS_RT CLUS_RT_001
|
Assume also that your program contains the following statements:
#include <ssdef.h>
#include <descrip.h>
.
.
.
unsigned int status;
$DESCRIPTOR(name,"CLUS_RT"); /* Logical name of cluster */
.
.
.
status = SYS$ASCEFC(...,&name,...);
|
The following logical name translation takes place:
- CEF$ is prefixed to CLUS_RT.
- CEF$CLUS_RT is translated to CLUS_RT_001. (Further translation is
unsuccessful. When logical name translation fails, the string is passed
to the service.)
There are two exceptions to the logical name translation method
discussed in this section:
- If the name string starts with an underscore (_), the operating
system strips the underscore and considers the resultant string to be
the actual name (that is, further translation is not performed).
- If the name string is the result of a logical name translation, the
name string is checked to see whether it has the
terminal attribute. If it does, the operating system
considers the resultant string to be the actual name (that is, further
translation is not performed).
6.8.6.2 Temporary Common Event Flag Clusters
Common event flag clusters are either temporary or permanent. The
perm argument to the SYS$ASCEFC system service defines
whether the cluster is temporary or permanent.
Temporary clusters require an element of the creating process's quota
for timer queue entries (TQELM quota). They are deleted automatically
when all processes associated with the cluster have disassociated.
Disassociation can
be performed explicitly with the Disassociate Common Event Flag Cluster
(SYS$DACEFC) system service, or implicitly when the image that called
SYS$ASCEFC exits.
6.8.6.3 Permanent Common Event Flag Clusters
If you have the PRMCEB privilege, you can create a permanent common
event flag cluster (set the perm argument to 1 when
you invoke SYS$ASCEFC). A permanent event flag cluster continues to
exist until it is marked explicitly for deletion with the Delete Common
Event Flag Cluster (SYS$DLCEFC) system service (requires the PRMCEB
privilege). Once a permanent cluster is marked for deletion, it is like
a temporary cluster; when the last process that associated with the
cluster disassociates from it, the cluster is deleted.
In the following examples, the first program segment associates common
event flag cluster 3 with the name CLUSTER and then clears the second
event flag in the cluster. The second program segment associates common
event flag cluster 2 with the name CLUSTER and then sets the second
event flag in the cluster (the flag cleared by the first program
segment).
Example 1
STATUS = SYS$ASCEFC (%VAL(96),
2 'CLUSTER',,)
STATUS = SYS$CLREF (%VAL(98))
|
Example 2
STATUS = SYS$ASCEFC (%VAL(64),
2 'CLUSTER',,)
STATUS = SYS$SETEF (%VAL(66))
|
For clearer code, rather than using a specific event flag number, use
one variable to contain the bit offset you need and one variable to
contain the number of the first bit in the common event flag cluster
that you are using. To reference the common event flag, add the offset
to the number of the first bit. The following examples accomplish the
same result as the preceding two examples:
Example 1
INTEGER*4 BASE,
2 OFFSET
PARAMETER (BASE = 96)
OFFSET=2
STATUS = SYS$ASCEFC (%VAL(BASE),
2 'CLUSTER',,)
STATUS = SYS$CLREF (%VAL(BASE+OFFSET))
|
Example 2
INTEGER*4 BASE,
2 OFFSET
PARAMETER (BASE = 64)
OFFSET=2
STATUS = SYS$ASCEFC (%VAL(BASE),
2 'CLUSTER',,)
STATUS = SYS$SETEF (%VAL(BASE+OFFSET))
|
Common event flags are often used for communicating between a parent
process and a created subprocess. The following parent process
associates the name CLUSTER with a common event flag cluster, creates a
subprocess, and then waits for the subprocess to set event flag 64:
INTEGER*4 BASE,
2 OFFSET
PARAMETER (BASE = 64,
2 OFFSET = 0)
.
.
.
! Associate common event flag cluster with name
STATUS = SYS$ASCEFC (%VAL(BASE),
2 'CLUSTER',,)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
! Create subprocess to execute concurrently
MASK = IBSET (MASK,0)
STATUS = LIB$SPAWN ('RUN REPORTSUB', ! Image
2 'INPUT.DAT', ! SYS$INPUT
2 'OUTPUT.DAT', ! SYS$OUTPUT
2 MASK)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
! Wait for response from subprocess
STATUS = SYS$WAITFR (%VAL(BASE+OFFSET))
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
.
.
.
|
REPORTSUB, the program executing in the subprocess, associates the name
CLUSTER with a common event flag cluster, performs some set of
operations, sets event flag 64 (allowing the parent to continue
execution), and continues executing:
INTEGER*4 BASE,
2 OFFSET
PARAMETER (BASE = 64,
2 OFFSET = 0)
.
.
.
! Do operations necessary for
! continuation of parent process
.
.
.
! Associate common event flag cluster with name
STATUS = SYS$ASCEFC (%VAL(BASE),
2 'CLUSTER',,)
IF (.NOT. STATUS)
2 CALL LIB$SIGNAL (%VAL(STATUS))
! Set flag for parent process to resume
STATUS = SYS$SETEF (%VAL(BASE+OFFSET))
.
.
.
|
6.8.7 Wait Form Services and SYS$SYNCH
A wait form system service is a variant of an asynchronous service in
which there is a service request and then a wait for the completion of
the request. The SYS$SYNCH system service checks the completion status
of a system service that completes asynchronously. For reliable
operation in most applications, the service whose completion status is
to be checked must have been called with the efn and
iosb arguments specified. The SYS$SYNCH service uses
the event flag and I/O status block of the service to be checked.
HP recommends that only EFN$C_ENF be used for concurrent use of event
flags.
6.8.8 Event Flag Waits
The following three system services place the process or thread in a
wait state until an event flag or a group of event flags is set:
- The Wait for Single Event Flag (SYS$WAITFR) system service places
the process or thread in a wait state until a single flag has
been set.
- The Wait for Logical OR of Event Flags (SYS$WFLOR) system service
places the process or thread in a wait state until any one of
a specified group of event flags has been set.
- The Wait for Logical AND of Event Flags (SYS$WFLAND) system service
places the process or thread in a wait state until all of a
specified group of event flags have been set.
Another system service that accepts an event flag number as an argument
is the Queue I/O Request (SYS$QIO) system service. The following
example shows a program segment that issues two SYS$QIO system service
calls and uses the SYS$WFLAND system service to wait until both I/O
operations complete before it continues execution:
.
.
.
#include <lib$routines.h>
#include <starlet.h>
#include <stsdef.h>
.
.
.
unsigned int RetStat, Efn1=1, Efn2=2, EFMask; (1)
unsigned short int IOSB1[4], IOSB2[4]; (2)
unsigned int EFMask = 1L<<Efn1 | 1L<<Efn2; (3)
.
.
.
// Issue first I/O request and check for error */
RetStat = sys$qio( Efn1, Chan1, FuncCode1, IOSB1, ...)
if (!$VMS_STATUS_SUCCESS( RetStat )) (4)
lib$signal(RetStat);
// Issue second I/O request and check for error
RetStat = sys$qio( Efn2, Chan2, FuncCode2, IOSB2, ...)
if (!$VMS_STATUS_SUCCESS( RetStat ))
lib$signal(RetStat);
// Wait until both complete and check for error
RetStat = sys$wfland( Efn1, EFMask ); (5)
if (!$VMS_STATUS_SUCCESS( RetStat ))
lib$signal(status);
// Determine which asynchronous operation has completed.
// If set to zero, the particular $qio call has not completed.
if ( IOSB1[0] ) (6)
CallOneCompleted();
if ( IOSB2[0] )
CallTwoCompleted();
.
.
.
|
- The event flag argument is specified in each
SYS$QIO request. Both of these event flags are explicitly declared in
event flag cluster 0. These variables contain the event flag numbers,
and not the event flag masks.
- The I/O Status Blocks are declared. Ensure
that the storage associated with these structures is valid over the
lifetime of the asychronous call. Ensure that these structures are not
declared within the local context of a call frame of a function that
can exit before the asynchronous call completes. Be sure that these
calls are declared with static or external context, within the stack
frame of a function that will either remain active, or was located
within other non-volatile storage.
The use of either LIB$GET_EF or
EFN$C_ENF (defined in efndef.h) is strongly recommended over the static
declaration of local event flags, because the consistent use of either
of these techniques will avoid the unintended reuse of local event
flags within different parts of the same program, and the intermittent
problems that can ensue. Common event flags are somewhat less likely to
encounter similar problems due to the requirement to associate with the
cluster before use. But the use and switching of event flag clusters
and the use of event flags within each cluster should still be
carefully coordinated.
- Set up the event flag mask. Since both of
these event flags are located in the same event flag cluster, you can
use a simple OR to create the bit mask. Since these event flags are in
the same cluster, you can use them in the SYS$WSFLAND call.
- After both I/O requests are queued
successfully, the program calls the SYS$WFLAND system service to wait
until the I/O operations complete. In this service call, the
Efn1 argument can specify any event flag number within
the event flag cluster containing the event flags to be waited for,
since the argument indicates which event flag cluster is associated
with the mask. The EFMask argument specifies to wait
for flags 1 and 2.
You should specify a unique event flag and a
unique I/O status block for each asynchronous call.
- Note that the SYS$WFLAND system service (and
the other wait system services) waits for the event flag to be set; it
does not wait for the I/O operation to complete. If some other event
were to set the required event flags, the wait for event flag would
complete prematurely. Use of event flags must be coordinated carefully.
- Use the I/O status block to determine which
of the two calls have completed. The I/O status block is initialized to
zero by the SYS$QIO call, and is set to a nonzero value when the call
is completed. An event flag can be set spuriously---typically if there
is unintended sharing or reuse of event flags---and thus you should
check the I/O status block. For a mechanism that can check both the
event flag and the IOSB and thus ensure that the call has completed,
see the SYS$SYNCH system service call.
6.8.9 Setting and Clearing Event Flags
System services that use event flags clear the event flag specified in
the system service call before they queue the timer or I/O request.
This ensures that the process knows the state of the event flag. If you
are using event flags in local clusters for other purposes, be sure the
flag's initial value is what you want before you use it.
The Set Event Flag (SYS$SETEF) and Clear Event Flag (SYS$CLREF) system
services set and clear specific event flags. For example, the following
system service call clears event flag 32:
The SYS$SETEF and SYS$CLREF services return successful status codes
that indicate whether the specified flag was set or cleared when the
service was called. The caller can thus determine the previous state of
the flag, if necessary. The codes returned are SS$_WASSET and
SS$_WASCLR.
All event flags in a common event flag cluster are initially clear when
the cluster is created. Section 6.8.10 describes the creation of common
event flag clusters.
6.8.10 Example of Using a Common Event Flag Cluster
The following example shows four cooperating processes that share a
common event flag cluster. The processes are named COLUMBIA, ENDEAVOUR,
ATLANTIS, and DISCOVERY, and are all in the same UIC group.
/* **** Common Header File **** (1)
.
.
.
#define EFC0 0 // EFC 0 (Local)
#define EFC1 32 // EFC 1 (Local)
#define EFC2 64 // EFC 2 (Common)
#define EFC3 96 // EFC 3 (Common)
int Efn0 = 0, Efn1 = 1, Efn2 = 2, Efn3 = 3;
int EFMask;
$DESCRIPTOR(EFCname,"ENTERPRISE");
.
.
.
// **** Process COLUMBIA **** (2)
//
// The image running within process COLUMBIA creates a common
// event flag cluster, associating it with Cluster 2
.
.
.
RetStat = sys$ascefc(EFC2, &EFCname,...); (3)
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
.
.
.
EFMask = 1L<<Efn1 | 1L<<Efn2 | 1L<<Efn3; (4)
// Wait for the specified event flags
RetStat = sys$wfland(EFC2, EFMask); (5)
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
.
.
.
// Disassociate the event flag cluster
RetStat = sys$dacefc(EFC2); (6)
// **** Process ENDEAVOUR ****
//
// The image running within process ENDEAVOUR associates with the
// specified event flag cluster, specifically associating it with
// the common event flag cluster 3.
.
.
.
// Associate the event flag cluster, using Cluster 3
RetStat = sys$ascefc(EFC3,&EFCname,...); (7)
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
// Set the event flag, and check for errors
RetStat = sys$setef(Efn2+EFC3); (8)
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
.
.
.
RetStat = sys$dacefc(EFC3);
// **** Process ATLANTIS ****
//
// The image running within process ATLANTIS associates with the
// specified event flag cluster, specifically associating it with
// the common event flag cluster 2.
// Associate the event flag cluster, using Cluster 2
RetStat = sys$ascefc(EFC2, &EFCname);
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
// Set the event flag, and check for errors
RetStat = sys$setef(Efn2+EFC2);
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
.
.
.
retstat = sys$dacefc(EFC2);
// **** Process DISCOVERY **** (9)
// The image running within process DISCOVERY associates with the
// specified event flag cluster, specifically associating it with
// the common event flag cluster 3.
RetStat = sys$ascefc(EFC3, &EFCname);
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
// Wait for the flag, and check for errors
RetStat = sys$waitfr(Efn2+EFC3);
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
// Set event flag 2, and check for errors
RetStat = sys$setef(Efn2+EFC3);
if (!$VMS_STATUS_SUCCESS(RetStat))
lib$signal(RetStat);
.
.
.
RetStat = sys$dacefc(EFC2);
|
- Set up some common definitions used by the
various applications, including preprocessor defines for the event flag
clusters, and some variables and values for particular event flags
within the clusters.
- Assume that COLUMBIA is the first process to
issue the SYS$ASCEFC system service and therefore is the creator of the
ENTERPRISE event flag cluster. Because this is a newly created common
event flag cluster, all event flags in it are clear. COLUMBA then waits
for the specified event flags, and then exits---the process will remain
in a common event flag (CEF) wait state.
- Use bit-shifts and an OR operation to create
a bit mask from the bit numbers.
- The SYS$ASCEFC call creates the relationship
of the named event flag cluster, the specified range of common event
flags, and the process. It also creates the event flag cluster, if
necessary.
- The SYS$DACEFC call disassociates the
specified event flag cluster from the COLUMBIA process.
- In process ENDEAVOUR, the argument
EFCname in the SYS$ASCEFC system service call is a
pointer to the string descriptor containing the name to be assigned to
the event flag cluster; in this example, the cluster is named
ENTERPRISE and was created by process COLUMBIA. While COLUMBIA mapped
this cluster as cluster 2, this service call associates this name with
cluster 3, event flags 96 through 127. Cooperating processes ENDEAVOUR,
ATLANTIS, and DISCOVERY must use the same character string name to
refer to this cluster.
- The continuation of process COLUMBIA depends
on (unspecified) work done by processes ENDEAVOUR, ATLANTIS, and
DISCOVERY. The SYS$WFLAND system service call specifies a mask
indicating the event flags that must be set before process COLUMBIA can
continue. The mask in this example (binary 1110) indicates that the
second, third, and fourth flags in the cluster must be set. Process
ENDEAVOUR sets the second event flag in the event flag cluster
longword, using the SYS$SETEF system service call.
- Process ATLANTIS associates with the cluster,
but instead of referring to it as cluster 2, it refers to it as cluster
3 (with event flags in the range 96 through 127). Thus, when process
ATLANTIS sets the event flag, it must bias the flag for the particular
event flag cluster longword.
- Process DISCOVERY associates with the
cluster, waits for an event flag set by process ENDEAVOUR, and sets an
event flag itself.
6.8.11 Example of Using Event Flag Routines and Services
This section contains an example of how to use event flag services.
Common event flags are often used for communicating between a parent
process and a created subprocess. In the following example, REPORT.FOR
creates a subprocess to execute REPORTSUB.FOR, which performs a number
of operations.
After REPORTSUB.FOR performs its first operation, the two processes can
perform in parallel. REPORT.FOR and REPORTSUB.FOR use the common event
flag cluster named JESSIER to communicate.
REPORT.FOR associates the cluster name with a common event flag
cluster, creates a subprocess to execute REPORTSUB.FOR and then waits
for REPORTSUB.FOR to set the first event flag in the cluster.
REPORTSUB.FOR performs its first operation, associates the cluster name
JESSIER with a common event flag cluster, and sets the first flag. From
then on, the processes execute concurrently.
REPORT.FOR
.
.
.
! Associate common event flag cluster
STATUS = SYS$ASCEFC (%VAL(64),
2 'JESSIER',,)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
! Create subprocess to execute concurrently
MASK = IBSET (MASK,0)
STATUS = LIB$SPAWN ('RUN REPORTSUB', ! Image
2 'INPUT.DAT', ! SYS$INPUT
2 'OUTPUT.DAT', ! SYS$OUTPUT
2 MASK
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
! Wait for response from subprocess.
STATUS = SYS$WAITFR (%VAL(64))
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
.
.
.
REPORTSUB.FOR
.
.
.
! Do operations necessary for
! continuation of parent process.
.
.
.
! Associate common event flag cluster
STATUS = SYS$ASCEFC (%VAL(64),
2 'JESSIER',,)
IF (.NOT. STATUS)
2 CALL LIB$SIGNAL (%VAL(STATUS))
! Set flag for parent process to resume
STATUS = SYS$SETEF (%VAL(64))
.
.
.
|
|