libroken: Build on windows
[openafs.git] / src / lwp / lock.c
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 /*
21         Locking routines for Vice.
22
23 */
24
25 #include <afsconfig.h>
26 #include <afs/param.h>
27
28 #ifdef AFS_PTHREAD_ENV
29 #include <afs/afs_assert.h>
30 /* can't include this in lwp, rx hasn't built yet */
31
32 #include <roken.h>
33 #include <rx/rx.h>
34 #else
35 #include <assert.h>
36 #endif
37
38 #include "lwp.h"
39 #include "lock.h"
40 #include <stdio.h>
41
42 #define FALSE   0
43 #define TRUE    1
44
45 void
46 Lock_Init(struct Lock *lock)
47 {
48     lock->readers_reading = 0;
49     lock->excl_locked = 0;
50     lock->wait_states = 0;
51     lock->num_waiting = 0;
52 #ifdef AFS_PTHREAD_ENV
53     MUTEX_INIT(&lock->mutex, "lock", MUTEX_DEFAULT, 0);
54     CV_INIT(&lock->read_cv, "read", CV_DEFAULT, 0);
55     CV_INIT(&lock->write_cv, "write", CV_DEFAULT, 0);
56 #endif /* AFS_PTHREAD_ENV */
57 }
58
59 void
60 Lock_Destroy(struct Lock *lock)
61 {
62 #ifdef AFS_PTHREAD_ENV
63     MUTEX_DESTROY(&lock->mutex);
64     CV_DESTROY(&lock->read_cv);
65     CV_DESTROY(&lock->write_cv);
66 #endif /* AFS_PTHREAD_ENV */
67 }
68
69 void
70 Afs_Lock_Obtain(struct Lock *lock, int how)
71 {
72     switch (how) {
73
74     case READ_LOCK:
75         lock->num_waiting++;
76         do {
77             lock->wait_states |= READ_LOCK;
78 #ifdef AFS_PTHREAD_ENV
79             CV_WAIT(&lock->read_cv, &lock->mutex);
80 #else /* AFS_PTHREAD_ENV */
81             LWP_WaitProcess(&lock->readers_reading);
82 #endif /* AFS_PTHREAD_ENV */
83         } while (lock->excl_locked & WRITE_LOCK);
84         lock->num_waiting--;
85         lock->readers_reading++;
86         break;
87
88     case WRITE_LOCK:
89         lock->num_waiting++;
90         do {
91             lock->wait_states |= WRITE_LOCK;
92 #ifdef AFS_PTHREAD_ENV
93             CV_WAIT(&lock->write_cv, &lock->mutex);
94 #else /* AFS_PTHREAD_ENV */
95             LWP_WaitProcess(&lock->excl_locked);
96 #endif /* AFS_PTHREAD_ENV */
97         } while (lock->excl_locked || lock->readers_reading);
98         lock->num_waiting--;
99         lock->excl_locked = WRITE_LOCK;
100         break;
101
102     case SHARED_LOCK:
103         lock->num_waiting++;
104         do {
105             lock->wait_states |= SHARED_LOCK;
106 #ifdef AFS_PTHREAD_ENV
107             CV_WAIT(&lock->write_cv, &lock->mutex);
108 #else /* AFS_PTHREAD_ENV */
109             LWP_WaitProcess(&lock->excl_locked);
110 #endif /* AFS_PTHREAD_ENV */
111         } while (lock->excl_locked);
112         lock->num_waiting--;
113         lock->excl_locked = SHARED_LOCK;
114         break;
115
116     case BOOSTED_LOCK:
117         lock->num_waiting++;
118         do {
119             lock->wait_states |= WRITE_LOCK;
120 #ifdef AFS_PTHREAD_ENV
121             CV_WAIT(&lock->write_cv, &lock->mutex);
122 #else /* AFS_PTHREAD_ENV */
123             LWP_WaitProcess(&lock->excl_locked);
124 #endif /* AFS_PTHREAD_ENV */
125         } while (lock->readers_reading);
126         lock->num_waiting--;
127         lock->excl_locked = WRITE_LOCK;
128         break;
129
130     default:
131         printf("Can't happen, bad LOCK type: %d\n", how);
132         assert(0);
133     }
134 }
135
136 /* wake up readers waiting for this lock */
137 void
138 Afs_Lock_WakeupR(struct Lock *lock)
139 {
140     if (lock->wait_states & READ_LOCK) {
141         lock->wait_states &= ~READ_LOCK;
142 #ifdef AFS_PTHREAD_ENV
143         CV_BROADCAST(&lock->read_cv);
144 #else /* AFS_PTHREAD_ENV */
145         LWP_NoYieldSignal(&lock->readers_reading);
146 #endif /* AFS_PTHREAD_ENV */
147     }
148 }
149
150 /* release a lock, giving preference to new readers */
151 void
152 Afs_Lock_ReleaseR(struct Lock *lock)
153 {
154     if (lock->wait_states & READ_LOCK) {
155         lock->wait_states &= ~READ_LOCK;
156 #ifdef AFS_PTHREAD_ENV
157         CV_BROADCAST(&lock->read_cv);
158 #else /* AFS_PTHREAD_ENV */
159         LWP_NoYieldSignal(&lock->readers_reading);
160 #endif /* AFS_PTHREAD_ENV */
161     } else {
162         lock->wait_states &= ~EXCL_LOCKS;
163 #ifdef AFS_PTHREAD_ENV
164         CV_BROADCAST(&lock->write_cv);
165 #else /* AFS_PTHREAD_ENV */
166         LWP_NoYieldSignal(&lock->excl_locked);
167 #endif /* AFS_PTHREAD_ENV */
168     }
169 }
170
171 /* release a lock, giving preference to new writers */
172 void
173 Afs_Lock_ReleaseW(struct Lock *lock)
174 {
175     if (lock->wait_states & EXCL_LOCKS) {
176         lock->wait_states &= ~EXCL_LOCKS;
177 #ifdef AFS_PTHREAD_ENV
178         CV_BROADCAST(&lock->write_cv);
179 #else /* AFS_PTHREAD_ENV */
180         LWP_NoYieldSignal(&lock->excl_locked);
181 #endif /* AFS_PTHREAD_ENV */
182     } else {
183         lock->wait_states &= ~READ_LOCK;
184 #ifdef AFS_PTHREAD_ENV
185         CV_BROADCAST(&lock->read_cv);
186 #else /* AFS_PTHREAD_ENV */
187         LWP_NoYieldSignal(&lock->readers_reading);
188 #endif /* AFS_PTHREAD_ENV */
189     }
190 }
191
192 #ifndef AFS_PTHREAD_ENV
193 /* These next guys exist to provide an interface to drop a lock atomically with
194  * blocking.  They're trivial to do in a non-preemptive LWP environment.
195  */
196
197 /* release a write lock and sleep on an address, atomically */
198 void
199 LWP_WaitProcessR(void *addr, struct Lock *alock)
200 {
201     ReleaseReadLock(alock);
202     LWP_WaitProcess(addr);
203 }
204
205 /* release a write lock and sleep on an address, atomically */
206 void
207 LWP_WaitProcessW(void *addr, struct Lock *alock)
208 {
209     ReleaseWriteLock(alock);
210     LWP_WaitProcess(addr);
211 }
212
213 /* release a write lock and sleep on an address, atomically */
214 void
215 LWP_WaitProcessS(void *addr, struct Lock *alock)
216 {
217     ReleaseSharedLock(alock);
218     LWP_WaitProcess(addr);
219 }
220 #endif /* AFS_PTHREAD_ENV */