down with assert, up with osi_Assert
[openafs.git] / src / lwp / 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 /*******************************************************************\
11 *                                                                   *
12 *       Information Technology Center                               *
13 *       Carnegie-Mellon University                                  *
14 *                                                                   *
15 *                                                                   *
16 *                                                                   *
17 \*******************************************************************/
18
19 /*
20         Include file for using Vice locking routines.
21 */
22
23 #ifndef LOCK_H
24 #define LOCK_H
25
26 #ifdef KERNEL
27 #error Do not include lwp/lock.h for kernel code. Use afs/lock.h instead.
28 #endif
29
30
31 /* The following macros allow multi statement macros to be defined safely, i.e.
32    - the multi statement macro can be the object of an if statement;
33    - the call to the multi statement macro may be legally followed by a semi-colon.
34    BEGINMAC and ENDMAC have been tested with both the portable C compiler and
35    Hi-C.  Both compilers were from the Palo Alto 4.2BSD software releases, and
36    both optimized out the constant loop code.  For an example of the use
37    of BEGINMAC and ENDMAC, see the definition for ReleaseWriteLock, below.
38    An alternative to this, using "if(1)" for BEGINMAC is not used because it
39    may generate worse code with pcc, and may generate warning messages with hi-C.
40 */
41
42 #define BEGINMAC do {
43 #define ENDMAC   } while (0)
44
45 #ifdef AFS_PTHREAD_ENV
46 #include <pthread.h>
47 #include <afs/afs_assert.h>
48 /* can't include in non-lwp case; rx builds later */
49 #include <rx/rx.h>
50 #define LOCK_LOCK(A) MUTEX_ENTER(&(A)->mutex);
51 #define LOCK_UNLOCK(A) MUTEX_EXIT(&(A)->mutex);
52 #else /* AFS_PTHREAD_ENV */
53 #define LOCK_LOCK(A)
54 #define LOCK_UNLOCK(A)
55 #endif /* AFS_PTHREAD_ENV */
56
57 /* all locks wait on excl_locked except for READ_LOCK, which waits on readers_reading */
58 struct Lock {
59     unsigned char wait_states;  /* type of lockers waiting */
60     unsigned char excl_locked;  /* anyone have boosted, shared or write lock? */
61     unsigned char readers_reading;      /* # readers actually with read locks */
62     unsigned char num_waiting;  /* probably need this soon */
63 #ifdef AFS_PTHREAD_ENV
64     pthread_mutex_t mutex;      /* protects this structure */
65     pthread_cond_t read_cv;     /* wait for read locks */
66     pthread_cond_t write_cv;    /* wait for write/shared locks */
67 #endif                          /* AFS_PTHREAD_ENV */
68 };
69
70 extern void Afs_Lock_Obtain(struct Lock *lock, int how);
71 extern void Afs_Lock_ReleaseR(struct Lock *lock);
72 extern void Afs_Lock_ReleaseW(struct Lock *lock);
73 extern void Afs_Lock_WakeupR(struct Lock *lock);
74 void Lock_Init(struct Lock *lock);
75 void Lock_Destroy(struct Lock *lock);
76
77 #define READ_LOCK       1
78 #define WRITE_LOCK      2
79 #define SHARED_LOCK     4
80 /* this next is not a flag, but rather a parameter to Afs_Lock_Obtain */
81 #define BOOSTED_LOCK 6
82
83 /* next defines wait_states for which we wait on excl_locked */
84 #define EXCL_LOCKS (WRITE_LOCK|SHARED_LOCK)
85
86 #define ObtainReadLock(lock)\
87         BEGINMAC \
88             LOCK_LOCK(lock); \
89             if (!((lock)->excl_locked & WRITE_LOCK) && !(lock)->wait_states)\
90                 (lock) -> readers_reading++;\
91             else\
92                 Afs_Lock_Obtain(lock, READ_LOCK); \
93             LOCK_UNLOCK(lock); \
94         ENDMAC
95
96 #define ObtainReadLockNoBlock(lock, code)\
97         BEGINMAC \
98             LOCK_LOCK(lock); \
99             if (!((lock)->excl_locked & WRITE_LOCK) && !(lock)->wait_states) {\
100                 (lock) -> readers_reading++;\
101                 code = 0;\
102             }\
103             else\
104                 code = -1; \
105             LOCK_UNLOCK(lock); \
106         ENDMAC
107
108 #define ObtainWriteLock(lock)\
109         BEGINMAC \
110             LOCK_LOCK(lock); \
111             if (!(lock)->excl_locked && !(lock)->readers_reading)\
112                 (lock) -> excl_locked = WRITE_LOCK;\
113             else\
114                 Afs_Lock_Obtain(lock, WRITE_LOCK); \
115             LOCK_UNLOCK(lock); \
116         ENDMAC
117
118 #define ObtainWriteLockNoBlock(lock, code)\
119         BEGINMAC \
120             LOCK_LOCK(lock); \
121             if (!(lock)->excl_locked && !(lock)->readers_reading) {\
122                 (lock) -> excl_locked = WRITE_LOCK;\
123                 code = 0;\
124             }\
125             else\
126                 code = -1; \
127             LOCK_UNLOCK(lock); \
128         ENDMAC
129
130 #define ObtainSharedLock(lock)\
131         BEGINMAC \
132             LOCK_LOCK(lock); \
133             if (!(lock)->excl_locked && !(lock)->wait_states)\
134                 (lock) -> excl_locked = SHARED_LOCK;\
135             else\
136                 Afs_Lock_Obtain(lock, SHARED_LOCK); \
137             LOCK_UNLOCK(lock); \
138         ENDMAC
139
140 #define ObtainSharedLockNoBlock(lock, code)\
141         BEGINMAC \
142             LOCK_LOCK(lock); \
143             if (!(lock)->excl_locked && !(lock)->wait_states) {\
144                 (lock) -> excl_locked = SHARED_LOCK;\
145                 code = 0;\
146             }\
147             else\
148                 code = -1; \
149             LOCK_UNLOCK(lock); \
150         ENDMAC
151
152 #define BoostSharedLock(lock)\
153         BEGINMAC \
154             LOCK_LOCK(lock); \
155             if (!(lock)->readers_reading)\
156                 (lock)->excl_locked = WRITE_LOCK;\
157             else\
158                 Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
159             LOCK_UNLOCK(lock); \
160         ENDMAC
161
162 /* this must only be called with a WRITE or boosted SHARED lock! */
163 #define UnboostSharedLock(lock)\
164         BEGINMAC\
165             LOCK_LOCK(lock); \
166             (lock)->excl_locked = SHARED_LOCK; \
167             if((lock)->wait_states) \
168                 Afs_Lock_ReleaseR(lock); \
169             LOCK_UNLOCK(lock); \
170         ENDMAC
171
172 #ifdef notdef
173 /* this is what UnboostSharedLock looked like before the hi-C compiler */
174 /* this must only be called with a WRITE or boosted SHARED lock! */
175 #define UnboostSharedLock(lock)\
176         ((lock)->excl_locked = SHARED_LOCK,\
177         ((lock)->wait_states ?\
178                 Afs_Lock_ReleaseR(lock) : 0))
179 #endif /* notdef */
180
181 #define ReleaseReadLock(lock)\
182         BEGINMAC\
183             LOCK_LOCK(lock); \
184             if (!--(lock)->readers_reading && (lock)->wait_states)\
185                 Afs_Lock_ReleaseW(lock) ; \
186             LOCK_UNLOCK(lock); \
187         ENDMAC
188
189
190 #ifdef notdef
191 /* This is what the previous definition should be, but the hi-C compiler generates
192   a warning for each invocation */
193 #define ReleaseReadLock(lock)\
194         (!--(lock)->readers_reading && (lock)->wait_states ?\
195                 Afs_Lock_ReleaseW(lock)    :\
196                 0)
197 #endif /* notdef */
198
199 #define ReleaseWriteLock(lock)\
200         BEGINMAC\
201             LOCK_LOCK(lock); \
202             (lock)->excl_locked &= ~WRITE_LOCK;\
203             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
204             LOCK_UNLOCK(lock); \
205         ENDMAC
206
207 #ifdef notdef
208 /* This is what the previous definition should be, but the hi-C compiler generates
209    a warning for each invocation */
210 #define ReleaseWriteLock(lock)\
211         ((lock)->excl_locked &= ~WRITE_LOCK,\
212         ((lock)->wait_states ?\
213                 Afs_Lock_ReleaseR(lock) : 0))
214 #endif /* notdef */
215
216 /* can be used on shared or boosted (write) locks */
217 #define ReleaseSharedLock(lock)\
218         BEGINMAC\
219             LOCK_LOCK(lock); \
220             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
221             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
222             LOCK_UNLOCK(lock); \
223         ENDMAC
224
225 #ifdef notdef
226 /* This is what the previous definition should be, but the hi-C compiler generates
227    a warning for each invocation */
228 /* can be used on shared or boosted (write) locks */
229 #define ReleaseSharedLock(lock)\
230         ((lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK),\
231         ((lock)->wait_states ?\
232                 Afs_Lock_ReleaseR(lock) : 0))
233 #endif /* notdef */
234
235 /* convert a write lock to a read lock */
236 #define ConvertWriteToReadLock(lock)\
237         BEGINMAC\
238             LOCK_LOCK(lock); \
239             (lock)->excl_locked &= ~WRITE_LOCK;\
240             (lock)->readers_reading++;\
241             if ((lock)->wait_states & READ_LOCK) \
242                 Afs_Lock_WakeupR(lock) ; \
243             LOCK_UNLOCK(lock); \
244         ENDMAC
245
246 /* I added this next macro to make sure it is safe to nuke a lock -- Mike K. */
247 #define LockWaiters(lock)\
248         ((int) ((lock)->num_waiting))
249
250 #define CheckLock(lock)\
251         ((lock)->excl_locked? (int) -1 : (int) (lock)->readers_reading)
252
253 #define WriteLocked(lock)\
254         ((lock)->excl_locked & WRITE_LOCK)
255
256 #endif /* LOCK_H */