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