HP OpenVMS Systems Documentation
OpenVMS Programming Concepts Manual
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).
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
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.
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.
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.
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.
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.
Key to Lock Modes:
NL = Null
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.
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.
Key to Lock Modes:
Key to Effects:
Return---The contents of the resource lock value block are returned to the lock value block of the process.
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.
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:
User-mode locks are automatically dequeued when the image exits.
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.
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.
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.
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.