2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /*******************************************************************\
12 * Information Technology Center *
13 * Carnegie-Mellon University *
17 \*******************************************************************/
21 Locking routines for Vice.
25 #include <afsconfig.h>
26 #include "afs/param.h"
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 */
33 /* probably needed if lock_trace is enabled - should ifdef */
36 void Lock_ReleaseR(struct afs_lock *lock);
37 void Lock_ReleaseW(struct afs_lock *lock);
40 Lock_Init(struct afs_lock *lock)
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;
51 lock->src_indicator = 0;
52 #endif /* INSTRUMENT_LOCKS */
53 lock->time_waiting.tv_sec = 0;
54 lock->time_waiting.tv_usec = 0;
58 ObtainLock(struct afs_lock *lock, int how,
59 unsigned int src_indicator)
63 if (!((lock)->excl_locked & WRITE_LOCK))
64 (lock)->readers_reading++;
66 Afs_Lock_Obtain(lock, READ_LOCK);
67 #if defined(INSTRUMENT_LOCKS)
68 (lock)->pid_last_reader = MyPidxx;
69 #endif /* INSTRUMENT_LOCKS */
72 if (!(lock)->excl_locked && !(lock)->readers_reading)
73 (lock)->excl_locked = WRITE_LOCK;
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 */
82 if (!(lock)->excl_locked)
83 (lock)->excl_locked = SHARED_LOCK;
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 */
95 ReleaseLock(struct afs_lock *lock, int how)
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);
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);
123 Afs_Lock_Obtain(struct afs_lock *lock, int how)
125 osi_timeval_t tt1, tt2, et;
128 AFS_STATCNT(Lock_Obtain);
138 lock->wait_states |= READ_LOCK;
139 afs_osi_Sleep(&lock->readers_reading);
140 } while (lock->excl_locked & WRITE_LOCK);
142 lock->readers_reading++;
148 lock->wait_states |= WRITE_LOCK;
149 afs_osi_Sleep(&lock->excl_locked);
150 } while (lock->excl_locked || lock->readers_reading);
152 lock->excl_locked = WRITE_LOCK;
158 lock->wait_states |= SHARED_LOCK;
159 afs_osi_Sleep(&lock->excl_locked);
160 } while (lock->excl_locked);
162 lock->excl_locked = SHARED_LOCK;
168 lock->wait_states |= WRITE_LOCK;
169 afs_osi_Sleep(&lock->excl_locked);
170 } while (lock->readers_reading);
172 lock->excl_locked = WRITE_LOCK;
176 osi_Panic("afs locktype");
180 afs_stats_GetDiff(et, tt1, tt2);
181 afs_stats_AddTo((lock->time_waiting), et);
182 us = (et.tv_sec << 20) + et.tv_usec;
185 afs_Trace3(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_INT32, us,
186 ICL_TYPE_POINTER, lock, ICL_TYPE_INT32, how);
190 /* release a lock, giving preference to new readers */
192 Afs_Lock_ReleaseR(struct afs_lock *lock)
194 AFS_STATCNT(Lock_ReleaseR);
196 if (lock->wait_states & READ_LOCK) {
197 lock->wait_states &= ~READ_LOCK;
198 afs_osi_Wakeup(&lock->readers_reading);
200 lock->wait_states &= ~EXCL_LOCKS;
201 afs_osi_Wakeup(&lock->excl_locked);
205 /* release a lock, giving preference to new writers */
207 Afs_Lock_ReleaseW(struct afs_lock *lock)
209 AFS_STATCNT(Lock_ReleaseW);
211 if (lock->wait_states & EXCL_LOCKS) {
212 lock->wait_states &= ~EXCL_LOCKS;
213 afs_osi_Wakeup(&lock->excl_locked);
215 lock->wait_states &= ~READ_LOCK;
216 afs_osi_Wakeup(&lock->readers_reading);
221 Wait for some change in the lock status.
222 void Lock_Wait(struct afs_lock *lock)
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);
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.
236 /* release a write lock and sleep on an address, atomically */
238 afs_osi_SleepR(char *addr, struct afs_lock *alock)
240 AFS_STATCNT(osi_SleepR);
241 ReleaseReadLock(alock);
245 /* release a write lock and sleep on an address, atomically */
247 afs_osi_SleepW(char *addr, struct afs_lock *alock)
249 AFS_STATCNT(osi_SleepW);
250 ReleaseWriteLock(alock);
254 /* release a write lock and sleep on an address, atomically */
256 afs_osi_SleepS(char *addr, struct afs_lock *alock)
258 AFS_STATCNT(osi_SleepS);
259 ReleaseSharedLock(alock);
264 #ifndef AFS_NOBOZO_LOCK
265 /* operations on locks that don't mind if we lock the same thing twice. I'd like to dedicate
266 this function to Sun Microsystems' Version 4.0 virtual memory system, without
267 which this wouldn't have been necessary */
269 afs_BozonLock(struct afs_bozoLock *alock, struct vcache *avc)
271 AFS_STATCNT(afs_BozonLock);
273 if (alock->count == 0) {
274 /* lock not held, we win */
275 alock->proc = afs_int_to_pointer((iparmtype)(uintptrsz)MyPidxx2Pid(MyPidxx));
278 } else if (alock->proc == afs_int_to_pointer((iparmtype)(uintptrsz)MyPidxx2Pid(MyPidxx))) {
279 /* lock is held, but by us, so we win anyway */
283 /* lock is held, and not by us; we wait */
284 alock->flags |= AFS_BOZONWAITING;
285 afs_osi_Sleep(alock);
290 /* releasing the same type of lock as defined above */
292 afs_BozonUnlock(struct afs_bozoLock *alock, struct vcache *avc)
294 AFS_STATCNT(afs_BozonUnlock);
295 if (alock->count <= 0)
296 osi_Panic("BozoUnlock");
297 if ((--alock->count) == 0) {
298 if (alock->flags & AFS_BOZONWAITING) {
299 alock->flags &= ~AFS_BOZONWAITING;
300 afs_osi_Wakeup(alock);
306 afs_BozonInit(struct afs_bozoLock *alock, struct vcache *avc)
308 AFS_STATCNT(afs_BozonInit);
315 afs_CheckBozonLock(struct afs_bozoLock *alock)
317 AFS_STATCNT(afs_CheckBozonLock);
318 if (alock->count || (alock->flags & AFS_BOZONWAITING))
324 afs_CheckBozonLockBlocking(struct afs_bozoLock *alock)
326 AFS_STATCNT(afs_CheckBozonLockBlocking);
327 if (alock->count || (alock->flags & AFS_BOZONWAITING))
328 if (alock->proc != afs_int_to_pointer((iparmtype)(uintptrsz)MyPidxx2Pid(MyPidxx)))
334 /* Not static - used conditionally if lock tracing is enabled */
336 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
339 struct afs_icl_log *tlp;
340 struct afs_icl_set *tsp;
344 if ((alock) == &afs_icl_lock)
347 ObtainReadLock(&afs_icl_lock);
349 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
350 if ((alock) == &tlp->lock)
352 for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
353 if ((alock) == &tsp->lock)
355 ReleaseReadLock(&afs_icl_lock);
359 afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32,
360 (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG,