Superlock

Superlock


Version 3.1

Superlock is a program to call the lock manager from DCL. It allows the user to synchronize commands in command procedures in the same way that the $ENQ/$DEQ system services synchronize program code. It does this by acquiring and releasing locks in Supervisor mode (hence the name). Supervisor mode locks remain granted after image rundown, and are only released either by explicit calls to Superlock, or when the process runs down.


2023-11-29 The information in this document is subject to change without notice and should not be construed as a commitment by anyone.

The software described in this document is provided as is. No guarantee is made to the suitability, reliability, security, usefulness, performance or good taste of this software.

No liability is accepted for any use or misuse of the product. Superlock may be distributed provided no alteration is made to the copyright notice in this documentation or in program sources. All rights are reserved.

Copyright ©2023 Tom Wade

Contents


Chapter 1
Introduction

1.1 Purpose of Superlock

When writing programs in a high level language, the programmer can make use of calls to the $ENQ and $DEQ system services. These services interface with the Distributed Lock Manager, a cluster wide service which acquires locks, allowing the programmer to control concurrent access to resources or critical sections of code. Normally, such locks are granted in User Mode, which means when the program exits, all such locks are released.

For this sort of coordination to be provided within DCL command files, the lock acquired by Superlock program must continue to be held after that program exits. By acquiring the lock in Supervisor mode, the lock remains granted until either the process exits, or a subsequent call to Superlock releases the lock.

1.2 Requisite Platforms

Superlock will run on the following operating system versions. It should run on later versions of each of the above, and may also run on earlier versions (although it may require that the program be rebuilt or at least relinked from the supplied sources).

1.3 Installing Superlock

The kit is normally distributed as a ZIP archive. UNZIPping this archive will produce a kit that is installed using the VMSINSTAL facility. This will ask you to specify a target directory into which it will restore the sources and the three image files (the installation procedure creates a separate subdirectory for each architecture). Optionally, full sources and documentation are also installed in subdirectories.

1.3.1 Building the program

The kit ships with EXE files created on the above listed versions of OpenVMS. If you wish to rebuild from the sources, then issue the following command:


 
 $ @BUILD 
This will compile and link the code for your platform. Note that you need a Fortran compiler to perform the compilation step.

1.3.2 Installing the image

