Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

1. 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.
2. 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.
3. 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.
4. 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 (or of EFN$C_ENF) and a unique I/O Status Block for any asynchronous call.
5. 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.
6. 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 $qio call, and is set to non-zero 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 $synch system service call.

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

    $CLREF_S EFN=#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.6.10 describes the creation of common event flag clusters.

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

1. 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.
2. 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.
3. Use bit-shifts and an OR operation to create a bit mask from the bit numbers.
4. 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.
5. The SYS$DACEFC call disassociates the specified event flag cluster from the COLUMBIA process.
6. 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.
7. 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.
8. 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.
9. Process DISCOVERY associates with the cluster, waits for an event flag set by process ENDEAVOUR, and sets an event flag itself.

### 6.6.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))
>     .
>     .
>     .

## 6.7 Synchronizing Operations with System Services

A number of system services can be executed either synchronously or asynchronously such as the following:

- SYS$GETJPI and SYS$GETJPIW
- SYS$QIO and SYS$QIOW

The W at the end of the system service name indicates the synchronous version of the service.

The asynchronous version of a system service queues a request and immediately returns control to your program pending the completion of the request. You can perform other operations while the system service executes. To avoid data corruptions, you should not attempt any read or write access to any of the buffers or itemlists referenced by the system service call prior to the completion of the asynchronous portion of the system service call. Further, no self-referential or self-modifying itemlists should be used.

Typically, you pass an event flag and an I/O status block to an asynchronous system service. When the system service completes, it sets the event flag and places the final status of the request in the I/O status block. Use the SYS$SYNCH system service to ensure that the system service has completed. You pass to SYS$SYNCH the event flag and I/O status block that you passed to the asynchronous system service; SYS$SYNCH waits for the event flag to be set and then examines the I/O status block to be sure that the system service rather than some other program set the event flag. If the I/O status block is still 0, SYS$SYNCH waits until the I/O status block is filled.

The following example shows the use of the SYS$GETJPI system service:

    ! Data structure for SYS$GETJPI
       .
       .
       .
    INTEGER*4 STATUS,
    2         FLAG,
    2         PID_VALUE
    ! I/O status block
    STRUCTURE /STATUS_BLOCK/
     INTEGER*2 JPISTATUS,
    2          LEN
     INTEGER*4 ZERO /0/
    END STRUCTURE
    RECORD /STATUS_BLOCK/ IOSTATUS
       .
       .
       .
    ! Call SYS$GETJPI and wait for information
    STATUS = LIB$GET_EF (FLAG)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
    STATUS = SYS$GETJPI (%VAL(FLAG),
    2                    PID_VALUE,
    2                    ,
    2                    NAME_BUF_LEN,
    2                    IOSTATUS,
    2                    ,)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
       .
       .
       .
    STATUS = SYS$SYNCH (%VAL(FLAG),
    2                   IOSTATUS)
    IF (.NOT. IOSTATUS.JPISTATUS) THEN
      CALL LIB$SIGNAL (%VAL(IOSTATUS.JPISTATUS))
    END IF

    END

The synchronous version of a system service acts as if you had used the asynchronous version followed immediately by a call to SYS$SYNCH; however, it behaves this way only if you specify a status block. If you omit the I/O status block, the result is as though you called the asynchronous version followed by a call to SYS$WAITFR. Regardless of whether you use the synchronous or asynchronous version of a system service, if you omit the efn argument, the service uses event flag 0.

## Chapter 7
Synchronizing Access to Resources

This chapter describes the use of the lock manager to synchronize access to shared resources and contains the following sections:

Section 7.1 describes how the lock manager synchronizes processes to a specified resource.

Section 7.2 describes the concepts of resources and locks.

Section 7.3 describes how to use the SYS$ENQ and SYS$ENQW system services to queue lock requests.

Section 7.4 describes specialized features of locking techniques.

Section 7.5 describes how to use the SYS$DEQ system service to dequeue the lock.

Section 7.6 describes how applications can perform local buffer caching.

Section 7.7 presents a code example of how to use lock management services.

## 7.1 Synchronizing Operations with the Lock Manager

Cooperating processes can use the lock manager to synchronize access to a shared resource (for example, a file, program, or device). This synchronization is accomplished by allowing processes to establish locks on named resources. All processes that access the shared resources must use the lock management services; otherwise, the resources are not effective.

Note The use of the term resource throughout this chapter means shared resource.

