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(register 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(register 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(register 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(register 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(register 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(register 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(register 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(register char *addr, register 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(register char *addr, register 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(register char *addr, register 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 */
276 alock->proc = (char *)ttoproc(curthread);
278 #ifdef AFS_64BITPOINTER_ENV
279 /* To shut up SGI compiler on remark(1413) warnings. */
280 alock->proc = (char *)(long)MyPidxx;
281 #else /* AFS_64BITPOINTER_ENV */
282 alock->proc = (char *)MyPidxx;
283 #endif /* AFS_64BITPOINTER_ENV */
288 } else if (alock->proc == (char *)ttoproc(curthread)) {
290 #ifdef AFS_64BITPOINTER_ENV
291 /* To shut up SGI compiler on remark(1413) warnings. */
292 } else if (alock->proc == (char *)(long)MyPidxx) {
293 #else /* AFS_64BITPOINTER_ENV */
294 } else if (alock->proc == (char *)MyPidxx) {
295 #endif /* AFS_64BITPOINTER_ENV */
297 /* lock is held, but by us, so we win anyway */
301 /* lock is held, and not by us; we wait */
302 alock->flags |= AFS_BOZONWAITING;
303 afs_osi_Sleep(alock);
308 /* releasing the same type of lock as defined above */
310 afs_BozonUnlock(struct afs_bozoLock *alock, struct vcache *avc)
312 AFS_STATCNT(afs_BozonUnlock);
313 if (alock->count <= 0)
314 osi_Panic("BozoUnlock");
315 if ((--alock->count) == 0) {
316 if (alock->flags & AFS_BOZONWAITING) {
317 alock->flags &= ~AFS_BOZONWAITING;
318 afs_osi_Wakeup(alock);
324 afs_BozonInit(struct afs_bozoLock *alock, struct vcache *avc)
326 AFS_STATCNT(afs_BozonInit);
333 afs_CheckBozonLock(struct afs_bozoLock *alock)
335 AFS_STATCNT(afs_CheckBozonLock);
336 if (alock->count || (alock->flags & AFS_BOZONWAITING))
342 afs_CheckBozonLockBlocking(struct afs_bozoLock *alock)
344 AFS_STATCNT(afs_CheckBozonLockBlocking);
345 if (alock->count || (alock->flags & AFS_BOZONWAITING))
347 if (alock->proc != (char *)ttoproc(curthread))
349 #ifdef AFS_64BITPOINTER_ENV
350 /* To shut up SGI compiler on remark(1413) warnings. */
351 if (alock->proc != (char *)(long)MyPidxx)
352 #else /* AFS_64BITPOINTER_ENV */
353 if (alock->proc != (char *)MyPidxx)
354 #endif /* AFS_64BITPOINTER_ENV */
361 /* Not static - used conditionally if lock tracing is enabled */
363 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
366 struct afs_icl_log *tlp;
367 struct afs_icl_set *tsp;
371 if ((alock) == &afs_icl_lock)
374 ObtainReadLock(&afs_icl_lock);
376 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
377 if ((alock) == &tlp->lock)
379 for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
380 if ((alock) == &tsp->lock)
382 ReleaseReadLock(&afs_icl_lock);
386 afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32,
387 (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG,