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