Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

### 7.4.2 Notification of Synchronous Completion

The lock management services provide a mechanism that allows processes to determine whether a lock request is granted synchronously, that is, if the lock is not placed on the conversion or waiting queue. This feature can be used to improve performance in applications where most locks are granted synchronously (as is normally the case).

If the flag bit LCK$M_SYNCSTS is set and a lock is granted synchronously, the status code SS$_SYNCH is returned in R0; no event flag is set, and no AST is delivered.

If the request is not completed synchronously, the success code SS$_NORMAL is returned; event flags or AST routines are handled normally (that is, the event flag is set, and the AST is delivered when the lock is granted).

### 7.4.3 Expediting Lock Requests

A request can be expedited (granted immediately) if its requested mode, when granted, does not block any currently queued requests from being granted. The LCK$M_EXPEDITE flag is specified in the SYS$ENQ operation to expedite a request. Currently, only NLMODE requests can be expedited. A request to expedite any other lock mode fails with SS$_UNSUPPORTED status.

### 7.4.4 Lock Status Block

The lock status block receives the final completion status and the lock identification, and optionally contains a lock value block (see Figure 7-4). When a request is queued, the lock identification is stored in the lock status block even if the lock has not been granted. This allows a procedure to dequeue locks that have not been granted. For more information about the Dequeue Lock Request (SYS$DEQ) system service, see Section 7.5.

Figure 7-4 Lock Status Block

The status code is placed in the lock status block either when the lock is granted or when errors occur in granting the lock.

The uses of the lock value block are described in Section 7.6.1.

### 7.4.5 Blocking ASTs

In some applications that use the lock management services, a process must know whether it is preventing another process from locking a resource. The lock management services inform processes of this through the use of blocking ASTs. When the lock prevents another lock from being granted, the blocking routine is delivered as an AST to the process. Blocking ASTs are not delivered when the state of the lock is either Conversion or Waiting.

To enable blocking ASTs, the blkast argument of the SYS$ENQ system service must contain the address of a blocking AST service routine. The astprm argument passes a parameter to the blocking AST. For more information about ASTs and AST service routines, see Chapter 8. Some uses of blocking ASTs are also described in that chapter.

### 7.4.6 Lock Conversions

Lock conversions perform three main functions:

- Maintaining a low-level lock and converting it to a higher lock mode when necessary
- Maintaining values stored in a resource lock value block (described in the following paragraphs)
- Improving performance in some applications

A procedure normally needs an exclusive (or protected write) mode lock while writing data. The procedure should not keep the resource exclusively locked all the time, however, because writing might not always be necessary. Maintaining an exclusive or protected write mode lock prevents other processes from accessing the resource. Lock conversions allow a process to request a low-level lock at first and convert the lock to a high-level lock mode (protected write mode, for example) only when it needs to write data.

Some applications of locks require the use of the lock value block. If a version number or other data is maintained in the lock value block, you need to maintain at least one lock on the resource so that the value block is not lost. In this case, processes convert their locks to null locks, rather than dequeuing them when they have finished accessing the resource.

To improve performance in some applications, all resources that might be locked are locked with null locks during initialization. You can convert the null locks to higher-level locks as needed. Usually a conversion request is faster than a new lock request because the necessary data structures have already been built. However, maintaining any lock for the life of a procedure uses system dynamic memory. Therefore, the approach of creating all necessary locks as null locks and converting them as needed improves performance at the expense of increased storage requirements.

Note If you specify the flag bit LCK$M_NOQUEUE on a lock conversion and the conversion fails, the new blocking AST address and parameter specified in the conversion request replace the blocking AST address and parameter specified in the previous SYS$ENQ request.

Queuing Lock Conversions

