OpenAFS
OpenAFS distributed network file system
/cygdrive/c/src/openafs/openafs.git/repo/src/afs/lock.h
00001 /*
00002  * Copyright 2000, International Business Machines Corporation and others.
00003  * All Rights Reserved.
00004  *
00005  * This software has been released under the terms of the IBM Public
00006  * License.  For details, see the LICENSE file in the top-level source
00007  * directory or online at http://www.openafs.org/dl/license10.html
00008  */
00009 
00010 #ifndef __AFSLOCK_INCLUDE__
00011 #define __AFSLOCK_INCLUDE__         1
00012 
00013 #if !defined(KERNEL) && !defined(KDUMP_KERNEL)
00014 #error Do not include afs/lock.h except for kernel code.
00015 #endif
00016 
00017 /*
00018  * (C) COPYRIGHT IBM CORPORATION 1987
00019  * LICENSED MATERIALS - PROPERTY OF IBM
00020  */
00021 
00022 #define INSTRUMENT_LOCKS
00023 /* This is the max lock number in use. Please update it if you add any new
00024  * lock numbers.
00025  */
00026 #define MAX_LOCK_NUMBER 780
00027 
00028 #ifdef AFS_BOZONLOCK_ENV
00029 struct afs_bozoLock {
00030     short count;                /* count of excl locks */
00031     char flags;                 /* bit 1: is anyone waiting? */
00032     char spare;                 /* for later */
00033     char *proc;                 /* process holding the lock, really an afs_proc_t * */
00034 };
00035 typedef struct afs_bozoLock afs_bozoLock_t;
00036 
00037 #define AFS_BOZONWAITING    1   /* someone is waiting for this lock */
00038 #endif
00039 
00040 #define AFS_RWLOCK_INIT(lock, nm)       Lock_Init(lock)
00041 #undef  LOCK_INIT
00042 #define LOCK_INIT(lock, nm)     Lock_Init(lock)
00043 
00044 /* The following macros allow multi statement macros to be defined safely, i.e.
00045    - the multi statement macro can be the object of an if statement;
00046    - the call to the multi statement macro may be legally followed by a semi-colon.
00047    BEGINMAC and ENDMAC have been tested with both the portable C compiler and
00048    Hi-C.  Both compilers were from the Palo Alto 4.2BSD software releases, and
00049    both optimized out the constant loop code.  For an example of the use
00050    of BEGINMAC and ENDMAC, see the definition for ReleaseWriteLock, below.
00051    An alternative to this, using "if(1)" for BEGINMAC is not used because it
00052    may generate worse code with pcc, and may generate warning messages with hi-C.
00053 */
00054 
00055 #define BEGINMAC do {
00056 #define ENDMAC   } while (0)
00057 
00058 #if defined(UKERNEL)
00059 typedef unsigned int afs_lock_tracker_t;
00060 # define MyPidxx (get_user_struct()->u_procp->p_pid )
00061 # define MyPidxx2Pid(x) (x)
00062 #elif defined(AFS_SUN5_ENV)
00063 typedef kthread_t * afs_lock_tracker_t;
00064 # define MyPidxx (curthread)
00065 # define MyPidxx2Pid(x) (x ? ttoproc(x)->p_pid : 0)
00066 #elif defined(AFS_SUN5_ENV) || defined(AFS_OBSD_ENV)
00067 typedef unsigned int afs_lock_tracker_t;
00068 # define MyPidxx (curproc->p_pid)
00069 # define MyPidxx2Pid(x) (x)
00070 #elif defined(AFS_AIX41_ENV)
00071 typedef tid_t afs_lock_tracker_t;
00072 extern tid_t thread_self();
00073 # define MyPidxx (thread_self())
00074 # define MyPidxx2Pid(x) ((afs_int32)(x))
00075 #elif defined(AFS_HPUX101_ENV)
00076 # if defined(AFS_HPUX1111_ENV)
00077 typedef struct kthread * afs_lock_tracker_t;
00078 #  define MyPidxx (u.u_kthreadp)
00079 #  define MyPidxx2Pid(x) (x ? kt_tid(x) : 0)
00080 # else
00081 typedef afs_proc_t * afs_lock_tracker_t;
00082 #  define MyPidxx (u.u_procp)
00083 #  define MyPidxx2Pid(x) (x ? (afs_int32)p_pid(x) : 0)
00084 # endif
00085 #elif defined(AFS_SGI64_ENV)
00086 # if defined(AFS_SGI65_ENV)
00087 typedef unsigned int afs_lock_tracker_t;
00088 #  define MyPidxx proc_pid(curproc())
00089 #  define MyPidxx2Pid(x) (x)
00090 # else
00091 typedef unsigned int afs_lock_tracker_t;
00092 #  define MyPidxx current_pid()
00093 #  define MyPidxx2Pid(x) (x)
00094 # endif
00095 #elif defined(AFS_LINUX20_ENV)
00096 typedef struct task_struct * afs_lock_tracker_t;
00097 # define MyPidxx (current)
00098 # define MyPidxx2Pid(x) (x? (x)->pid : 0)
00099 #elif defined(AFS_DARWIN_ENV)
00100 # if defined(AFS_DARWIN80_ENV)
00101 typedef unsigned int afs_lock_tracker_t;
00102 #  define MyPidxx (proc_selfpid())
00103 #  define MyPidxx2Pid(x) (x)
00104 # else
00105 typedef unsigned int afs_lock_tracker_t;
00106 #  define MyPidxx (current_proc()->p_pid )
00107 #  define MyPidxx2Pid(x) (x)
00108 # endif
00109 #elif defined(AFS_FBSD_ENV)
00110 typedef unsigned int afs_lock_tracker_t;
00111 # define MyPidxx (curproc->p_pid )
00112 # define MyPidxx2Pid(x) (x)
00113 #elif defined(AFS_NBSD40_ENV)
00114 typedef unsigned int afs_lock_tracker_t;
00115 #define MyPidxx osi_getpid() /* XXX could generalize this (above) */
00116 #define MyPidxx2Pid(x) (x)
00117 #else
00118 typedef unsigned int afs_lock_tracker_t;
00119 # define MyPidxx (u.u_procp->p_pid )
00120 # define MyPidxx2Pid(x) (x)
00121 #endif
00122 
00123 /* all locks wait on excl_locked except for READ_LOCK, which waits on readers_reading */
00124 struct afs_lock {
00125     unsigned char wait_states;  /* type of lockers waiting */
00126     unsigned char excl_locked;  /* anyone have boosted, shared or write lock? */
00127     unsigned short readers_reading;     /* # readers actually with read locks */
00128     unsigned short num_waiting; /* probably need this soon */
00129     unsigned short spare;       /* not used now */
00130     osi_timeval_t time_waiting; /* for statistics gathering */
00131 #if defined(INSTRUMENT_LOCKS)
00132     /* the following are useful for debugging
00133      ** the field 'src_indicator' is updated only by ObtainLock() and
00134      ** only for writes/shared  locks. Hence, it indictes where in the
00135      ** source code the shared/write lock was set.
00136      */
00137     afs_lock_tracker_t pid_last_reader; /* proceess id of last reader */
00138     afs_lock_tracker_t pid_writer;      /* process id of writer, else 0 */
00139     unsigned int src_indicator; /* third param to ObtainLock() */
00140 #endif                          /* INSTRUMENT_LOCKS */
00141 };
00142 typedef struct afs_lock afs_lock_t;
00143 typedef struct afs_lock afs_rwlock_t;
00144 
00145 #define READ_LOCK       1
00146 #define WRITE_LOCK      2
00147 #define SHARED_LOCK     4
00148 /* this next is not a flag, but rather a parameter to Afs_Lock_Obtain */
00149 #define BOOSTED_LOCK 6
00150 
00151 /* next defines wait_states for which we wait on excl_locked */
00152 #define EXCL_LOCKS (WRITE_LOCK|SHARED_LOCK)
00153 
00154 #ifdef KERNEL
00155 #include "icl.h"
00156 
00157 extern int afs_trclock;
00158 
00159 #define AFS_LOCK_TRACE_ENABLE 0
00160 #if AFS_LOCK_TRACE_ENABLE
00161 #define AFS_LOCK_TRACE(op, lock, type) \
00162         if (afs_trclock) Afs_Lock_Trace(op, lock, type, __FILE__, __LINE__);
00163 #else
00164 #define AFS_LOCK_TRACE(op, lock, type)
00165 #endif
00166 
00167 #if defined(INSTRUMENT_LOCKS)
00168 
00169 #define ObtainReadLock(lock)\
00170   BEGINMAC  \
00171         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\
00172         if (!((lock)->excl_locked & WRITE_LOCK)) \
00173             ((lock)->readers_reading)++; \
00174         else \
00175             Afs_Lock_Obtain(lock, READ_LOCK); \
00176         (lock)->pid_last_reader = MyPidxx; \
00177    ENDMAC
00178 
00179 #define NBObtainReadLock(lock) \
00180         (((lock)->excl_locked & WRITE_LOCK) ? EWOULDBLOCK :  (((lock)->readers_reading++), ((lock)->pid_last_reader = MyPidxx), 0))
00181 
00182 #define ObtainWriteLock(lock, src)\
00183   BEGINMAC  \
00184         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\
00185         if (!(lock)->excl_locked && !(lock)->readers_reading)\
00186             (lock) -> excl_locked = WRITE_LOCK;\
00187         else\
00188             Afs_Lock_Obtain(lock, WRITE_LOCK); \
00189         (lock)->pid_writer = MyPidxx; \
00190         (lock)->src_indicator = src;\
00191    ENDMAC
00192 
00193 #define NBObtainWriteLock(lock, src) (((lock)->excl_locked || (lock)->readers_reading) ? EWOULDBLOCK : (((lock) -> excl_locked = WRITE_LOCK), ((lock)->pid_writer = MyPidxx), ((lock)->src_indicator = src), 0))
00194 
00195 #define ObtainSharedLock(lock, src)\
00196   BEGINMAC  \
00197         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\
00198         if (!(lock)->excl_locked)\
00199             (lock) -> excl_locked = SHARED_LOCK;\
00200         else\
00201             Afs_Lock_Obtain(lock, SHARED_LOCK); \
00202         (lock)->pid_writer = MyPidxx; \
00203         (lock)->src_indicator = src;\
00204    ENDMAC
00205 
00206 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), ((lock)->pid_writer = MyPidxx), ((lock)->src_indicator = src), 0))
00207 
00208 #define UpgradeSToWLock(lock, src)\
00209   BEGINMAC  \
00210         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\
00211         if (!(lock)->readers_reading)\
00212             (lock)->excl_locked = WRITE_LOCK;\
00213         else\
00214             Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
00215         (lock)->pid_writer = MyPidxx; \
00216         (lock)->src_indicator = src;\
00217    ENDMAC
00218 
00219 /* this must only be called with a WRITE or boosted SHARED lock! */
00220 #define ConvertWToSLock(lock)\
00221         BEGINMAC\
00222         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\
00223             (lock)->excl_locked = SHARED_LOCK; \
00224             if((lock)->wait_states) \
00225                 Afs_Lock_ReleaseR(lock); \
00226         ENDMAC
00227 
00228 #define ConvertWToRLock(lock) \
00229         BEGINMAC\
00230         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
00231             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
00232             ((lock)->readers_reading)++;\
00233             (lock)->pid_last_reader = MyPidxx ; \
00234             (lock)->pid_writer = 0;\
00235             Afs_Lock_ReleaseR(lock);\
00236         ENDMAC
00237 
00238 #define ConvertSToRLock(lock) \
00239         BEGINMAC\
00240         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
00241             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
00242             ((lock)->readers_reading)++;\
00243             (lock)->pid_last_reader = MyPidxx ; \
00244             (lock)->pid_writer = 0;\
00245             Afs_Lock_ReleaseR(lock);\
00246         ENDMAC
00247 
00248 #define ReleaseReadLock(lock)\
00249         BEGINMAC\
00250         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\
00251             if (!(--((lock)->readers_reading)) && (lock)->wait_states)\
00252                 Afs_Lock_ReleaseW(lock) ; \
00253         if ( (lock)->pid_last_reader == MyPidxx ) \
00254                 (lock)->pid_last_reader =0;\
00255         ENDMAC
00256 
00257 #define ReleaseWriteLock(lock)\
00258         BEGINMAC\
00259         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\
00260             (lock)->excl_locked &= ~WRITE_LOCK;\
00261             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
00262             (lock)->pid_writer=0; \
00263         ENDMAC
00264 
00265 /* can be used on shared or boosted (write) locks */
00266 #define ReleaseSharedLock(lock)\
00267         BEGINMAC\
00268         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\
00269             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
00270             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
00271             (lock)->pid_writer=0; \
00272         ENDMAC
00273 
00274 #else /* INSTRUMENT_LOCKS */
00275 
00276 #define ObtainReadLock(lock)\
00277   BEGINMAC  \
00278         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\
00279         if (!((lock)->excl_locked & WRITE_LOCK)) \
00280             ((lock)->readers_reading)++; \
00281         else \
00282             Afs_Lock_Obtain(lock, READ_LOCK); \
00283    ENDMAC
00284 
00285 #define NBObtainReadLock(lock) \
00286         (((lock)->excl_locked & WRITE_LOCK) ? EWOULDBLOCK : (((lock)->readers_reading++), 0))
00287 
00288 #define ObtainWriteLock(lock, src)\
00289   BEGINMAC  \
00290         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\
00291         if (!(lock)->excl_locked && !(lock)->readers_reading)\
00292             (lock) -> excl_locked = WRITE_LOCK;\
00293         else\
00294             Afs_Lock_Obtain(lock, WRITE_LOCK); \
00295    ENDMAC
00296 
00297 #define NBObtainWriteLock(lock, src) (((lock)->excl_locked || (lock)->readers_reading) ? EWOULDBLOCK : (((lock) -> excl_locked = WRITE_LOCK),  0))
00298 
00299 #define ObtainSharedLock(lock, src)\
00300   BEGINMAC  \
00301         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\
00302         if (!(lock)->excl_locked)\
00303             (lock) -> excl_locked = SHARED_LOCK;\
00304         else\
00305             Afs_Lock_Obtain(lock, SHARED_LOCK); \
00306    ENDMAC
00307 
00308 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), 0))
00309 
00310 #define UpgradeSToWLock(lock, src)\
00311   BEGINMAC  \
00312         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\
00313         if (!(lock)->readers_reading)\
00314             (lock)->excl_locked = WRITE_LOCK;\
00315         else\
00316             Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
00317    ENDMAC
00318 
00319 /* this must only be called with a WRITE or boosted SHARED lock! */
00320 #define ConvertWToSLock(lock)\
00321         BEGINMAC\
00322         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\
00323             (lock)->excl_locked = SHARED_LOCK; \
00324             if((lock)->wait_states) \
00325                 Afs_Lock_ReleaseR(lock); \
00326         ENDMAC
00327 
00328 #define ConvertWToRLock(lock) \
00329         BEGINMAC\
00330         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
00331             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
00332             ((lock)->readers_reading)++;\
00333             Afs_Lock_ReleaseR(lock);\
00334         ENDMAC
00335 
00336 #define ConvertSToRLock(lock) \
00337         BEGINMAC\
00338         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
00339             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
00340             ((lock)->readers_reading)++;\
00341             Afs_Lock_ReleaseR(lock);\
00342         ENDMAC
00343 
00344 #define ReleaseReadLock(lock)\
00345         BEGINMAC\
00346         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\
00347             if (!(--((lock)->readers_reading)) && (lock)->wait_states)\
00348                 Afs_Lock_ReleaseW(lock) ; \
00349         ENDMAC
00350 
00351 #define ReleaseWriteLock(lock)\
00352         BEGINMAC\
00353         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\
00354             (lock)->excl_locked &= ~WRITE_LOCK;\
00355             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
00356         ENDMAC
00357 
00358 /* can be used on shared or boosted (write) locks */
00359 #define ReleaseSharedLock(lock)\
00360         BEGINMAC\
00361         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\
00362             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
00363             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
00364         ENDMAC
00365 
00366 #endif /* INSTRUMENT_LOCKS */
00367 
00368 /* I added this next macro to make sure it is safe to nuke a lock -- Mike K. */
00369 #define LockWaiters(lock)\
00370         ((int) ((lock)->num_waiting))
00371 
00372 #define CheckLock(lock)\
00373         ((lock)->excl_locked? (int) -1 : (int) (lock)->readers_reading)
00374 
00375 #define WriteLocked(lock)\
00376         ((lock)->excl_locked & WRITE_LOCK)
00377 #endif
00378 
00379 /*
00380 
00381 You can also use the lock package for handling parent locks for independently-lockable sets of
00382 small objects.  The concept here is that the parent lock is at the same level in the
00383 locking hierarchy as the little locks, but certain restrictions apply.
00384 
00385 The general usage pattern is as follows.  You have a set of entries to search.  When searching it, you
00386 have a "scan" lock on the table.  If you find what you're looking for, you drop the lock down
00387 to a "hold" lock, lock the entry, and release the parent lock.  If you don't find what
00388 you're looking for, you create the entry, downgrade the "scan" lock to a "hold" lock,
00389 lock the entry and unlock the parent.
00390 
00391 To delete an item from the table, you initially obtain a "purge" lock on the parent.  Unlike all
00392 of the other parent lock modes described herein, in order to obtain a "purge" lock mode, you
00393 must have released all locks on any items in the table.  Once you have obtained the parent
00394 lock in "purge" mode, you should check to see if the entry is locked.  If its not locked, you
00395 are free to delete the entry, knowing that no one else can attempt to obtain a lock
00396 on the entry while you have the purge lock held on the parent.  Unfortunately, if it *is* locked,
00397 you can not lock it yourself and wait for the other dude to release it, since the entry's locker
00398 may need to lock another entry before unlocking the entry you want (which would result in
00399 deadlock).  Instead, then, you must release the parent lock, and try again "later" (see Lock_Wait
00400 for assistance in waiting until later). Unfortunately, this is the best locking paradigm I've yet
00401 come up with.
00402 
00403 What are the advantages to this scheme?  First, the use of the parent lock ensures that
00404 two people don't try to add the same entry at the same time or delete an entry while someone
00405 else is adding it.  It also ensures that when one process is deleting an entry, no one else is
00406 preparing to lock the entry.  Furthermore, when obtaining a lock on a little entry, you
00407 are only holding a "hold" lock on the parent lock, so that others may come in and search
00408 the table during this time.  Thus it will not hold up the system if a little entry takes
00409 a great deal of time to free up.
00410 
00411 Here's how to compute the compatibility matrix:
00412 
00413 The invariants are:
00414 
00415 add     no deletions, additions allowed, additions will be performed, will obtain little locks
00416 hold    no deletions, additions allowed, no additions will be performed, will obtain little locks
00417 purge   no deletions or additions allowed, deletions will be performed, don't obtain little locks
00418 
00419 When we compute the locking matrix, we note that hold is compatible with hold and add.
00420 Add is compatible only with hold.  purge is not compatible with anything.  This is the same
00421 matrix as obtained by mapping add->S, hold->read and purge->write locks.  Thus we
00422 can use the locks above to solve this problem, and we do.
00423 
00424 */
00425 
00426 #endif /* __AFSLOCK_INCLUDE__ */
 All Data Structures Files Functions Variables