death to register
[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
29 #ifdef AFS_PTHREAD_ENV
30 #include <afs/assert.h>
31 #else /* AFS_PTHREAD_ENV */
32 #include <assert.h>
33 #endif /* AFS_PTHRED_ENV */
34 #include "lwp.h"
35 #include "lock.h"
36 #include <stdio.h>
37
38 #define FALSE   0
39 #define TRUE    1
40
41 void
42 Lock_Init(struct Lock *lock)
43 {
44     lock->readers_reading = 0;
45     lock->excl_locked = 0;
46     lock->wait_states = 0;
47     lock->num_waiting = 0;
48 #ifdef AFS_PTHREAD_ENV
49     assert(pthread_mutex_init(&lock->mutex, (const pthread_mutexattr_t *)0) ==
50            0);
51     assert(pthread_cond_init(&lock->read_cv, (const pthread_condattr_t *)0) ==
52            0);
53     assert(pthread_cond_init(&lock->write_cv, (const pthread_condattr_t *)0)
54            == 0);
55 #endif /* AFS_PTHRED_ENV */
56 }
57
58 void
59 Lock_Destroy(struct Lock *lock)
60 {
61 #ifdef AFS_PTHREAD_ENV
62     assert(pthread_mutex_destroy(&lock->mutex) == 0);
63     assert(pthread_cond_destroy(&lock->read_cv) == 0);
64     assert(pthread_cond_destroy(&lock->write_cv) == 0);
65 #endif /* AFS_PTHRED_ENV */
66 }
67 \f
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             assert(pthread_cond_wait(&lock->read_cv, &lock->mutex) == 0);
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             assert(pthread_cond_wait(&lock->write_cv, &lock->mutex) == 0);
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             assert(pthread_cond_wait(&lock->write_cv, &lock->mutex) == 0);
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             assert(pthread_cond_wait(&lock->write_cv, &lock->mutex) == 0);
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         assert(pthread_cond_broadcast(&lock->read_cv) == 0);
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         assert(pthread_cond_broadcast(&lock->read_cv) == 0);
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         assert(pthread_cond_broadcast(&lock->write_cv) == 0);
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         assert(pthread_cond_broadcast(&lock->write_cv) == 0);
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         assert(pthread_cond_broadcast(&lock->read_cv) == 0);
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 */