Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

interrupt_management(3K)

process_management(3K)



lock_management(3K)            DG/UX R4.11MU05           lock_management(3K)


NAME
       lock_management: lm_initialize_sequenced_lock,
       lm_initialize_unsequenced_lock, lm_obtain_sequenced_lock,
       lm_obtain_sequenced_lock_no_wait, lm_obtain_unsequenced_lock,
       lm_obtain_unsequenced_lock_no_wait, lm_release_sequenced_lock,
       lm_release_unsequenced_lock, misc_obtain_spin_lock,
       misc_release_spin_lock - implement locks on critical sections of data

SYNOPSIS
       #include "/usr/src/uts/aviion/ii/i_lm.h"

       void          lm_initialize_sequenced_lock (lock_ptr)
       lm_sequenced_lock_ptr_type    lock_ptr;   /*WRITE ONLY*/

       void          lm_initialize_unsequenced_lock (lock_ptr)
       lm_unsequenced_lock_ptr_type  lock_ptr;   /*WRITE ONLY*/

       void          lm_obtain_sequenced_lock (lock_ptr)
       lm_sequenced_lock_ptr_type    lock_ptr;   /*WRITE ONLY*/

       boolean_type  lm_obtain_sequenced_lock_no_wait (lock_ptr)
       lm_sequenced_lock_ptr_type    lock_ptr;   /*READ/WRITE*/

       void          lm_obtain_unsequenced_lock(lock_ptr)
       lm_unsequenced_lock_ptr_type  lock_ptr;   /*WRITE ONLY*/

       boolean_type  lm_obtain_unsequenced_lock_no_wait (lock_ptr)
       lm_unsequenced_lock_ptr_type  lock_ptr;   /*READ/WRITE*/

       void          lm_release_sequenced_lock(lock_ptr)
       lm_sequenced_lock_ptr_type    lock_ptr;   /*WRITE ONLY*/

       void          lm_release_unsequenced_lock(lock_ptr)
       lm_unsequenced_lock_ptr_type  lock_ptr;   /*WRITE ONLY*/

       #include "/usr/src/uts/aviion/ii/i_misc.h"

       void    misc_obtain_spin_lock (lock_ptr)
       misc_spin_lock_ptr_type lock_ptr; /*READ/WRITE*/

       void    misc_release_spin_lock (lock_ptr)
       misc_spin_lock_ptr_type lock_ptr; /*READ/WRITE*/

   where:
       lock_ptr  Pointer to lock to be initialized, obtained, or released.

DESCRIPTION
       The following routines are described in this man page:
       lm_initialize_sequenced_lock       Initialize a sequenced lock
       lm_initialize_unsequenced_lock     Initialize an unsequenced lock
       lm_obtain_sequenced_lock           Obtain a sequenced lock
       lm_obtain_sequenced_lock_no_wait   Get sequenced lock, if available
       lm_obtain_unsequenced_lock         Obtain an unsequenced lock
       lm_obtain_unsequenced_lock_no_wait Get unsequenced lock, if available
       lm_release_sequenced_lock          Release a sequenced lock
       lm_release_unsequenced_lock        Release an unsequenced lock
       misc_obtain_spin_lock              Obtain a spin lock
       misc_release_spin_lock             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, lm_obtain_sequenced_lock.  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,
       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:
              nk_jp_disable_my_interrupts();
              misc_obtain_spin_lock(&some_resource_spin_lock);
               .
               .
              misc_release_spin_lock(&some_resource_spin_lock);
              nk_jp_enable_my_interrupts();

       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
       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.

       lm_sequenced_lock_type
              typedef struct
                  {
                  lm_resource_counter_type    rc;
                  }  lm_sequenced_lock_type  ;

       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.

       lm_unsequenced_lock_type
              typedef struct
                  {
                  ...
                  }  lm_unsequenced_lock_type  ;

       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.

       misc_spin_lock_type
              typedef bit32e_type      misc_spin_lock_type ;

       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.

   lm_initialize_sequenced_lock
       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.

   lm_initialize_unsequenced_lock
       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.

   lm_obtain_sequenced_lock
       This routine obtains the specified lock.  The calling LWP is pended
       if the lock is not immediately available.

   lm_obtain_sequenced_lock_no_wait
       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.

   lm_obtain_unsequenced_lock
       This routine obtains the specified lock.  The calling LWP is pended
       if the lock is not immediately available.

   lm_obtain_unsequenced_lock_no_wait
       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.

   lm_release_sequenced_lock
       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.

   lm_release_unsequenced_lock
       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.

   misc_obtain_spin_lock
       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.

   misc_release_spin_lock
       This routine releases a spin lock.

DIAGNOSTICS
   Return Value
       For lm_obtain_sequenced_lock_no_wait and
       lm_obtain_unsequenced_lock_no_wait:
              TRUE   The lock was obtained.
              FALSE  The lock was not obtained.

       For the other routines: none.

   Errors
       None.

SEE ALSO
       interrupt_management(3K), process_management(3K).
       Programming in the DG/UX Kernel Environment.


Licensed material--property of copyright holder(s)

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026