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
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.
- OpenVMS VAX 7.2
- OpenVMS Alpha 7.3-2 (tested to 8.4)
- OpenVMS IA64 8.2-1 (tested to 8.4)
- OpenVMS X86 V9.2
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:
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
- The calling process has SYSLCK privilege or
- 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:
- 01:00 (1 hour)
- 00:01:00 (1 minute)
- 1 02:00:00 (1 day and 2 hours)