fix-indent-bug-with-lock-macros-part-three-20040818
[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 <assert.h>
47 #include <pthread.h>
48 #define LOCK_LOCK(A) assert(pthread_mutex_lock(&(A)->mutex) == 0)
49 #define LOCK_UNLOCK(A) assert(pthread_mutex_unlock(&(A)->mutex) == 0)
50 #else /* AFS_PTHREAD_ENV */
51 #define LOCK_LOCK(A)
52 #define LOCK_UNLOCK(A)
53 #endif /* AFS_PTHREAD_ENV */
54
55 /* all locks wait on excl_locked except for READ_LOCK, which waits on readers_reading */
56 struct Lock {
57     unsigned char wait_states;  /* type of lockers waiting */
58     unsigned char excl_locked;  /* anyone have boosted, shared or write lock? */
59     unsigned char readers_reading;      /* # readers actually with read locks */
60     unsigned char num_waiting;  /* probably need this soon */
61 #ifdef AFS_PTHREAD_ENV
62     pthread_mutex_t mutex;      /* protects this structure */
63     pthread_cond_t read_cv;     /* wait for read locks */
64     pthread_cond_t write_cv;    /* wait for write/shared locks */
65 #endif                          /* AFS_PTHREAD_ENV */
66 };
67
68 extern void Afs_Lock_Obtain(struct Lock *lock, int how);
69 extern void Afs_Lock_ReleaseR(struct Lock *lock);
70 extern void Afs_Lock_ReleaseW(struct Lock *lock);
71 void Lock_Init(struct Lock *lock);
72 void Lock_Destroy(struct Lock *lock);
73
74 #define READ_LOCK       1
75 #define WRITE_LOCK      2
76 #define SHARED_LOCK     4
77 /* this next is not a flag, but rather a parameter to Afs_Lock_Obtain */
78 #define BOOSTED_LOCK 6
79
80 /* next defines wait_states for which we wait on excl_locked */
81 #define EXCL_LOCKS (WRITE_LOCK|SHARED_LOCK)
82
83 #define ObtainReadLock(lock)\
84         BEGINMAC \
85             LOCK_LOCK(lock); \
86             if (!((lock)->excl_locked & WRITE_LOCK) && !(lock)->wait_states)\
87                 (lock) -> readers_reading++;\
88             else\
89                 Afs_Lock_Obtain(lock, READ_LOCK); \
90             LOCK_UNLOCK(lock); \
91         ENDMAC
92
93 #define ObtainReadLockNoBlock(lock, code)\
94         BEGINMAC \
95             LOCK_LOCK(lock); \
96             if (!((lock)->excl_locked & WRITE_LOCK) && !(lock)->wait_states) {\
97                 (lock) -> readers_reading++;\
98                 code = 0;\
99             }\
100             else\
101                 code = -1; \
102             LOCK_UNLOCK(lock); \
103         ENDMAC
104
105 #define ObtainWriteLock(lock)\
106         BEGINMAC \
107             LOCK_LOCK(lock); \
108             if (!(lock)->excl_locked && !(lock)->readers_reading)\
109                 (lock) -> excl_locked = WRITE_LOCK;\
110             else\
111                 Afs_Lock_Obtain(lock, WRITE_LOCK); \
112             LOCK_UNLOCK(lock); \
113         ENDMAC
114
115 #define ObtainWriteLockNoBlock(lock, code)\
116         BEGINMAC \
117             LOCK_LOCK(lock); \
118             if (!(lock)->excl_locked && !(lock)->readers_reading) {\
119                 (lock) -> excl_locked = WRITE_LOCK;\
120                 code = 0;\
121             }\
122             else\
123                 code = -1; \
124             LOCK_UNLOCK(lock); \
125         ENDMAC
126
127 #define ObtainSharedLock(lock)\
128         BEGINMAC \
129             LOCK_LOCK(lock); \
130             if (!(lock)->excl_locked && !(lock)->wait_states)\
131                 (lock) -> excl_locked = SHARED_LOCK;\
132             else\
133                 Afs_Lock_Obtain(lock, SHARED_LOCK); \
134             LOCK_UNLOCK(lock); \
135         ENDMAC
136
137 #define ObtainSharedLockNoBlock(lock, code)\
138         BEGINMAC \
139             LOCK_LOCK(lock); \
140             if (!(lock)->excl_locked && !(lock)->wait_states) {\
141                 (lock) -> excl_locked = SHARED_LOCK;\
142                 code = 0;\
143             }\
144             else\
145                 code = -1; \
146             LOCK_UNLOCK(lock); \
147         ENDMAC
148
149 #define BoostSharedLock(lock)\
150         BEGINMAC \
151             LOCK_LOCK(lock); \
152             if (!(lock)->readers_reading)\
153                 (lock)->excl_locked = WRITE_LOCK;\
154             else\
155                 Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
156             LOCK_UNLOCK(lock); \
157         ENDMAC
158
159 /* this must only be called with a WRITE or boosted SHARED lock! */
160 #define UnboostSharedLock(lock)\
161         BEGINMAC\
162             LOCK_LOCK(lock); \
163             (lock)->excl_locked = SHARED_LOCK; \
164             if((lock)->wait_states) \
165                 Afs_Lock_ReleaseR(lock); \
166             LOCK_UNLOCK(lock); \
167         ENDMAC
168
169 #ifdef notdef
170 /* this is what UnboostSharedLock looked like before the hi-C compiler */
171 /* this must only be called with a WRITE or boosted SHARED lock! */
172 #define UnboostSharedLock(lock)\
173         ((lock)->excl_locked = SHARED_LOCK,\
174         ((lock)->wait_states ?\
175                 Afs_Lock_ReleaseR(lock) : 0))
176 #endif /* notdef */
177
178 #define ReleaseReadLock(lock)\
179         BEGINMAC\
180             LOCK_LOCK(lock); \
181             if (!--(lock)->readers_reading && (lock)->wait_states)\
182                 Afs_Lock_ReleaseW(lock) ; \
183             LOCK_UNLOCK(lock); \
184         ENDMAC
185
186
187 #ifdef notdef
188 /* This is what the previous definition should be, but the hi-C compiler generates
189   a warning for each invocation */
190 #define ReleaseReadLock(lock)\
191         (!--(lock)->readers_reading && (lock)->wait_states ?\
192                 Afs_Lock_ReleaseW(lock)    :\
193                 0)
194 #endif /* notdef */
195
196 #define ReleaseWriteLock(lock)\
197         BEGINMAC\
198             LOCK_LOCK(lock); \
199             (lock)->excl_locked &= ~WRITE_LOCK;\
200             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
201             LOCK_UNLOCK(lock); \
202         ENDMAC
203
204 #ifdef notdef
205 /* This is what the previous definition should be, but the hi-C compiler generates
206    a warning for each invocation */
207 #define ReleaseWriteLock(lock)\
208         ((lock)->excl_locked &= ~WRITE_LOCK,\
209         ((lock)->wait_states ?\
210                 Afs_Lock_ReleaseR(lock) : 0))
211 #endif /* notdef */
212
213 /* can be used on shared or boosted (write) locks */
214 #define ReleaseSharedLock(lock)\
215         BEGINMAC\
216             LOCK_LOCK(lock); \
217             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
218             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
219             LOCK_UNLOCK(lock); \
220         ENDMAC
221
222 #ifdef notdef
223 /* This is what the previous definition should be, but the hi-C compiler generates
224    a warning for each invocation */
225 /* can be used on shared or boosted (write) locks */
226 #define ReleaseSharedLock(lock)\
227         ((lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK),\
228         ((lock)->wait_states ?\
229                 Afs_Lock_ReleaseR(lock) : 0))
230 #endif /* notdef */
231
232 /* convert a write lock to a read lock */
233 #define ConvertWriteToReadLock(lock)\
234         BEGINMAC\
235             LOCK_LOCK(lock); \
236             (lock)->excl_locked &= ~WRITE_LOCK;\
237             (lock)->readers_reading++;\
238             if ((lock)->wait_states & READ_LOCK) \
239                 Afs_Lock_WakeupR(lock) ; \
240             LOCK_UNLOCK(lock); \
241         ENDMAC
242
243 /* I added this next macro to make sure it is safe to nuke a lock -- Mike K. */
244 #define LockWaiters(lock)\
245         ((int) ((lock)->num_waiting))
246
247 #define CheckLock(lock)\
248         ((lock)->excl_locked? (int) -1 : (int) (lock)->readers_reading)
249
250 #define WriteLocked(lock)\
251         ((lock)->excl_locked & WRITE_LOCK)
252
253 #endif /* LOCK_H */