To perform a lock conversion, a procedure calls the SYS$ENQ system service with the flag bit LCK$M_CONVERT. Lock conversions do not use the resnam, parid, acmode, or prot argument. The lock being converted is identified by the lock identification contained in the lock status block. The following program shows a simple lock conversion. Note that the lock must be granted before it can be converted.

    #include <stdio.h>
    #include <descrip.h>
    #include <lckdef.h>

    /* Declare a lock status block */

    struct lock_blk {
                    unsigned short lkstat, reserved;
                    unsigned int lock_id;
    }lksb;

       .
       .
       .
            unsigned int status, lkmode, flags;
            $DESCRIPTOR(resource,"STRUCTURE_1");
       .
       .
       .
            lkmode = LCK$K_NLMODE;

    /* Queue a request for protected read mode lock */
            status = SYS$ENQW(0,    /* efn - event flag */
                      lkmode,       /* lkmode - lock mode */
                      &lksb,        /* lksb - lock status block */
                      0,            /* flags */
                       &resource,   /* resnam - name of resource */
                      0, 0, 0, 0, 0, 0);
       .
       .
       .
            lkmode = LCK$K_PWMODE;
            flags = LCK$M_CONVERT;

    /* Queue a request for protected write mode lock */
            status = SYS$ENQW(0,     /* efn - event flag */
                      lkmode,        /* lkmode - lock mode */
                      &lksb,         /* lksb - lock status block */
                      flags,         /* flags */
                      0, 0, 0, 0, 0, 0, 0);
       .
       .
       .
    }

### 7.4.7 Forced Queuing of Conversions

It is possible to force certain conversions to be queued that would otherwise be granted. A conversion request with the LCK$M_QUECVT flag set is forced to wait behind any already queued conversions.

The conversion request is granted immediately if no conversions are already queued.

The QUECVT behavior is valid only for a subset of all possible conversions. Table 7-4 defines the legal set of conversion requests for LCK$M_QUECVT. Illegal conversion requests fail with SS$_BADPARAM returned.

Table 7-4 Legal QUECVT Conversions
| Lock Mode to Which Lock Is Converted
--- | ---
Lock Mode at Which Lock Is Held | NL | CR | CW | PR | PW | EX
NL | No | Yes | Yes | Yes | Yes | Yes
CR | No | No | Yes | Yes | Yes | Yes
CW | No | No | No | Yes | Yes | Yes
PR | No | No | Yes | No | Yes | Yes
PW | No | No | No | No | No | Yes
EX | No | No | No | No | No | No

Key to Lock Modes:

> NL = Null
> CR = Concurrent read
> CW = Concurrent write
> PR = Protected read
> PW = Protected write
> EX = Exclusive

### 7.4.8 Parent Locks

When a lock request is queued, you can declare a parent lock for the new lock. A lock that has a parent is called a sublock. To specify a parent lock, the lock identification of the parent lock is passed in the parid argument to the SYS$ENQ system service. A parent lock must be granted before the sublocks belonging to the parent can be granted.

The benefits of specifying parent locks are as follows:

- Low-level locks (concurrent read or concurrent write) such as files can be held at a coarse granularity; whereas high-level (protected write or exclusive mode) sublocks such as records or data items are held on resources of a finer granularity.
- Resource names are unique with each parent; parent locks are part of the resource name.

The following paragraphs describe the use of parent locks.

Assume that a number of processes need to access a database. The database can be locked at two levels: the file and individual records. For updating all the records in a file, locking the whole file and updating the records without additional locking is faster and more efficient. But for updating selected records, locking each record as it is needed is preferable.

To use parent locks in this way, all processes request locks on the file. Processes that need to update all records must request protected write or exclusive mode locks on the file. Processes that need to update individual records request concurrent write mode locks on the file and then use sublocks to lock the individual records in protected write or exclusive mode.

In this way, the processes that need to access all records can do so by locking the file, while processes that share the file can lock individual records. A number of processes can share the file-level lock at concurrent write mode while their sublocks update selected records.

On VAX systems, the number of levels of sublocks is limited by the size of the interrupt stack. If the limit is exceeded, the error status SS$_EXDEPTH is returned. The size of the interrupt stack is controlled by the SYSGEN parameter INTSTKPAGES. The default value for INTSTKPAGES allows 32 levels of sublocks. For more information about SYSGEN and INTSTKPAGES, see the OpenVMS System Manager's Manual.

