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 | ||
29 | #include "afs/sysincludes.h" /* Standard vendor system headers */ | |
30 | #include "afsincludes.h" /* Afs-based standard headers */ | |
31 | #include "afs/afs_stats.h" /* afs statistics */ | |
32 | ||
33 | /* probably needed if lock_trace is enabled - should ifdef */ | |
34 | int afs_trclock = 0; | |
35 | ||
36 | void Lock_ReleaseR(struct afs_lock *lock); | |
37 | void Lock_ReleaseW(struct afs_lock *lock); | |
38 | ||
39 | void | |
40 | Lock_Init(struct afs_lock *lock) | |
41 | { | |
42 | ||
43 | AFS_STATCNT(Lock_Init); | |
44 | lock->readers_reading = 0; | |
45 | lock->excl_locked = 0; | |
46 | lock->wait_states = 0; | |
47 | lock->num_waiting = 0; | |
48 | #if defined(INSTRUMENT_LOCKS) | |
49 | lock->pid_last_reader = 0; | |
50 | lock->pid_writer = 0; | |
51 | lock->src_indicator = 0; | |
52 | #endif /* INSTRUMENT_LOCKS */ | |
53 | lock->time_waiting.tv_sec = 0; | |
54 | lock->time_waiting.tv_usec = 0; | |
55 | } | |
56 | ||
57 | void | |
58 | ObtainLock(struct afs_lock *lock, int how, | |
59 | unsigned int src_indicator) | |
60 | { | |
61 | switch (how) { | |
62 | case READ_LOCK: | |
63 | if (!((lock)->excl_locked & WRITE_LOCK)) | |
64 | (lock)->readers_reading++; | |
65 | else | |
66 | Afs_Lock_Obtain(lock, READ_LOCK); | |
67 | #if defined(INSTRUMENT_LOCKS) | |
68 | (lock)->pid_last_reader = MyPidxx; | |
69 | #endif /* INSTRUMENT_LOCKS */ | |
70 | break; | |
71 | case WRITE_LOCK: | |
72 | if (!(lock)->excl_locked && !(lock)->readers_reading) | |
73 | (lock)->excl_locked = WRITE_LOCK; | |
74 | else | |
75 | Afs_Lock_Obtain(lock, WRITE_LOCK); | |
76 | #if defined(INSTRUMENT_LOCKS) | |
77 | (lock)->pid_writer = MyPidxx; | |
78 | (lock)->src_indicator = src_indicator; | |
79 | #endif /* INSTRUMENT_LOCKS */ | |
80 | break; | |
81 | case SHARED_LOCK: | |
82 | if (!(lock)->excl_locked) | |
83 | (lock)->excl_locked = SHARED_LOCK; | |
84 | else | |
85 | Afs_Lock_Obtain(lock, SHARED_LOCK); | |
86 | #if defined(INSTRUMENT_LOCKS) | |
87 | (lock)->pid_writer = MyPidxx; | |
88 | (lock)->src_indicator = src_indicator; | |
89 | #endif /* INSTRUMENT_LOCKS */ | |
90 | break; | |
91 | } | |
92 | } | |
93 | ||
94 | void | |
95 | ReleaseLock(struct afs_lock *lock, int how) | |
96 | { | |
97 | if (how == READ_LOCK) { | |
98 | if (!--lock->readers_reading && lock->wait_states) { | |
99 | #if defined(INSTRUMENT_LOCKS) | |
100 | if (lock->pid_last_reader == MyPidxx) | |
101 | lock->pid_last_reader = 0; | |
102 | #endif /* INSTRUMENT_LOCKS */ | |
103 | Afs_Lock_ReleaseW(lock); | |
104 | } | |
105 | } else if (how == WRITE_LOCK) { | |
106 | lock->excl_locked &= ~WRITE_LOCK; | |
107 | #if defined(INSTRUMENT_LOCKS) | |
108 | lock->pid_writer = 0; | |
109 | #endif /* INSTRUMENT_LOCKS */ | |
110 | if (lock->wait_states) | |
111 | Afs_Lock_ReleaseR(lock); | |
112 | } else if (how == SHARED_LOCK) { | |
113 | lock->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK); | |
114 | #if defined(INSTRUMENT_LOCKS) | |
115 | lock->pid_writer = 0; | |
116 | #endif /* INSTRUMENT_LOCKS */ | |
117 | if (lock->wait_states) | |
118 | Afs_Lock_ReleaseR(lock); | |
119 | } | |
120 | } | |
121 | ||
122 | void | |
123 | Afs_Lock_Obtain(struct afs_lock *lock, int how) | |
124 | { | |
125 | osi_timeval_t tt1, tt2, et; | |
126 | afs_uint32 us; | |
127 | ||
128 | AFS_STATCNT(Lock_Obtain); | |
129 | ||
130 | AFS_ASSERT_GLOCK(); | |
131 | osi_GetuTime(&tt1); | |
132 | ||
133 | switch (how) { | |
134 | ||
135 | case READ_LOCK: | |
136 | lock->num_waiting++; | |
137 | do { | |
138 | lock->wait_states |= READ_LOCK; | |
139 | afs_osi_Sleep(&lock->readers_reading); | |
140 | } while (lock->excl_locked & WRITE_LOCK); | |
141 | lock->num_waiting--; | |
142 | lock->readers_reading++; | |
143 | break; | |
144 | ||
145 | case WRITE_LOCK: | |
146 | lock->num_waiting++; | |
147 | do { | |
148 | lock->wait_states |= WRITE_LOCK; | |
149 | afs_osi_Sleep(&lock->excl_locked); | |
150 | } while (lock->excl_locked || lock->readers_reading); | |
151 | lock->num_waiting--; | |
152 | lock->excl_locked = WRITE_LOCK; | |
153 | break; | |
154 | ||
155 | case SHARED_LOCK: | |
156 | lock->num_waiting++; | |
157 | do { | |
158 | lock->wait_states |= SHARED_LOCK; | |
159 | afs_osi_Sleep(&lock->excl_locked); | |
160 | } while (lock->excl_locked); | |
161 | lock->num_waiting--; | |
162 | lock->excl_locked = SHARED_LOCK; | |
163 | break; | |
164 | ||
165 | case BOOSTED_LOCK: | |
166 | lock->num_waiting++; | |
167 | do { | |
168 | lock->wait_states |= WRITE_LOCK; | |
169 | afs_osi_Sleep(&lock->excl_locked); | |
170 | } while (lock->readers_reading); | |
171 | lock->num_waiting--; | |
172 | lock->excl_locked = WRITE_LOCK; | |
173 | break; | |
174 | ||
175 | default: | |
176 | osi_Panic("afs locktype"); | |
177 | } | |
178 | ||
179 | osi_GetuTime(&tt2); | |
180 | afs_stats_GetDiff(et, tt1, tt2); | |
181 | afs_stats_AddTo((lock->time_waiting), et); | |
182 | us = (et.tv_sec << 20) + et.tv_usec; | |
183 | ||
184 | if (afs_trclock) { | |
185 | afs_Trace3(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_INT32, us, | |
186 | ICL_TYPE_POINTER, lock, ICL_TYPE_INT32, how); | |
187 | } | |
188 | } | |
189 | ||
190 | /* release a lock, giving preference to new readers */ | |
191 | void | |
192 | Afs_Lock_ReleaseR(struct afs_lock *lock) | |
193 | { | |
194 | AFS_STATCNT(Lock_ReleaseR); | |
195 | AFS_ASSERT_GLOCK(); | |
196 | if (lock->wait_states & READ_LOCK) { | |
197 | lock->wait_states &= ~READ_LOCK; | |
198 | afs_osi_Wakeup(&lock->readers_reading); | |
199 | } else { | |
200 | lock->wait_states &= ~EXCL_LOCKS; | |
201 | afs_osi_Wakeup(&lock->excl_locked); | |
202 | } | |
203 | } | |
204 | ||
205 | /* release a lock, giving preference to new writers */ | |
206 | void | |
207 | Afs_Lock_ReleaseW(struct afs_lock *lock) | |
208 | { | |
209 | AFS_STATCNT(Lock_ReleaseW); | |
210 | AFS_ASSERT_GLOCK(); | |
211 | if (lock->wait_states & EXCL_LOCKS) { | |
212 | lock->wait_states &= ~EXCL_LOCKS; | |
213 | afs_osi_Wakeup(&lock->excl_locked); | |
214 | } else { | |
215 | lock->wait_states &= ~READ_LOCK; | |
216 | afs_osi_Wakeup(&lock->readers_reading); | |
217 | } | |
218 | } | |
219 | ||
220 | /* | |
221 | Wait for some change in the lock status. | |
222 | void Lock_Wait(struct afs_lock *lock) | |
223 | { | |
224 | AFS_STATCNT(Lock_Wait); | |
225 | if (lock->readers_reading || lock->excl_locked) return 1; | |
226 | lock->wait_states |= READ_LOCK; | |
227 | afs_osi_Sleep(&lock->readers_reading); | |
228 | return 0; | |
229 | } | |
230 | */ | |
231 | ||
232 | /* These next guys exist to provide an interface to drop a lock atomically with | |
233 | * blocking. They're trivial to do in a non-preemptive LWP environment. | |
234 | */ | |
235 | ||
236 | /* release a write lock and sleep on an address, atomically */ | |
237 | void | |
238 | afs_osi_SleepR(char *addr, struct afs_lock *alock) | |
239 | { | |
240 | AFS_STATCNT(osi_SleepR); | |
241 | ReleaseReadLock(alock); | |
242 | afs_osi_Sleep(addr); | |
243 | } | |
244 | ||
245 | /* release a write lock and sleep on an address, atomically */ | |
246 | void | |
247 | afs_osi_SleepW(char *addr, struct afs_lock *alock) | |
248 | { | |
249 | AFS_STATCNT(osi_SleepW); | |
250 | ReleaseWriteLock(alock); | |
251 | afs_osi_Sleep(addr); | |
252 | } | |
253 | ||
254 | /* release a write lock and sleep on an address, atomically */ | |
255 | void | |
256 | afs_osi_SleepS(char *addr, struct afs_lock *alock) | |
257 | { | |
258 | AFS_STATCNT(osi_SleepS); | |
259 | ReleaseSharedLock(alock); | |
260 | afs_osi_Sleep(addr); | |
261 | } | |
262 | ||
263 | /* Not static - used conditionally if lock tracing is enabled */ | |
264 | int | |
265 | Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line) | |
266 | { | |
267 | int traceok; | |
268 | struct afs_icl_log *tlp; | |
269 | struct afs_icl_set *tsp; | |
270 | ||
271 | if (!afs_trclock) | |
272 | return 1; | |
273 | if ((alock) == &afs_icl_lock) | |
274 | return 1; | |
275 | ||
276 | ObtainReadLock(&afs_icl_lock); | |
277 | traceok = 1; | |
278 | for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) | |
279 | if ((alock) == &tlp->lock) | |
280 | traceok = 0; | |
281 | for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp) | |
282 | if ((alock) == &tsp->lock) | |
283 | traceok = 0; | |
284 | ReleaseReadLock(&afs_icl_lock); | |
285 | if (!traceok) | |
286 | return 1; | |
287 | ||
288 | afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32, | |
289 | (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG, | |
290 | (long)type); | |
291 | return 0; | |
292 | } |