lock_management(3K) DG/UX 5.4R3.00 lock_management(3K)
NAME
lockmanagement: lminitializesequencedlock,
lminitializeunsequencedlock, lmobtainsequencedlock,
lmobtainsequencedlocknowait, lmobtainunsequencedlock,
lmobtainunsequencedlocknowait, lmreleasesequencedlock,
lmreleaseunsequencedlock, miscobtainspinlock,
miscreleasespinlock - implement locks on critical sections of data
SYNOPSIS
#include "/usr/src/uts/aviion/ii/ilm.h"
void lminitializesequencedlock (lockptr)
lmsequencedlockptrtype lockptr; /*WRITE ONLY*/
void lminitializeunsequencedlock (lockptr)
lmunsequencedlockptrtype lockptr; /*WRITE ONLY*/
void lmobtainsequencedlock (lockptr)
lmsequencedlockptrtype lockptr; /*WRITE ONLY*/
booleantype lmobtainsequencedlocknowait (lockptr)
lmsequencedlockptrtype lockptr; /*READ/WRITE*/
void lmobtainunsequencedlock(lockptr)
lmunsequencedlockptrtype lockptr; /*WRITE ONLY*/
booleantype lmobtainunsequencedlocknowait (lockptr)
lmunsequencedlockptrtype lockptr; /*READ/WRITE*/
void lmreleasesequencedlock(lockptr)
lmsequencedlockptrtype lockptr; /*WRITE ONLY*/
void lmreleaseunsequencedlock(lockptr)
lmunsequencedlockptrtype lockptr; /*WRITE ONLY*/
#include "/usr/src/uts/aviion/ii/imisc.h"
void miscobtainspinlock (lockptr)
miscspinlockptrtype lockptr; /*READ/WRITE*/
void miscreleasespinlock (lockptr)
miscspinlockptrtype lockptr; /*READ/WRITE*/
where:
lockptr Pointer to lock to be initialized, obtained, or released.
DESCRIPTION
The following routines are described in this man page:
lminitializesequencedlock Initialize a sequenced lock
lminitializeunsequencedlock Initialize an unsequenced lock
lmobtainsequencedlock Obtain a sequenced lock
lmobtainsequencedlocknowait Get sequenced lock, if available
lmobtainunsequencedlock Obtain an unsequenced lock
lmobtainunsequencedlocknowait Get unsequenced lock, if available
Licensed material--property of copyright holder(s) 1
lock_management(3K) DG/UX 5.4R3.00 lock_management(3K)
lmreleasesequencedlock Release a sequenced lock
lmreleaseunsequencedlock Release an unsequenced lock
miscobtainspinlock Obtain a spin lock
miscreleasespinlock Release a spin lock
Overview to Using Locks on the DG/UX System
The kernel lock facilities are used to protect critical sections of
code. If more than one LWP is executing the same code and/or
accessing the same data at the same time, the data may become
corrupted. The lock facilities guarantee exclusive access to the
code or data covered by the lock while the lock-holder is executing
in that region.
Most operating systems use locking facilities. However, locking is
particularly important in the DG/UX kernel. Unlike traditional UNIX
kernels, the DG/UX kernel provides fully preemptive scheduling. This
means that a LWP might be suspended while updating a data base and
another LWP that accesses the same data might be given control. In
addition, because the DG/UX system runs in a fully symmetric
environment, you can't disable interrupts for protection as has often
been done in single-processor UNIX kernels. Such disabling only
affects one processor--other LWPs may be running on other processors.
To further enhance performance with multiple processors, the DG/UX
kernel also provides fine-grained locks that protect individual data
bases rather than the traditional approach that locks the entire
kernel data base at once.
All locks provide mutual exclusion. However, several types of locks
are available each of which provides certain additional features.
Different locks also vary in performance and in the memory required
to implement them. The three types of locks the DG/UX kernel
provides are: sequenced locks, unsequenced locks, and spin locks.
There are three routines for each type of lock: a routine to
initialize the lock; a routine to obtain the lock (start locking);
and a routine to release the lock (stop locking). Note that routine
names consist of the operation and lock type plus the kernel
subsystem (and, hence, include file) where the routine is located--
for example, lmobtainsequencedlock. Each type of lock also uses
its own corresponding data structures.
To use a lock, you first allocate space for it and then call the
appropriate initialization routine. You then call the obtain
routine. Once this call returns, you hold the lock and no other LWP
can have the lock until you call the corresponding release routine.
Sometimes someone else may already hold the lock you want when you
try to obtain it. This situation, called contention, is handled
differently depending on the type of lock involved. In fact, what
happens during contention is one of the major differences that define
the different locks. So, before discussing this situation, we'll
describe the different types of locks.
Spin locks are the simplest type of lock. They cause the caller to
loop within the call until the lock can be obtained. This looping,
Licensed material--property of copyright holder(s) 2
lock_management(3K) DG/UX 5.4R3.00 lock_management(3K)
called a "busy wait," consumes a lot of CPU resources because the LWP
continues to run on the physical processor until the lock is
available.
Spin locks are very dangerous because the potential for deadlock is
high. Obviously, to release a lock the owner of the lock must be
able to execute the release routine for that lock. If someone else
busy waits for a spin lock on the same processor that is running the
lock-owner LWP, they will tie up the processor and the lock owner
will not be able to call the release routine. This is called
deadlock.
Because of the potential for deadlock spin locks should generally be
avoided. If you must use them, you should use them only for
protecting very small critical sections of code (only a few
instructions in length). You should also make sure that the LWP
cannot lose the processor on which it is running while holding a spin
lock. This means that the LWP cannot take any action that might
require it to be removed from the processor including taking a page
fault. Thus, the lock itself must be allocated in wired memory and
you must only reference wired memory while holding the lock.
Finally, while holding a spin lock, you must also ensure that
interrupts are disabled.
The sequence to gain exclusive access to a resource protected by a
spin lock is as follows:
nkjpdisablemyinterrupts();
miscobtainspinlock(&someresourcespinlock);
.
.
miscreleasespinlock(&someresourcespinlock);
nkjpenablemyinterrupts();
You disable interrupts before attempting to gain the spin lock.
Then, if the lock is not available, it can only be because another
LWP on a different processor is holding the lock. If this happens,
your LWP, by owning its home processor, will spin until the lock
becomes available. Such busy-waiting is a major reason why spin
locks should be held only for a short time.
You will use sequenced or unsequenced locks for most locking needs.
Neither sequenced nor unsequenced locks use busy waiting; so the
holder of the lock can give up the processor. They differ in how
waiting is done.
Sequenced locks grant access on a first-come-first-serve basis. They
avoid the scheduling overhead by ordering contending LWPs based on
when they first tried to obtain the lock. When the lock is released,
only the next LWP in line is awakened.
Unsequenced locks are faster and take less space and CPU time than
sequenced locks. When you call to obtain an unsequenced lock, the
kernel removes your LWP from the processor until the lock is
available (that is, when the current owner releases it). They
Licensed material--property of copyright holder(s) 3
lock_management(3K) DG/UX 5.4R3.00 lock_management(3K)
provide no ordering of requesters.
Unsequenced locks, however, may not perform well under high
contention, because they can cause a cascade of rescheduling. When
the lock is released, ALL the LWPs waiting on the lock are awakened
(made runnable again). At some point after they start running, they
will attempt to obtain the lock again. One of them will be first and
will succeed in obtaining the lock. The rest will find the lock
already locked and will be put back to sleep until the new owner
releases the lock and the sequence of events repeats itself. The
resulting cascade of awakenings and reschedulings creates a high cost
in system time.
Unsequenced locks might also have a "livelock" problem. If new LWPs
are always trying to get the lock, a LWP might recurrently fail to
obtain the lock, and thus wait a long time to make forward progress.
The LWP would not be dead, but would essentially be looping trying
but failing to get the lock and continue.
Sequenced locks avoid these problems, but at a cost. The cost is in
performance (obtaining and releasing them is slower and takes more
CPU time) and space (a sequenced lock takes more space to implement).
The cost results from the queue of waiting LWPs that is associated
with a sequenced lock. When a LWP must wait on the lock, it is
entered onto the end of a FIFO queue of waiting LWPs. When the lock
is released, the system wakes up only the LWP at the head of the list
and this LWP obtains the lock.
Both sequenced and unsequenced locks provide no-wait versions of
their obtain routines that return control immediately. The no-wait
routines either return with the lock now locked on the caller's
behalf, or with an indication that the lock could not be obtained.
The no-wait version allows a LWP to handle other operations and try
to obtain the lock again later.
For a more detailed discussion of locks on the DG/UX system, see the
reference listed in the Preface of this manual.
Constants and Data Structures
This subsection describes constants and data structures defined in
the include files cited in the SYNOPSIS section and used by the
routines documented in this man page.
Try to avoid dependencies on the specifics of these structures, such
as size or location of fields, because these specifics may change in
later releases of the software. You can verify exact variable
definitions in the appropriate include file. The best way to avoid
such dependencies is to use kernel-supplied routines to manipulate
these structures.
lmsequencedlocktype
typedef struct
{
lmresourcecountertype rc;
Licensed material--property of copyright holder(s) 4
lock_management(3K) DG/UX 5.4R3.00 lock_management(3K)
} lmsequencedlocktype ;
This type is a sequenced lock. A sequenced lock may be created by
simply declaring an instance of this type. The user of the lock is
responsible for allocating the space occupied by the lock instance
and reclaiming that space when the lock is destroyed. A sequenced
lock is simply a resource counter that has an initial value of one.
lmunsequencedlocktype
typedef struct
{
...
} lmunsequencedlocktype ;
This type is an unsequenced lock. An unsequenced lock may be created
by simply declaring an instance of this type. The user of the lock
is responsible for allocating the space occupied by the lock instance
and reclaiming that space when the lock is destroyed.
miscspinlocktype
typedef bit32etype miscspinlocktype ;
This type defines a spin lock. The spin lock uses all 32 bits. The
lock is considered held when all bits are 1, and is considered not
held when all bits are zero.
lminitializesequencedlock
This routine initializes a sequenced lock. None of the obtain or
release operations should be performed on a lock until it has been
initialized by this routine.
lminitializeunsequencedlock
This routine initializes an unsequenced lock. None of the obtain or
release operations should be performed on a lock until it has been
initialized by this routine.
lmobtainsequencedlock
This routine obtains the specified lock. The calling LWP is pended
if the lock is not immediately available.
lmobtainsequencedlocknowait
This routine obtains the specified lock if it is not already held.
The calling LWP is not pended if the lock is not immediately
available. The return value indicates whether the lock was obtained.
lmobtainunsequencedlock
This routine obtains the specified lock. The calling LWP is pended
if the lock is not immediately available.
lmobtainunsequencedlocknowait
This routine obtains the specified lock if it is not already held.
The calling LWP is not pended if the lock is not immediately
available.
Licensed material--property of copyright holder(s) 5
lock_management(3K) DG/UX 5.4R3.00 lock_management(3K)
lmreleasesequencedlock
This routine releases the specified lock. If other LWPs are waiting
for the lock to become available, the next one in sequence will be
awakened.
lmreleaseunsequencedlock
This routine releases the specified lock. If other LWPs are waiting
for the lock to become available, all waiting LWPs will be awakened
and one will be given the lock.
miscobtainspinlock
This routine obtains a spin lock if it is not already held. If the
lock is not immediately available, the LWP loops until it becomes
available. Spin locks are the only locks that can be obtained at
interrupt level.
miscreleasespinlock
This routine releases a spin lock.
DIAGNOSTICS
Return Value
For lmobtainsequencedlocknowait and
lmobtainunsequencedlocknowait:
TRUE The lock was obtained.
FALSE The lock was not obtained.
For the other routines: none.
Errors
None.
SEE ALSO
interruptmanagement(3K), processmanagement(3K).
Programming in the DG/UX Kernel Environment.
Licensed material--property of copyright holder(s) 6