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