ab1911105fd66cc7aed65197bc52247c5310a83f
[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 ObtainWriteLock(lock)\
91         BEGINMAC \
92             LOCK_LOCK(lock) \
93             if (!(lock)->excl_locked && !(lock)->readers_reading)\
94                 (lock) -> excl_locked = WRITE_LOCK;\
95             else\
96                 Afs_Lock_Obtain(lock, WRITE_LOCK); \
97             LOCK_UNLOCK(lock) \
98         ENDMAC
99     
100 #define ObtainSharedLock(lock)\
101         BEGINMAC \
102             LOCK_LOCK(lock) \
103             if (!(lock)->excl_locked && !(lock)->wait_states)\
104                 (lock) -> excl_locked = SHARED_LOCK;\
105             else\
106                 Afs_Lock_Obtain(lock, SHARED_LOCK); \
107             LOCK_UNLOCK(lock) \
108         ENDMAC
109
110 #define BoostSharedLock(lock)\
111         BEGINMAC \
112             LOCK_LOCK(lock) \
113             if (!(lock)->readers_reading)\
114                 (lock)->excl_locked = WRITE_LOCK;\
115             else\
116                 Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
117             LOCK_UNLOCK(lock) \
118         ENDMAC
119
120 /* this must only be called with a WRITE or boosted SHARED lock! */
121 #define UnboostSharedLock(lock)\
122         BEGINMAC\
123             LOCK_LOCK(lock) \
124             (lock)->excl_locked = SHARED_LOCK; \
125             if((lock)->wait_states) \
126                 Afs_Lock_ReleaseR(lock); \
127             LOCK_UNLOCK(lock) \
128         ENDMAC
129
130 #ifdef notdef
131 /* this is what UnboostSharedLock looked like before the hi-C compiler */
132 /* this must only be called with a WRITE or boosted SHARED lock! */
133 #define UnboostSharedLock(lock)\
134         ((lock)->excl_locked = SHARED_LOCK,\
135         ((lock)->wait_states ?\
136                 Afs_Lock_ReleaseR(lock) : 0))
137 #endif /* notdef */
138
139 #define ReleaseReadLock(lock)\
140         BEGINMAC\
141             LOCK_LOCK(lock) \
142             if (!--(lock)->readers_reading && (lock)->wait_states)\
143                 Afs_Lock_ReleaseW(lock) ; \
144             LOCK_UNLOCK(lock) \
145         ENDMAC
146
147
148 #ifdef notdef
149 /* This is what the previous definition should be, but the hi-C compiler generates
150   a warning for each invocation */
151 #define ReleaseReadLock(lock)\
152         (!--(lock)->readers_reading && (lock)->wait_states ?\
153                 Afs_Lock_ReleaseW(lock)    :\
154                 0)
155 #endif /* notdef */
156
157 #define ReleaseWriteLock(lock)\
158         BEGINMAC\
159             LOCK_LOCK(lock) \
160             (lock)->excl_locked &= ~WRITE_LOCK;\
161             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
162             LOCK_UNLOCK(lock) \
163         ENDMAC
164
165 #ifdef notdef
166 /* This is what the previous definition should be, but the hi-C compiler generates
167    a warning for each invocation */
168 #define ReleaseWriteLock(lock)\
169         ((lock)->excl_locked &= ~WRITE_LOCK,\
170         ((lock)->wait_states ?\
171                 Afs_Lock_ReleaseR(lock) : 0))
172 #endif /* notdef */
173
174 /* can be used on shared or boosted (write) locks */
175 #define ReleaseSharedLock(lock)\
176         BEGINMAC\
177             LOCK_LOCK(lock) \
178             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
179             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
180             LOCK_UNLOCK(lock) \
181         ENDMAC
182
183 #ifdef notdef
184 /* This is what the previous definition should be, but the hi-C compiler generates
185    a warning for each invocation */
186 /* can be used on shared or boosted (write) locks */
187 #define ReleaseSharedLock(lock)\
188         ((lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK),\
189         ((lock)->wait_states ?\
190                 Afs_Lock_ReleaseR(lock) : 0))
191 #endif /* notdef */
192
193 /* convert a write lock to a read lock */
194 #define ConvertWriteToReadLock(lock)\
195         BEGINMAC\
196             LOCK_LOCK(lock) \
197             (lock)->excl_locked &= ~WRITE_LOCK;\
198             (lock)->readers_reading++;\
199             if ((lock)->wait_states & READ_LOCK) \
200                 Afs_Lock_WakeupR(lock) ; \
201             LOCK_UNLOCK(lock) \
202         ENDMAC
203
204 /* I added this next macro to make sure it is safe to nuke a lock -- Mike K. */
205 #define LockWaiters(lock)\
206         ((int) ((lock)->num_waiting))
207
208 #define CheckLock(lock)\
209         ((lock)->excl_locked? (int) -1 : (int) (lock)->readers_reading)
210
211 #define WriteLocked(lock)\
212         ((lock)->excl_locked & WRITE_LOCK)
213
214 #endif /* LOCK_H */