To synchronize access to resources, the lock management services provide a mechanism that allows processes to wait in a queue until a particular resource is available.

The lock manager does not ensure proper access to the resource; rather, the programs must respect the rules for using the lock manager. The rules required for proper synchronization to the resource are as follows:

- The resource must always be referred to by an agreed-upon name.
- Access to the resource is always accomplished by queuing a lock request with the SYS$ENQ or SYS$ENQW system service.
- All lock requests that are placed in a wait queue must wait for access to the resource.

A process can choose to lock a resource and then create a subprocess to operate on this resource. In this case, the program that created the subprocess (the parent program) should not exit until the subprocess has exited. To ensure that the parent program does not exit before the subprocess, specify an event flag to be set when the subprocess exits (use the completion-efn argument of LIB$SPAWN). Before exiting from the parent program, use SYS$WAITFR to ensure that the event flag is set. (You can suppress the logout message from the subprocess by using the SYS$DELPRC system service to delete the subprocess instead of allowing the subprocess to exit.)

Table 7-1 summarizes the lock manager services.

Table 7-1 Lock Manager Services
Routine | Description
--- | ---
SYS$ENQ(W) | Queues a new lock or lock conversion on a resource
SYS$DEQ | Releases locks and cancels lock requests
SYS$GETLKI(W) | Obtains information about the lock database

## 7.2 Concepts of Resources and Locks

A resource can be any entity on the operating system (for example, files, data structures, databases, or executable routines). When two or more processes access the same resource, you often need to control their access to the resource. You do not want to have one process reading the resource while another process writes new data, because a writer can quickly invalidate anything being read by a reader. The lock management system services allow processes to associate a name with a resource and request access to that resource. Lock modes enable processes to indicate how they want to share access with other processes.

To use the lock management system services, a process must request access to a resource (request a lock) using the Enqueue Lock Request (SYS$ENQ) system service. The following three arguments to the SYS$ENQ system service are required for new locks:

- Resource name---The lock management services use the resource name to look for other lock requests that use the same name.
- Lock mode to be associated with the requested lock---The lock mode indicates how the process wants to share the resource with other processes.
- Address of a lock status block---The lock status block receives the completion status for a lock request and the lock identification. The lock identification refers to a lock request after it has been queued.

The lock management services compare the lock mode of the newly requested lock to the mode of other locks with the same resource name. New locks are granted in the following instances:

- If no other process has a lock on the resource.
- If another process has a lock on the resource and the mode of the new request is compatible with the existing lock.
- If another process already has a lock on the resource and the mode of the new request is not compatible with the lock mode of the existing lock, the new request is placed in a queue, where it waits until the resource becomes available. When the resource becomes available, the process is notified that the lock has been granted.

Processes can also use the SYS$ENQ system service to change the lock mode of a lock. This is called a lock conversion.

### 7.2.1 Resource Granularity

Many resources can be divided into smaller parts. As long as a part of a resource can be identified by a resource name, the part can be locked. The term resource granularity describes the part of the resource being locked.

Figure 7-1 depicts a model of a database. The database is divided into areas, such as a file, which in turn are subdivided into records. The records are further divided into items.

Figure 7-1 Model Database

The processes that request locks on the database shown in Figure 7-1 may lock the whole database, an area in the database, a record, or a single item. Locking the entire database is considered locking at a coarse granularity; locking a single item is considered locking at a fine granularity.

In this example, overall access to the database can be represented by a root resource name. Access either to areas in the database or records within areas can be represented by sublocks.

Root resources consist of the following:

- Resource domain
- Resource name
- Access mode

Subresources consist of the following:

- Parent resource
- Resource name
- Access mode

### 7.2.2 Resource Domains

Because resource names are arbitrary names chosen by applications, one application may interfere (either intentionally or unintentionally) with another application. Unintentional interference can be easily avoided by careful design, such as by using a registered facility name as a prefix for all root resource names used by an application.

Intentional interference can be prevented by using resource domains. A resource domain is a namespace for root resource names and is identified by a number. Resource domain 0 is used as a system resource domain. Usually, other resource domains are used by the UIC group corresponding to the domain number.

By using the SYS$SET_RESOURCE_DOMAIN system service, a process can gain access to any resource domain subject to normal operating system access control. By default, each resource domain allows read, write, and lock access by members of the corresponding UIC group. See the OpenVMS Guide to System Security for more information about access control.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_021.HTML