Document revision date: 30 March 2001
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

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:

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:

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:

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

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
5841PRO_023.HTML