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