lock man page on Plan9

Man page or keyword search:  
man Server   549 pages
apropos Keyword Search (all sections)
Output format
Plan9 logo
[printable version]

LOCK(2)								       LOCK(2)

NAME
       lock,  canlock, unlock, qlock, canqlock, qunlock, rlock, canrlock, run‐
       lock, wlock, canwlock, wunlock, rsleep,	rwakeup,  rwakeupall,  incref,
       decref  -  spin	locks, queueing rendezvous locks, reader-writer locks,
       rendezvous points, and reference counts

SYNOPSIS
       #include <u.h>
       #include <libc.h>

       void lock(Lock *l)
       int  canlock(Lock *l)
       void unlock(Lock *l)

       void qlock(QLock *l)
       int  canqlock(QLock *l)
       void qunlock(QLock *l)

       void rlock(RWLock *l)
       int  canrlock(RWLock *l)
       void runlock(RWLock *l)

       void wlock(RWLock *l)
       int  canwlock(RWLock *l)
       void wunlock(RWLock *l)

       typedef struct Rendez {
	    QLock *l;
	    ...
       } Rendez;

       void rsleep(Rendez *r)
       int  rwakeup(Rendez *r)
       int  rwakeupall(Rendez *r)

       #include <thread.h>

       typedef struct Ref {
	    long ref;
       } Ref;

       void incref(Ref*)
       long decref(Ref*)

DESCRIPTION
       These routines are used	to synchronize processes sharing memory.

       Locks are spin locks, QLocks and RWLocks are different types of	queue‐
       ing rendezvous locks, and Rendezes are rendezvous points.

       Locks  and  rendezvous  points work in regular programs as well as pro‐
       grams that use the thread library (see thread(2)).  The thread  library
       replaces	 the  rendezvous(2)  system  call with its own implementation,
       threadrendezvous, so that threads as well as processes may be  synchro‐
       nized by locking calls in threaded programs.

       Used  carelessly,  spin	locks can be expensive and can easily generate
       deadlocks.  Their use is discouraged, especially in programs  that  use
       the  thread  library  because  they  prevent  context  switches between
       threads.

       Lock blocks until the lock has been obtained.  Canlock is non-blocking.
       It  tries  to obtain a lock and returns a non-zero value if it was suc‐
       cessful, 0 otherwise.  Unlock releases a lock.

       QLocks have the same interface but are not spin locks; instead  if  the
       lock is taken qlock will suspend execution of the calling task until it
       is released.

       Although Locks are the more primitive lock, they have limitations;  for
       example,	 they  cannot synchronize between tasks in the same proc.  Use
       QLocks instead.

       RWLocks manage access to a data structure that has distinct readers and
       writers.	  Rlock grants read access; runlock releases it.  Wlock grants
       write access; wunlock releases it.  Canrlock and canwlock are the  non-
       blocking	 versions.   There  may be any number of simultaneous readers,
       but only one writer.  Moreover, if write access is granted no  one  may
       have read access until write access is released.

       All  types  of lock should be initialized to all zeros before use; this
       puts them in the unlocked state.

       Rendezes are rendezvous points.	Each Rendez r is protected by a	 QLock
       r->l, which must be held by the callers of rsleep, rwakeup, and rwakeu‐
       pall.  Rsleep atomically releases r->l and suspends  execution  of  the
       calling	task.	After  resuming	 execution, rsleep will reacquire r->l
       before returning.  If any processes are sleeping on  r,	rwakeup	 wakes
       one of them.  it returns 1 if a process was awakened, 0 if not.	Rwake‐
       upall wakes all processes sleeping on r, returning the number  of  pro‐
       cesses awakened.	 Rwakeup and rwakeupall do not release r->l and do not
       suspend execution of the current task.

       Before use, Rendezes should be initialized to all zeros except for r->l
       pointer,	 which	should	point  at  the QLock that will guard r.	 It is
       important that this QLock is the same one that protects the  rendezvous
       condition; see the example.

       A  Ref  contains	 a long that can be incremented and decremented atomi‐
       cally: Incref increments the Ref in one atomic operation.  Decref atom‐
       ically  decrements  the	Ref and returns zero if the resulting value is
       zero, non-zero otherwise.

EXAMPLE
       Implement a buffered single-element channel using rsleep and rwakeup:

	      typedef struct Chan
	      {
		  QLock l;
		  Rendez full, empty;
		  int val, haveval;
	      } Chan;

	      Chan*
	      mkchan(void)
	      {
		  Chan *c;

		  c = mallocz(sizeof *c, 1);
		  c->full.l = &c->l;
		  c->empty.l = &c->l;
		  return c;
	      }

	      void
	      send(Chan *c, int val)
	      {
		  qlock(&c->l);
		  while(c->haveval)
		      rsleep(&c->full);
		  c->haveval = 1;
		  c->val = val;
		  rwakeup(&c->empty);  /* no longer empty */
		  qunlock(&c->l);
	      }

	      int
	      recv(Chan *c)
	      {
		  int v;

		  qlock(&c->l);
		  while(!c->haveval)
		      rsleep(&c->empty);
		  c->haveval = 0;
		  v = c->val;
		  rwakeup(&c->full);  /* no longer full */
		  qunlock(&c->l);
		  return v;
	      }

       Note that the QLock protecting the Chan is the same QLock used for  the
       Rendez; this ensures that wakeups are not missed.

SOURCE
       /sys/src/libc/port/lock.c
       /sys/src/libc/9sys/qlock.c
       /sys/src/libthread/ref.c

SEE ALSO
       rfork in fork(2)

BUGS
       Locks  are  not	strictly spin locks.  After each unsuccessful attempt,
       lock calls sleep(0) to yield the CPU;  this  handles  the  common  case
       where some other process holds the lock.	 After a thousand unsuccessful
       attempts, lock sleeps for 100ms between attempts.  After another	 thou‐
       sand  unsuccessful  attempts,  lock  sleeps  for	 a full second between
       attempts.  Locks are not intended to be held for long periods of	 time.
       The  100ms and full second sleeps are only heuristics to avoid tying up
       the CPU when a process deadlocks.  As discussed above, if a lock is  to
       be  held for much more than a few instructions, the queueing lock types
       should be almost always be used.

       It is an error for a program to fork when it holds  a  lock  in	shared
       memory,	since  this will result in two processes holding the same lock
       at the same time, which should not happen.

								       LOCK(2)
[top]
                             _         _         _ 
                            | |       | |       | |     
                            | |       | |       | |     
                         __ | | __ __ | | __ __ | | __  
                         \ \| |/ / \ \| |/ / \ \| |/ /  
                          \ \ / /   \ \ / /   \ \ / /   
                           \   /     \   /     \   /    
                            \_/       \_/       \_/ 
More information is available in HTML format for server Plan9

List of man pages available for Plan9

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net