HP OpenVMS Systems Documentation

Content starts here

OpenVMS Programming Concepts Manual


Previous Contents Index

6.6.2 Introducing Local and Common Event Flag Numbers and Event Flag Clusters

Each event flag has a unique number; event flag arguments in system service calls refer to these numbers. For example, if you specify event flag 1 in a call to the SYS$QIO system service, then event flag 1 is set when the I/O operation completes.

To allow manipulation of groups of event flags, the flags are ordered in clusters of 32 numbers corresponding to bits 0 through 31 (<31:0>) in a longword. The clusters are also numbered from 0 to 4. The range of event flag numbers encompasses the flags in all clusters: event flag 0 is the first flag in cluster 0, event flag 32 is the first flag in cluster 1, and so on.

Event flags are divided into five clusters: two for local event flags and two for common event flags. There is also a special local cluster 4 that supports EFN 128.

  • A local event flag cluster is process specific and is used to synchronize events within a process.
  • A common event flag cluster can be shared by cooperating processes in the same UIC group. A common event flag cluster is identified by name and is specific to a UIC group and VMScluster node. Before a process can use a common event flag cluster, it must explicitly "associate" with the cluster. (Association is described in Section 6.6.6.) Use them to synchronize events among images executing in different processes.
  • A special local cluster 4 supports only EFN 128, symbolically EFN$C_ENF. EFN$C_ENF is intended for use with wait form services, such as SYS$QIOW and SYS$ENQW, or SYS$SYNCH system service. However, EFN 128 can also be used with ASTs and the SYS$QIO service. By using EFN 128 with ASTs, for example, you can avoid setting event flag zero (0), which eliminates possible event flag contention in processes. The EFN 128 allows you to bypass all event flag processing in system services. Using EFN 128 also allows for faster processing.
    There is no need to reserve or free this event flag. Multiple threads of execution may concurrently use EFN$C_ENF without interference. With explicit event flag services, EFN$C_ENF behaves as if always set. For more information, see Section 6.6.4.

Table 6-4 summarizes the ranges of event flag numbers and the clusters to which they belong.

The same system services manipulate flags in either local and common event flag clusters. Because the event flag number implies the cluster number, you need not specify the cluster number when you call a system service that refers to an event flag.

When a system service requires an event flag cluster number as an argument, you need only specify the number of any event flag in the cluster. Thus, to read the event flags in cluster 1, you could specify any number in the range 32 through 63.

Table 6-4 Event Flags
Cluster Number Flag Number Type Usage
0 0 Local Default flag used by system routines.
0 1 to 23 Local May be used in system routines. When an event flag is requested, it is not returned unless it has been previously and specifically freed by calls to LIB$FREE_EF.
0 24 to 31 Local Reserved for Compaq use only.
1 32 to 63 Local Available for general use.
2 64 to 95 Common Available for general use.
3 96 to 127 Common Available for general use.
4 128 Local Available for general use without explicit allocation.

6.6.3 Using Event Flag Zero (0)

Event flag 0 is the default event flag. Whenever a process requests a system service with an event flag number argument, but does not specify a particular flag, event flag 0 is used. Therefore, event flag 0 is more likely than other event flags to be used incorrectly for multiple concurrent requests.

Code that uses any event flag should be able to tolerate spurious sets, assuming that the only real danger is a spurious clear that causes a thread to miss an event. Since any system service that uses an event flag clears the flag, there is a danger that an event which has occured but has not been responded to is masked which can result in a hang. For further information, see the SYS$SYNCH system service in OpenVMS System Services Reference Manual: GETUTC--Z.

6.6.4 Using EFN$C_ENF Local Event Flag

The combination of EFN$C_ENF and a status block should be used with the wait form of system services, or with SYS$SYNCH system service. EFN$C_ENF does not need to be initialized, nor does it need to be reserved or freed. Multiple threads of execution may concurrently use EFN$C_ENF without interference as long as they use a unique status block for each concurrent asynchronous service. When EFN$C_ENF is used with explicit event flag system services, it performs as if always set. You should use EFN$C_ENF to eliminate the chance for event flag overlap.

6.6.5 Using Local Event Flags

Local event flags are automatically available to each program. They are not automatically initialized. However, if an event flag is passed to a system service such as SYS$GETJPI, the service initializes the flag before using it.