In order to request a lock in Supervisor mode, the program must be running in Supervisor mode (or in a more privileged mode). Programs normally run in User mode, and you can't acquire a Supervisor mode lock from User mode. Since VMS does not provide a Change Mode to Supervisor service, Superlock changes to Executive mode to request the lock. As users won't normally have CMEXEC privileges (and you shouldn't give it to them) the program must be installed with CMEXEC privileges in order to work. You may wish to look through the source code to satisfy yourself that the program only uses Executive mode to issue the lock request. In addition, you have the option of installing the image with SYSLCK privilege. This privilege is required to acquire locks that can be shared by processes outside the same UIC group. Normally, users won't have this privilege (and although this is a less risky privilege than CMEXEC, you shouldn't hand it out to ordinary users). If you don't install with this privilege, Superlock will still work, however all coordination to a given lock resource will only be possible for users within a given UIC group. Superlock only uses SYSLCK privilege to set the LCK$M_SYSTEM bit on the lock flags. You can also install the program with the /OPEN /HEADER attributes for performance reasons.

Note

Version 3 supplies a SUPERLOCK_STARTUP.COM file which installs the appropriate image with CMEXEC and SYSLCK, and defines the logical name for the interactive help library. You can modify this file if you wish. You can place a call to this file in the SYSTARTUP_VMS.COM file.


Chapter 2
Using Superlock

To use Superlock, you need to define a foreign command to activate the image appropriate to your architecture. Typically a foreign command (such as LOCK) is defined to do this.

Note

V3.0 supplies a file SUPERLOCK_LOGIN.COM which defines the symbol LOCK as a foreign command activating the image appropriate to the current architecture. This procedure can be called from the SYS$SYLOGIN, the user's LOGIN.COM or as part of your site specific login setup procedures.

2.1 A simple Lock Example

Suppose you have a command procedure which can be run by many users. It is important that a series of critical commands within the procedure be only executed by only one user at a time. We choose a lock name (the actual name is totally arbitrary) to control this access. Your command procedure would look something like:


 
 $ Set Noon 
 $ @SYS$SYSDEVICE:[SUPERLOCK]SUPERLOCK_LOGIN 
 $ 
 $ (various DCL commands which can be run concurrently if needed) 
 $ 
 $ Lock /system /write /id=lock_id MYLOCK 
 $ (section of critical commands) 
 $ Lock /release /id=lock_id 
 $   (remainder of commands that can be run concurrently). 
In the above example, when the first user executes the 1st lock command, he is granted exclusive write access to the lock (since he is the first, nobody else has it). The DCL symbol LOCK_ID is created by the program and set to the value of the lock. This symbol is used by later LOCK commands to refer to an already created lock. While the first user is executing commands in the critical section, assume a second user reaches the 1st LOCK command. This time the Superlock program detects that the lock is already acquired, and the program waits. When the first user reaches the 2nd LOCK command and releases the lock, the second user is then granted it, and Superlock exits allowing him to execute the critical section. Thus at most, only one user can be executing commands in the critical section. If any of the processes terminate abnormally, all Supervisor mode locks that it holds are released automatically. Note that the /WRITE qualifier is required (see below for a description of lock modes).

Note

Although standard DCL doesn't have a LOCK command, it does have an UNLOCK command, which relates to older file system locking that doesn't use the Distributed Lock Manager. For this reason, Superlock defined a LOCK command to acquire a lock, and uses LOCK/RELEASE to release it, so as not to interfere with an existing command. UNLOCK is now regarded as obsolete (replaced by SET FILE/UNLOCK) so you could consider defining the symbol UNLOCK to be LOCK/RELEASE).

2.2 Resource Name

The resource name is specified as the parameter to the LOCK command. The resource name is an alphanumeric string of between 1 and 31 characters used to identify the resource. This parameter is required when requesting a new lock, and is omitted where you are releasing or modifying a lock already held.

2.3 Lock ID

The /ID qualifier specifies a DCL symbol used to keep track of the Lock ID. The Lock ID is a 32 bit integer that identifies a lock that has been granted to the current process. If you are requesting a new lock, the lock ID is stored in the DCL symbol provided to the /ID qualifier. If you are releasing or modifying an existing lock, you must provide the /ID qualifier specifying a DCL symbol containing the value returned by a previous LOCK command.

Note

With previous versions of Superlock, if you did not specify the /ID qualifier when requesting a new lock, the lock would still be granted, but you would not be able to subsequently release the lock except by terminating the process. From V3.0 on, the /ID qualifer defaults to the symbol LOCK_ID.

2.4 System Wide Locks

By default, resource names are local to the UIC group of the process requesting the lock. If you wish to coordinate locks between processes in different UIC groups, you will need to specify the /SYSTEM qualifier. The use of this qualifier is only possible if either
  1. The calling process has SYSLCK privilege or
  2. The SUPERLOCK image is installed with SYSLCK privilege.
Note that installing the image with SYSLCK does not allow non-privileged users access to internal system locks (which are all Executive mode).

The /SYSTEM qualifier is only required when requesting a new lock; subsequent calls using the /ID qualifier do not require this qualifier.

2.5 Specifying Lock Modes

The Lock Mode specifies what degree of access you require to the lock, and what degree of concurrent access you are prepared to allow. Use the /READ /WRITE and /ALLOW qualifiers to specify lock modes. This allows you to control simultaneous access to the resource. For example, suppose your DCL scripts read and optionally create files in a directory. While you are happy to allow many users to read files at the same time, you don't want more than one user to create a file at the same time. In this case, any process wishing to read files will use a LOCK command such as:


 
 $ Lock /system /read /id=lock_id MYLOCK /allow=WRITE 
 $ (DCL commands to read files) 
 $ Lock /id=lock_id /release 
 
whereas a process wishing to modify the files will use


 
 $ Lock /system /write /id=lock_id MYLOCK /allow=READ 
 $ (DCL commands to write files) 
 $ Lock /id=lock_id /release 
 
If a number of processes wish to read, the LOCK command in the first example will all succeed. If someone then executes the LOCK /WRITE command (in the second example) he will be granted access unless another writer has already requested the lock. Note that if you replace the /ALLOW=WRITE by /ALLOW=READ in the first example, this will have a slightly different effect. In this case any number of readers may procede, but if anyone attempts to write, they will be blocked until all the readers currently holding the lock have released it. Once granted, the write then has exclusive access, and other readers have to wait until the lock has been released.

2.5.1 Default values for /ALLOW

If you request /READ access, the default for /ALLOW is READ. This is the traditional shared read lock. If you request /WRITE access, the default for /ALLOW is NONE. This is effectively an exclusive lock.

Note

Not all possible combinations are possible using this method. For access to the full range of supported lock modes, use the /MODE qualifier described below instead.

2.5.2 Null Mode

If you omit the /READ, /WRITE and /ALLOW qualifiers, you will be granted null mode access to the lock. Null mode is always granted, and should not be construed as permission to access the resource. If processes will be acquiring and releasing a lock repeatedly, it is more efficient to switch between a 'real' and null mode. It also has an impact on the preservation of the Lock Value Block (see later section).

Note

A common mistake is to omit any mode reference (/READ, /WRITE, /MODE), expecting a lock to be exclusive. The default is NULL which is always granted. While useful when you are repeatedly locking and unlocking (it is faster to modify an existing lock mode than acquire a new one), in itself it doesn't prevent any concurrent access. You need to use one of the three qualifiers to ensure any kind of exclusive access.

2.6 Alternative Method of Specifying Lock Mode

Version 3.0 of Superlock offers an alternative means of specifying the lock mode. Instead of using a combination of /READ, /WRITE and /ALLOW, you specify the /MODE qualifier, providing the exact lock mode as defined for the $ENQ system service. The various options for /MODE and their meanings are:

2.6.1 NLMODE

NLMODE is the null mode. It grants no access to the resource, but serves as a placeholder for future lock requests. Once granted (and Null mode will always be granted), you can modify the lock with subsequent Superlock commands. If processes are frequently locking and unlocking the same resource, it is more efficient to obtain Null access first. Each time you need to access the resource, you modify the lock to increase the mode, and when finished, you modify the lock mode back down to Null. A lock modification has less overhead than a lock creation or release. Null mode is the default in the absence of any explicit /MODE, /READ or /WRITE.

2.6.2 CRMODE

Concurrent read grants the caller read access, while permitting read or write access to other callers. Normally this is used when you are defining sublocks for more granular access (see the chapter on sublocks).

2.6.3 CWMODE

Concurrent write grants the caller write access, while permitting other callers read or write access. This is also normally used in conjunction with sublocks.

2.6.4 PRMODE

Protected read grants the caller read access, while permitting only read access to other callers. No write access is allowed. This is the traditional share readonly lock.

2.6.5 PWMODE

Protected write mode grants write access to the caller, while permitting read access to other callers. No other writers are allowed. This is the traditional update lock.

2.6.6 EXMODE

Exclusive mode grants the caller read and write access, and allows no access (other than NLMODE) to other callers. This is the traditional exclusive lock.

Note

/MODE is not compatible with any of /READ, /WRITE or /ALLOW. An attempt to use /MODE with any of the others results in an error message.
The following table shows what lock attempts will be granted given the mode of any currently granted locks. Column 1 indicates the type of lock requested, and the other columns indicate whether it will be granted if another lock of the specified type is already granted. For example, if you request a PRMODE lock (row 4) and a CWMODE lock is already granted (column 4) then No indicates the lock will not be granted.
Requested mode NL CR CW PR PW EX
NL Yes Yes Yes Yes Yes Yes
CR Yes Yes Yes Yes Yes No
CW Yes Yes Yes No No No
PR Yes Yes No Yes No No
PW Yes Yes No No No No
EX Yes No No No No No

2.6.7 Converting the Lock Mode

If you already have a lock, you can request a change of mode by issuing the appropriate LOCK command for the desired mode. Superlock will assume that you are requesting a new lock if you specify the resource name as the 1st parameter. If you omit this, then the /ID qualifier is required, and Superlock will enqueue a request to change to the new mode. Note that a mode change request may be blocked if others already have been granted access to the lock in a mode that would prevent your attempted access. For example:


 
 $ Lock MYLOCK /id=lock_id ! get NULL access to new lock. 
 $ Lock /id=lock_id /read ! convert to concurrent read 
 $ Lock /id=lock_id  ! revert to NULL mode 
There is far greater overhead in creating a new lock than converting an existing one. The former involves finding the master node, and building the data structures for the lock. In a lock conversion, the data structures are already created, and the master node in a cluster is known, so the operation is much quicker. Thus, if your application is repeatedly acquiring and releasing a lock on the same resource, it is more efficient to acquire the lock in Null mode (which is always granted), and then convert the lock to a more restricted mode when you need it, and revert to Null when you don't. This also allows the processes to exchange information using the Lock Value Block.

2.7 Releasing a Lock

To release a lock, simply use the /RELEASE qualifier along with the /ID qualifier.


 
 $ Lock /id=lock_id /release ! release lock already held. 
 

2.8 Waiting for a Lock

Normally, if you request a lock that is already granted, you want to wait until the lock is available before you proceed. The /WAIT qualifier indicates this, and /WAIT is the default. If you don't want to wait, you can specify /NOWAIT, and if the lock cannot be granted, Superlock will return the SS$_NOTQUEUED status. For example, suppose you wanted to enforce a limit on users whereby they could not log in cluster wide more than once interactively. You could use the /MAXJOBS qualifier in the UAF, but this would also limit batch jobs. You can achieve this by inserting the following commands in the SYS$SYLOGIN


 
 $ If F$Mode () .eqs. "INTERACTIVE"   !  interactive only. 
 $ Then 
 $  user := 'F$Getjpi ("username")' ! get username 
 $  Lock /nowait /write LOGIN_'user' ! exclusive lock 
 $ 
 $  If .not. $status ! go away 
 $  Then 
 $   Write SYS$OUTPUT "Already logged in" 
 $   Logout 
 $  EndIf 
 $ EndIf 
 
The lock will be automatically released when the process exits. Remember the lock manager operates cluster wide, so this will only allow him to login once throughout the cluster. A variation on this would be to offer the user the option of first logging out the older process with a STOP/ID command. The process ID of the blocking process can be retrieved using the /REPORT_BLOCKERS qualifier (see section below).

2.9 Executive Locks

By default, Superlock uses Supervisor mode locks. These locks remain held after the requesting image has terminated (unlike user mode locks). Superlock can also be used to request Executive mode locks, should that be required. Note that RMS and other critical system components use Executive mode locks to coordinate access to the file system, so care must be taken that you don't compromise this.

Note

Although Superlock is installed with CMEXEC privileges, it will not allow a user who does not possess CMEXEC as part of the process privilege set to request Executive mode locks.

2.10 Synchronous Return Status

If you specify the /SYNC qualifier, Superlock will return an alternative value in $status if the lock can be granted immediately. This value is SS$_SYNCH (%X689). If the lock is granted after being queued (i.e. there was a wait period), the normal SS$_NORMAL (%X01) is returned. This can be used if you need to know whether the lock was granted immediately or not.

2.11 Help Dialog

If you specify the /HELP qualifier, Superlock will enter a help dialog using the help library specified by the logical SUPERLOCK_HELP_LIBRARY (this logical is normally set by the Superlock startup command file). Once /HELP is specified, Superlock will ignore all other qualifiers, and won't enqueue or dequeue any locks. You can, if you prefer, incorporate the SUPERLOCK.HLB help file into your DCL HELP command, either by adding the contents to the SYS$HELP:HELPLIB.HLB file, or using the HLP$LIBARY logicals.

2.12 Lock Timeout

You can optionally specify a timeout period using the /TIMEOUT qualifier. If the lock has not been granted during this period, then the lock request (or conversion) is cancelled, and Superlock exits with an SS$_TIMEOUT status code. The following are examples of timeout periods:


Next Contents