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