On Alpha systems, the number of levels of sublocks is limited by the size of the kernel stack. If the limit is exceeded, the error status SS$_EXDEPTH is returned. The size of the kernel stack is controlled by the SYSGEN parameter KSTACKPAGES.

### 7.4.9 Lock Value Blocks

The lock value block is an optional, 16-byte extension of a lock status block. The first time a process associates a lock value block with a particular resource, the lock management services create a resource lock value block for that resource. The lock management services maintain the resource lock value block until there are no more locks on the resource.

To associate a lock value block with a resource, the process must set the flag bit LCK$M_VALBLK in calls to the SYS$ENQ system service. The lock status block lksb argument must contain the address of the lock status block for the resource.

When a process sets the flag bit LCK$M_VALBLK in a lock request (or conversion request) and the request (or conversion) is granted, the contents of the resource lock value block are written to the lock value block of the process.

When a process sets the flag bit LCK$M_VALBLK on a conversion from protected write or exclusive mode to a lower mode, the contents of the process's lock value block are stored in the resource lock value block.

In this manner, processes can pass the value in the lock value block along with the ownership of a resource.

Table 7-5 shows how lock conversions affect the contents of the process's and the resource's lock value block.

Table 7-5 Effect of Lock Conversion on Lock Value Block
| Lock Mode to Which Lock Is Converted
--- | ---
Lock Mode at Which Lock Is Held | NL | CR | CW | PR | PW | EX
NL | Return | Return | Return | Return | Return | Return
CR | Neither | Return | Return | Return | Return | Return
CW | Neither | Neither | Return | Return | Return | Return
PR | Neither | Neither | Neither | Return | Return | Return
PW | Write | Write | Write | Write | Write | Return
EX | Write | Write | Write | Write | Write | Write

Key to Lock Modes:

> NL---Null
> CR---Concurrent read
> CW---Concurrent write
> PR---Protected read
> PW---Protected write
> EX---Exclusive

Key to Effects:

> Return---The contents of the resource lock value block are returned to the lock value block of the process.
> Neither---The lock value block of the process is not written; the resource lock value block is not returned.
> Write---The contents of the process's lock value block are written to the resource lock value block.

Note that when protected write or exclusive mode locks are dequeued using the Dequeue Lock Request (SYS$DEQ) system service and the address of a lock value block is specified in the valblk argument, the contents of that lock value block are written to the resource lock value block.

## 7.5 Dequeuing Locks

When a process no longer needs a lock on a resource, you can dequeue the lock by using the Dequeue Lock Request (SYS$DEQ) system service. Dequeuing locks means that the specified lock request is removed from the queue it is in. Locks are dequeued from any queue: Granted, Waiting, or Conversion (see Section 7.2.6). When the last lock on a resource is dequeued, the lock management services delete the name of the resource from its data structures.

The four arguments to the SYS$DEQ macro (lkid, valblk, acmode, and flags) are optional. The lkid argument allows the process to specify a particular lock to be dequeued, using the lock identification returned in the lock status block.

The valblk argument contains the address of a 16-byte lock value block. If the lock being dequeued is in protected write or exclusive mode, the contents of the lock value block are stored in the lock value block associated with the resource. If the lock being dequeued is in any other mode, the lock value block is not used. The lock value block can be used only if a particular lock is being dequeued.

Three flags are available:

- LCK$M_DEQUALL---The LCK$M_DEQALL flag indicates that all locks of the access mode specified with the acmode argument and less privileged access modes are to be dequeued. The access mode is maximized with the access mode of the caller. If the flag LCK$M_DEQALL is specified, then the lkid argument must be 0 (or not specified).
- LCK$M_CANCEL---When LCK$M_CANCEL is specified, SYS$DEQ attempts to cancel a lock conversion request that was queued by SYS$ENQ. This attempt can succeed only if the lock request has not yet been granted, in which case the request is in the conversion queue. The LCK$M_CANCEL flag is ignored if the LCK$M_DEQALL flag is specified. For more information about the LCK$M_CANCEL flag, see the description of the SYS$DEQ service in the OpenVMS System Services Reference Manual.
- LCK$M_INVVALBLK---When LCK$M_INVVALBLK is specified, $DEQ marks the lock value block, which is maintained for the resource in the lock database, as invalid. See the descriptions of SYS$DEQ and SYS$ENQ in the OpenVMS System Services Reference Manual for more information about the LCK$M_INVVALBLK flag.

