Complete removal of DUX client code
[openafs.git] / src / afs / lock.h
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #ifndef __AFSLOCK_INCLUDE__
11 #define __AFSLOCK_INCLUDE__         1
12
13 #if !defined(KERNEL) && !defined(KDUMP_KERNEL)
14 #error Do not include afs/lock.h except for kernel code.
15 #endif
16
17 /*
18  * (C) COPYRIGHT IBM CORPORATION 1987
19  * LICENSED MATERIALS - PROPERTY OF IBM
20  */
21
22 #if     (defined(AFS_SUN5_ENV))
23 #define AFS_NOBOZO_LOCK
24 #endif
25
26 #define INSTRUMENT_LOCKS
27 /* This is the max lock number in use. Please update it if you add any new
28  * lock numbers.
29  */
30 #define MAX_LOCK_NUMBER 780
31
32 struct afs_bozoLock {
33     short count;                /* count of excl locks */
34     char flags;                 /* bit 1: is anyone waiting? */
35     char spare;                 /* for later */
36     char *proc;                 /* process holding the lock, really an afs_proc_t * */
37 };
38 #ifndef AFS_NOBOZO_LOCK
39 typedef struct afs_bozoLock afs_bozoLock_t;
40 #else
41 #ifdef  AFS_SUN5_ENV
42 typedef kmutex_t afs_bozoLock_t;
43 #else
44 typedef struct afs_bozoLock afs_bozoLock_t;
45 #endif
46 #define afs_BozonLock(lock, avc)
47 #define afs_BozonUnlock(lock, avc)
48 #define afs_BozonInit(lock, nm)
49 #define afs_CheckBozonLock(lock)                0
50 #define afs_CheckBozonLockBlocking(lock)        0
51 #endif
52
53 #define AFS_BOZONWAITING    1   /* someone is waiting for this lock */
54
55 #undef MObtainWriteLock         /* Defined also in ../rx/rx_machdep.h" */
56 #undef MReleaseWriteLock
57 #define MObtainReadLock(lock)   ObtainReadLock(lock)
58 #define MObtainWriteLock(lock,src)      ObtainWriteLock(lock,src)
59 #define MObtainSharedLock(lock,src)     ObtainSharedLock(lock,src)
60 #define MUpgradeSToWLock(lock,src)      UpgradeSToWLock(lock,src)
61 #define MConvertWToSLock(lock)  ConvertWToSLock(lock)
62 #define MReleaseReadLock(lock)  ReleaseReadLock(lock)
63 #define MReleaseWriteLock(lock) ReleaseWriteLock(lock)
64 #define MReleaseSharedLock(lock) ReleaseSharedLock(lock)
65
66 #define AFS_RWLOCK_INIT(lock, nm)       Lock_Init(lock)
67 #undef  LOCK_INIT
68 #define LOCK_INIT(lock, nm)     Lock_Init(lock)
69
70 /* The following macros allow multi statement macros to be defined safely, i.e.
71    - the multi statement macro can be the object of an if statement;
72    - the call to the multi statement macro may be legally followed by a semi-colon.
73    BEGINMAC and ENDMAC have been tested with both the portable C compiler and
74    Hi-C.  Both compilers were from the Palo Alto 4.2BSD software releases, and
75    both optimized out the constant loop code.  For an example of the use
76    of BEGINMAC and ENDMAC, see the definition for ReleaseWriteLock, below.
77    An alternative to this, using "if(1)" for BEGINMAC is not used because it
78    may generate worse code with pcc, and may generate warning messages with hi-C.
79 */
80
81 #define BEGINMAC do {
82 #define ENDMAC   } while (0)
83
84 #if defined(AFS_SUN57_ENV)
85 typedef kthread_t * afs_lock_tracker_t;
86 #define MyPidxx (curthread)
87 #define MyPidxx2Pid(x) (x ? ttoproc(x)->p_pid : 0)
88 #elif defined(AFS_SUN5_ENV) || defined(AFS_OBSD_ENV)
89 typedef unsigned int afs_lock_tracker_t;
90 #define MyPidxx (curproc->p_pid)
91 #define MyPidxx2Pid(x) (x)
92 #else
93 #if defined(AFS_AIX41_ENV)
94 typedef tid_t afs_lock_tracker_t;
95 extern tid_t thread_self();
96 #define MyPidxx (thread_self())
97 #define MyPidxx2Pid(x) ((afs_int32)(x))
98 #else /* AFS_AIX41_ENV */
99 #if defined(AFS_HPUX101_ENV)
100 #if defined(AFS_HPUX1111_ENV)
101 typedef struct kthread * afs_lock_tracker_t;
102 #define MyPidxx (u.u_kthreadp)
103 #define MyPidxx2Pid(x) (x ? kt_tid(x) : 0)
104 #else
105 typedef afs_proc_t * afs_lock_tracker_t;
106 #define MyPidxx (u.u_procp)
107 #define MyPidxx2Pid(x) (x ? (afs_int32)p_pid(x) : 0)
108 #endif
109 #else
110 #if defined(AFS_SGI64_ENV)
111 #if defined(AFS_SGI65_ENV)
112 typedef unsigned int afs_lock_tracker_t;
113 #define MyPidxx proc_pid(curproc())
114 #define MyPidxx2Pid(x) (x)
115 #else
116 typedef unsigned int afs_lock_tracker_t;
117 #define MyPidxx current_pid()
118 #define MyPidxx2Pid(x) (x)
119 #endif
120 #else /* AFS_SGI64_ENV */
121 #ifdef AFS_LINUX20_ENV
122 typedef struct task_struct * afs_lock_tracker_t;
123 #define MyPidxx (current)
124 #define MyPidxx2Pid(x) (x? (x)->pid : 0)
125 #else
126 #if defined(AFS_DARWIN_ENV)
127 #if defined(AFS_DARWIN80_ENV)
128 typedef unsigned int afs_lock_tracker_t;
129 #define MyPidxx (proc_selfpid())
130 #define MyPidxx2Pid(x) (x)
131 #else
132 typedef unsigned int afs_lock_tracker_t;
133 #define MyPidxx (current_proc()->p_pid )
134 #define MyPidxx2Pid(x) (x)
135 #endif
136 #else
137 #if defined(AFS_FBSD_ENV)
138 typedef unsigned int afs_lock_tracker_t;
139 #define MyPidxx (curproc->p_pid )
140 #define MyPidxx2Pid(x) (x)
141 #else
142 typedef unsigned int afs_lock_tracker_t;
143 #define MyPidxx (u.u_procp->p_pid )
144 #define MyPidxx2Pid(x) (x)
145 #endif /* AFS_FBSD_ENV */
146 #endif /* AFS_DARWIN_ENV */
147 #endif /* AFS_LINUX20_ENV */
148 #endif /* AFS_SGI64_ENV */
149 #endif /* AFS_HPUX101_ENV */
150 #endif /* AFS_AIX41_ENV */
151 #endif
152
153 /* all locks wait on excl_locked except for READ_LOCK, which waits on readers_reading */
154 struct afs_lock {
155     unsigned char wait_states;  /* type of lockers waiting */
156     unsigned char excl_locked;  /* anyone have boosted, shared or write lock? */
157     unsigned short readers_reading;     /* # readers actually with read locks */
158     unsigned short num_waiting; /* probably need this soon */
159     unsigned short spare;       /* not used now */
160     osi_timeval_t time_waiting; /* for statistics gathering */
161 #if defined(INSTRUMENT_LOCKS)
162     /* the following are useful for debugging 
163      ** the field 'src_indicator' is updated only by ObtainLock() and
164      ** only for writes/shared  locks. Hence, it indictes where in the
165      ** source code the shared/write lock was set.
166      */
167     afs_lock_tracker_t pid_last_reader; /* proceess id of last reader */
168     afs_lock_tracker_t pid_writer;      /* process id of writer, else 0 */
169     unsigned int src_indicator; /* third param to ObtainLock() */
170 #endif                          /* INSTRUMENT_LOCKS */
171 };
172 typedef struct afs_lock afs_lock_t;
173 typedef struct afs_lock afs_rwlock_t;
174
175 #define READ_LOCK       1
176 #define WRITE_LOCK      2
177 #define SHARED_LOCK     4
178 /* this next is not a flag, but rather a parameter to Afs_Lock_Obtain */
179 #define BOOSTED_LOCK 6
180
181 /* next defines wait_states for which we wait on excl_locked */
182 #define EXCL_LOCKS (WRITE_LOCK|SHARED_LOCK)
183
184 #ifdef KERNEL
185 #include "icl.h"
186
187 extern int afs_trclock;
188
189 #define AFS_LOCK_TRACE_ENABLE 0
190 #if AFS_LOCK_TRACE_ENABLE
191 #define AFS_LOCK_TRACE(op, lock, type) \
192         if (afs_trclock) Afs_Lock_Trace(op, lock, type, __FILE__, __LINE__);
193 #else
194 #define AFS_LOCK_TRACE(op, lock, type)
195 #endif
196
197 #if defined(INSTRUMENT_LOCKS)
198
199 #define ObtainReadLock(lock)\
200   BEGINMAC  \
201         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\
202         if (!((lock)->excl_locked & WRITE_LOCK)) \
203             ((lock)->readers_reading)++; \
204         else \
205             Afs_Lock_Obtain(lock, READ_LOCK); \
206         (lock)->pid_last_reader = MyPidxx; \
207    ENDMAC
208
209 #define NBObtainReadLock(lock) \
210         (((lock)->excl_locked & WRITE_LOCK) ? EWOULDBLOCK :  (((lock)->readers_reading++), ((lock)->pid_last_reader = MyPidxx), 0))
211
212 #define ObtainWriteLock(lock, src)\
213   BEGINMAC  \
214         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\
215         if (!(lock)->excl_locked && !(lock)->readers_reading)\
216             (lock) -> excl_locked = WRITE_LOCK;\
217         else\
218             Afs_Lock_Obtain(lock, WRITE_LOCK); \
219         (lock)->pid_writer = MyPidxx; \
220         (lock)->src_indicator = src;\
221    ENDMAC
222
223 #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))
224
225 #define ObtainSharedLock(lock, src)\
226   BEGINMAC  \
227         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\
228         if (!(lock)->excl_locked)\
229             (lock) -> excl_locked = SHARED_LOCK;\
230         else\
231             Afs_Lock_Obtain(lock, SHARED_LOCK); \
232         (lock)->pid_writer = MyPidxx; \
233         (lock)->src_indicator = src;\
234    ENDMAC
235
236 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), ((lock)->pid_writer = MyPidxx), ((lock)->src_indicator = src), 0))
237
238 #define UpgradeSToWLock(lock, src)\
239   BEGINMAC  \
240         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\
241         if (!(lock)->readers_reading)\
242             (lock)->excl_locked = WRITE_LOCK;\
243         else\
244             Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
245         (lock)->pid_writer = MyPidxx; \
246         (lock)->src_indicator = src;\
247    ENDMAC
248
249 /* this must only be called with a WRITE or boosted SHARED lock! */
250 #define ConvertWToSLock(lock)\
251         BEGINMAC\
252         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\
253             (lock)->excl_locked = SHARED_LOCK; \
254             if((lock)->wait_states) \
255                 Afs_Lock_ReleaseR(lock); \
256         ENDMAC
257
258 #define ConvertWToRLock(lock) \
259         BEGINMAC\
260         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
261             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
262             ((lock)->readers_reading)++;\
263             (lock)->pid_last_reader = MyPidxx ; \
264             (lock)->pid_writer = 0;\
265             Afs_Lock_ReleaseR(lock);\
266         ENDMAC
267
268 #define ConvertSToRLock(lock) \
269         BEGINMAC\
270         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
271             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
272             ((lock)->readers_reading)++;\
273             (lock)->pid_last_reader = MyPidxx ; \
274             (lock)->pid_writer = 0;\
275             Afs_Lock_ReleaseR(lock);\
276         ENDMAC
277
278 #define ReleaseReadLock(lock)\
279         BEGINMAC\
280         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\
281             if (!(--((lock)->readers_reading)) && (lock)->wait_states)\
282                 Afs_Lock_ReleaseW(lock) ; \
283         if ( (lock)->pid_last_reader == MyPidxx ) \
284                 (lock)->pid_last_reader =0;\
285         ENDMAC
286
287 #define ReleaseWriteLock(lock)\
288         BEGINMAC\
289         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\
290             (lock)->excl_locked &= ~WRITE_LOCK;\
291             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
292             (lock)->pid_writer=0; \
293         ENDMAC
294
295 /* can be used on shared or boosted (write) locks */
296 #define ReleaseSharedLock(lock)\
297         BEGINMAC\
298         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\
299             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
300             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
301             (lock)->pid_writer=0; \
302         ENDMAC
303
304 #else /* INSTRUMENT_LOCKS */
305
306 #define ObtainReadLock(lock)\
307   BEGINMAC  \
308         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\
309         if (!((lock)->excl_locked & WRITE_LOCK)) \
310             ((lock)->readers_reading)++; \
311         else \
312             Afs_Lock_Obtain(lock, READ_LOCK); \
313    ENDMAC
314
315 #define NBObtainReadLock(lock) \
316         (((lock)->excl_locked & WRITE_LOCK) ? EWOULDBLOCK : (((lock)->readers_reading++), 0))
317
318 #define ObtainWriteLock(lock, src)\
319   BEGINMAC  \
320         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\
321         if (!(lock)->excl_locked && !(lock)->readers_reading)\
322             (lock) -> excl_locked = WRITE_LOCK;\
323         else\
324             Afs_Lock_Obtain(lock, WRITE_LOCK); \
325    ENDMAC
326
327 #define NBObtainWriteLock(lock, src) (((lock)->excl_locked || (lock)->readers_reading) ? EWOULDBLOCK : (((lock) -> excl_locked = WRITE_LOCK),  0))
328
329 #define ObtainSharedLock(lock, src)\
330   BEGINMAC  \
331         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\
332         if (!(lock)->excl_locked)\
333             (lock) -> excl_locked = SHARED_LOCK;\
334         else\
335             Afs_Lock_Obtain(lock, SHARED_LOCK); \
336    ENDMAC
337
338 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), 0))
339
340 #define UpgradeSToWLock(lock, src)\
341   BEGINMAC  \
342         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\
343         if (!(lock)->readers_reading)\
344             (lock)->excl_locked = WRITE_LOCK;\
345         else\
346             Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
347    ENDMAC
348
349 /* this must only be called with a WRITE or boosted SHARED lock! */
350 #define ConvertWToSLock(lock)\
351         BEGINMAC\
352         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\
353             (lock)->excl_locked = SHARED_LOCK; \
354             if((lock)->wait_states) \
355                 Afs_Lock_ReleaseR(lock); \
356         ENDMAC
357
358 #define ConvertWToRLock(lock) \
359         BEGINMAC\
360         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
361             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
362             ((lock)->readers_reading)++;\
363             Afs_Lock_ReleaseR(lock);\
364         ENDMAC
365
366 #define ConvertSToRLock(lock) \
367         BEGINMAC\
368         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
369             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
370             ((lock)->readers_reading)++;\
371             Afs_Lock_ReleaseR(lock);\
372         ENDMAC
373
374 #define ReleaseReadLock(lock)\
375         BEGINMAC\
376         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\
377             if (!(--((lock)->readers_reading)) && (lock)->wait_states)\
378                 Afs_Lock_ReleaseW(lock) ; \
379         ENDMAC
380
381 #define ReleaseWriteLock(lock)\
382         BEGINMAC\
383         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\
384             (lock)->excl_locked &= ~WRITE_LOCK;\
385             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
386         ENDMAC
387
388 /* can be used on shared or boosted (write) locks */
389 #define ReleaseSharedLock(lock)\
390         BEGINMAC\
391         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\
392             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
393             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
394         ENDMAC
395
396 #endif /* INSTRUMENT_LOCKS */
397
398 /* I added this next macro to make sure it is safe to nuke a lock -- Mike K. */
399 #define LockWaiters(lock)\
400         ((int) ((lock)->num_waiting))
401
402 #define CheckLock(lock)\
403         ((lock)->excl_locked? (int) -1 : (int) (lock)->readers_reading)
404
405 #define WriteLocked(lock)\
406         ((lock)->excl_locked & WRITE_LOCK)
407 #endif
408
409 /*
410
411 You can also use the lock package for handling parent locks for independently-lockable sets of
412 small objects.  The concept here is that the parent lock is at the same level in the
413 locking hierarchy as the little locks, but certain restrictions apply.
414
415 The general usage pattern is as follows.  You have a set of entries to search.  When searching it, you
416 have a "scan" lock on the table.  If you find what you're looking for, you drop the lock down
417 to a "hold" lock, lock the entry, and release the parent lock.  If you don't find what
418 you're looking for, you create the entry, downgrade the "scan" lock to a "hold" lock,
419 lock the entry and unlock the parent.
420
421 To delete an item from the table, you initially obtain a "purge" lock on the parent.  Unlike all
422 of the other parent lock modes described herein, in order to obtain a "purge" lock mode, you
423 must have released all locks on any items in the table.  Once you have obtained the parent
424 lock in "purge" mode, you should check to see if the entry is locked.  If its not locked, you
425 are free to delete the entry, knowing that no one else can attempt to obtain a lock
426 on the entry while you have the purge lock held on the parent.  Unfortunately, if it *is* locked,
427 you can not lock it yourself and wait for the other dude to release it, since the entry's locker
428 may need to lock another entry before unlocking the entry you want (which would result in
429 deadlock).  Instead, then, you must release the parent lock, and try again "later" (see Lock_Wait
430 for assistance in waiting until later). Unfortunately, this is the best locking paradigm I've yet
431 come up with.
432
433 What are the advantages to this scheme?  First, the use of the parent lock ensures that
434 two people don't try to add the same entry at the same time or delete an entry while someone
435 else is adding it.  It also ensures that when one process is deleting an entry, no one else is
436 preparing to lock the entry.  Furthermore, when obtaining a lock on a little entry, you
437 are only holding a "hold" lock on the parent lock, so that others may come in and search
438 the table during this time.  Thus it will not hold up the system if a little entry takes
439 a great deal of time to free up.
440
441 Here's how to compute the compatibility matrix:
442
443 The invariants are:
444
445 add     no deletions, additions allowed, additions will be performed, will obtain little locks
446 hold    no deletions, additions allowed, no additions will be performed, will obtain little locks
447 purge   no deletions or additions allowed, deletions will be performed, don't obtain little locks
448
449 When we compute the locking matrix, we note that hold is compatible with hold and add.
450 Add is compatible only with hold.  purge is not compatible with anything.  This is the same
451 matrix as obtained by mapping add->S, hold->read and purge->write locks.  Thus we
452 can use the locks above to solve this problem, and we do.
453
454 */
455
456 #endif /* __AFSLOCK_INCLUDE__ */