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