The following is an example of dequeuing locks:

    #include <stdio.h>
    #include <descrip.h>
    #include <lckdef.h>

    /* Declare a lock status block */

    struct lock_blk {
                    unsigned short lkstat ,reserved;
                    unsigned int lock_id;
    }lksb;

       .
       .
       .
            void read_updates();
            unsigned int status, lkmode=LCK$K_CRMODE, lkid;
            $DESCRIPTOR(resnam,"STRUCTURE_1"); /* resource */

    /* Queue a request for concurrent read mode lock */
            status = SYS$ENQW(0,          /* efn - event flag */
                            lkmode,       /* lkmode - lock mode */
                            &lksb,        /* lksb - lock status block */
                            0,            /* flags */
                            &resnam,      /* resnam - name of resource */
                            0,            /* parid - lock id of parent */
                            &read_updates,/* astadr - AST routine */
                            0, 0, 0, 0);
            if((status & 1) != 1)
                    LIB$SIGNAL(status);

       .
       .
       .
            lkid = lksb.lock_id;
            status = SYS$DEQ( lkid,        /* lkid - id of lock to be dequeued */
                           0, 0, 0);
            if((status & 1) != 1)
                    LIB$SIGNAL(status);

    }

User-mode locks are automatically dequeued when the image exits.

## 7.6 Local Buffer Caching with the Lock Management Services

The lock management services provide methods for applications to perform local buffer caching (also called distributed buffer management). Local buffer caching allows a number of processes to maintain copies of data (disk blocks, for example) in buffers local to each process and to be notified when the buffers contain invalid data because of modifications by another process. In applications where modifications are infrequent, substantial I/O can be saved by maintaining local copies of buffers. You can use either the lock value block or blocking ASTs (or both) to perform buffer caching.

### 7.6.1 Using the Lock Value Block

To support local buffer caching using the lock value block, each process maintaining a cache of buffers maintains a null mode lock on a resource that represents the current contents of each buffer. (For this discussion, assume that the buffers contain disk blocks.) The value block associated with each resource is used to contain a disk block "version number." The first time a lock is obtained on a particular disk block, the current version number of that disk block is returned in the lock value block of the process. If the contents of the buffer are cached, this version number is saved along with the buffer. To reuse the contents of the buffer, the null lock must be converted to protected read mode or exclusive mode, depending on whether the buffer is to be read or written. This conversion returns the latest version number of the disk block. The version number of the disk block is compared with the saved version number. If they are equal, the cached copy is valid. If they are not equal, a fresh copy of the disk block must be read from disk.

Whenever a procedure modifies a buffer, it writes the modified buffer to disk and then increments the version number before converting the corresponding lock to null mode. In this way, the next process that attempts to use its local copy of the same buffer finds a version number mismatch and must read the latest copy from disk rather than use its cached (now invalid) buffer.

### 7.6.2 Using Blocking ASTs

Blocking ASTs notify processes with granted locks that another process with an incompatible lock mode has been queued to access the same resource.

Blocking ASTs support local buffer caching in two ways. One technique involves deferred buffer writes; the other technique is an alternative method of local buffer caching without using value blocks.

#### 7.6.2.1 Deferring Buffer Writes

When local buffer caching is being performed, a modified buffer must be written to disk before the exclusive mode lock can be released. If a large number of modifications are expected (particularly over a short period of time), you can reduce disk I/O by both maintaining the exclusive mode lock for the entire time that the modifications are being made and by writing the buffer once. However, this prevents other processes from using the same disk block during this interval. This problem can be avoided if the process holding the exclusive mode lock has a blocking AST. The AST notifies the process if another process needs to use the same disk block. The holder of the exclusive mode lock can then write the buffer to disk and convert its lock to null mode (thereby allowing the other process to access the disk block). However, if no other process needs the same disk block, the first process can modify it many times but write it only once.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_023.HTML