Commit | Line | Data |
---|---|---|
805e021f CE |
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 */ |