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