When using local event flags, use the event flag routines as follows:

  1. To ensure that the event flag you are using is not accessed and changed by other users, allocate local event flags. The OpenVMS RTL Library (LIB$) Manual describes routines you can use to allocate an arbitrary event flag (LIB$GET_EF), and to allocate a particular event flag (LIB$RESERVE_EF) from the processwide pool of available local event flags. Similar routines do not exist for common event flags.
    The LIB$GET_EF routine by default allocates flags from event flag cluster 1 (event flags 32 through 63). Event flags 1 through 32 (in event flag cluster 0) can also optionally be allocated by calls to LIB$GET_EF. To maintain compatibility with older application software that used event flags 1 through 23 in an uncoordinated fashion, these event flags must be initially marked as free by application calls to the LIB$FREE_EF routine before these flags can be allocated by subsequent calls to the LIB$GET_EF routine.
  2. Before using the event flag, initialize it using the SYS$CLREF system service, unless you pass the event flag to a routine that clears it for you.
  3. When an event that is relevant to other program components is completed, set the event flag with the SYS$SETEF system service.
  4. A program component can read the event flag to determine what has happened and act accordingly. Use the SYS$READEF system service to read the event flag.
  5. The program components that evaluate event flag status can be placed in a wait state. Then, when the event flag is set, execution is resumed. Use the SYS$WAITFR, SYS$WFLOR, SYS$WFLAND, or SYS$SYNCH routine to accomplish this task.
  6. When a local event flag is no longer required, free it by using the LIB$FREE_EF routine.

The following Fortran example uses LIB$GET_EF to choose a local event flag and then uses SYS$CLREF to set the event flag to 0 (clear the event flag). (Note that run-time library routines require an event flag number to be passed by reference, and system services require an event flag number to be passed by value.)


INTEGER FLAG,
2       STATUS,
2       LIB$GET_EF,
2       SYS$CLREF

STATUS = LIB$GET_EF (FLAG)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
STATUS = SYS$CLREF (%VAL(FLAG))
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))

6.6.5.1 Example of Event Flag Services

Local event flags are used most commonly with other system services. For example, you can use the Set Timer (SYS$SETIMR) system service to request that an event flag be set either at a specific time of day or after a specific interval of time has passed. If you want to place a process in a wait state for a specified period of time, specify an event flag number for the SYS$SETIMR service and then use the Wait for Single Event Flag (SYS$WAITFR) system service, as shown in the C example that follows:



   .
   .
   .
main() {

        unsigned int status, daytim[1], efn=3;

/* Set the timer */
        status = SYS$SETIMR( efn,  /* efn - event flag */
                   &daytim,        /* daytim - expiration time */
                   0,              /* astadr - AST routine */
                   0,              /* reqidt - timer request id */
                   0);             /* flags */
        if ((status & 1) != 1)
                LIB$SIGNAL( status );
   .
   .
   .

/* Wait until timer expires */
        status = SYS$WAITFR( efn );
        if ((status & 1) != 1)
                LIB$SIGNAL( status );
   .
   .
   .
}


In this example, the daytim argument refers to a 64-bit time value. For details about how to obtain a time value in the proper format for input to this service, see Chapter 27.

6.6.6 Using Common Event Flags

Common event flags are manipulated like local event flags. However, before a process can use event flags in a common event flag cluster, the cluster must be created. The Associate Common Event Flag Cluster (SYS$ASCEFC) system service creates a common event flag cluster. ( Section 6.6.6.1 explains the format of this string.) By calling SYS$ASCEFC, other processes in the same UIC group can establish their association with the cluster so they can access flags in it. Each process that associates with the cluster must use the same name to refer to it; the SYS$ASCEFC system service establishes correspondence between the cluster name and the cluster number that a process assigns to the cluster.

The first program to name a common event flag cluster creates it; all flags in a newly created cluster are clear. Other processes on the same OpenVMS cluster node that have the same UIC group number as the creator of the cluster can reference the cluster by invoking SYS$ASCEFC and specifying the cluster name.

Different processes may associate the same name with different common event flag numbers; as long as the name and UIC group are the same, the processes reference the same cluster.

Common event flags act as a communication mechanism between images executing in different processes in the same group on the same OpenVMS cluster node. Common event flags are often used as a synchronization tool for other, more complicated communication techniques, such as logical names and global sections. For more information about using event flags to synchronize communication between processes, see Chapter 3.

If every cooperating process that is going to use a common event flag cluster has the necessary privilege or quota to create a cluster, the first process to call the SYS$ASCEFC system service creates the cluster.

The following example shows how a process might create a common event flag cluster named COMMON_CLUSTER and assign it a cluster number of 2:



   .
   .
   .
#include <descrip.h>
   .
   .
   .
        unsigned int status, efn=65;
        $DESCRIPTOR(name,"COMMON_CLUSTER"); /* Cluster name */
   .
   .
   .
/* Create cluster 2 */
        status = SYS$ASCEFC( efn, &name, 0, 0);




Other processes in the same group can now associate with this cluster. Those processes must use the same character string name to refer to the cluster; however, the cluster numbers they assign do not have to be the same.

6.6.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:

  1. CEF$ is prefixed to the current name string, and the result is subjected to logical name translation.
  2. 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.
  3. 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:

  1. CEF$ is prefixed to CLUS_RT.
  2. 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.6.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.6.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.6.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.

Compaq recommends that only EFN$C_ENF be used for concurrent use of event flags.

6.6.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();
   .
   .
   .


Previous Next Contents Index