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"
31 #include "afs/sysincludes.h" /* Standard vendor system headers */
32 #include "afsincludes.h" /* Afs-based standard headers */
33 #include "afs/afs_stats.h" /* afs statistics */
35 /* probably needed if lock_trace is enabled - should ifdef */
38 void Lock_ReleaseR(struct afs_lock *lock);
39 void Lock_ReleaseW(struct afs_lock *lock);
42 Lock_Init(register struct afs_lock *lock)
45 AFS_STATCNT(Lock_Init);
46 lock->readers_reading = 0;
47 lock->excl_locked = 0;
48 lock->wait_states = 0;
49 lock->num_waiting = 0;
50 #if defined(INSTRUMENT_LOCKS)
51 lock->pid_last_reader = 0;
53 lock->src_indicator = 0;
54 #endif /* INSTRUMENT_LOCKS */
55 lock->time_waiting.tv_sec = 0;
56 lock->time_waiting.tv_usec = 0;
60 ObtainLock(register struct afs_lock *lock, int how,
61 unsigned int src_indicator)
65 if (!((lock)->excl_locked & WRITE_LOCK))
66 (lock)->readers_reading++;
68 Afs_Lock_Obtain(lock, READ_LOCK);
69 #if defined(INSTRUMENT_LOCKS)
70 (lock)->pid_last_reader = MyPidxx;
71 #endif /* INSTRUMENT_LOCKS */
74 if (!(lock)->excl_locked && !(lock)->readers_reading)
75 (lock)->excl_locked = WRITE_LOCK;
77 Afs_Lock_Obtain(lock, WRITE_LOCK);
78 #if defined(INSTRUMENT_LOCKS)
79 (lock)->pid_writer = MyPidxx;
80 (lock)->src_indicator = src_indicator;
81 #endif /* INSTRUMENT_LOCKS */
84 if (!(lock)->excl_locked)
85 (lock)->excl_locked = SHARED_LOCK;
87 Afs_Lock_Obtain(lock, SHARED_LOCK);
88 #if defined(INSTRUMENT_LOCKS)
89 (lock)->pid_writer = MyPidxx;
90 (lock)->src_indicator = src_indicator;
91 #endif /* INSTRUMENT_LOCKS */
97 ReleaseLock(register struct afs_lock *lock, int how)
99 if (how == READ_LOCK) {
100 if (!--lock->readers_reading && lock->wait_states) {
101 #if defined(INSTRUMENT_LOCKS)
102 if (lock->pid_last_reader == MyPidxx)
103 lock->pid_last_reader = 0;
104 #endif /* INSTRUMENT_LOCKS */
105 Afs_Lock_ReleaseW(lock);
107 } else if (how == WRITE_LOCK) {
108 lock->excl_locked &= ~WRITE_LOCK;
109 #if defined(INSTRUMENT_LOCKS)
110 lock->pid_writer = 0;
111 #endif /* INSTRUMENT_LOCKS */
112 if (lock->wait_states)
113 Afs_Lock_ReleaseR(lock);
114 } else if (how == SHARED_LOCK) {
115 lock->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);
116 #if defined(INSTRUMENT_LOCKS)
117 lock->pid_writer = 0;
118 #endif /* INSTRUMENT_LOCKS */
119 if (lock->wait_states)
120 Afs_Lock_ReleaseR(lock);
125 Afs_Lock_Obtain(register struct afs_lock *lock, int how)
127 osi_timeval_t tt1, tt2, et;
130 AFS_STATCNT(Lock_Obtain);
140 lock->wait_states |= READ_LOCK;
141 afs_osi_Sleep(&lock->readers_reading);
142 } while (lock->excl_locked & WRITE_LOCK);
144 lock->readers_reading++;
150 lock->wait_states |= WRITE_LOCK;
151 afs_osi_Sleep(&lock->excl_locked);
152 } while (lock->excl_locked || lock->readers_reading);
154 lock->excl_locked = WRITE_LOCK;
160 lock->wait_states |= SHARED_LOCK;
161 afs_osi_Sleep(&lock->excl_locked);
162 } while (lock->excl_locked);
164 lock->excl_locked = SHARED_LOCK;
170 lock->wait_states |= WRITE_LOCK;
171 afs_osi_Sleep(&lock->excl_locked);
172 } while (lock->readers_reading);
174 lock->excl_locked = WRITE_LOCK;
178 osi_Panic("afs locktype");
182 afs_stats_GetDiff(et, tt1, tt2);
183 afs_stats_AddTo((lock->time_waiting), et);
184 us = (et.tv_sec << 20) + et.tv_usec;
187 afs_Trace3(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_INT32, us,
188 ICL_TYPE_POINTER, lock, ICL_TYPE_INT32, how);
192 /* release a lock, giving preference to new readers */
194 Afs_Lock_ReleaseR(register struct afs_lock *lock)
196 AFS_STATCNT(Lock_ReleaseR);
198 if (lock->wait_states & READ_LOCK) {
199 lock->wait_states &= ~READ_LOCK;
200 afs_osi_Wakeup(&lock->readers_reading);
202 lock->wait_states &= ~EXCL_LOCKS;
203 afs_osi_Wakeup(&lock->excl_locked);
207 /* release a lock, giving preference to new writers */
209 Afs_Lock_ReleaseW(register struct afs_lock *lock)
211 AFS_STATCNT(Lock_ReleaseW);
213 if (lock->wait_states & EXCL_LOCKS) {
214 lock->wait_states &= ~EXCL_LOCKS;
215 afs_osi_Wakeup(&lock->excl_locked);
217 lock->wait_states &= ~READ_LOCK;
218 afs_osi_Wakeup(&lock->readers_reading);
223 Wait for some change in the lock status.
224 void Lock_Wait(register struct afs_lock *lock)
226 AFS_STATCNT(Lock_Wait);
227 if (lock->readers_reading || lock->excl_locked) return 1;
228 lock->wait_states |= READ_LOCK;
229 afs_osi_Sleep(&lock->readers_reading);
234 /* These next guys exist to provide an interface to drop a lock atomically with
235 * blocking. They're trivial to do in a non-preemptive LWP environment.
238 /* release a write lock and sleep on an address, atomically */
240 afs_osi_SleepR(register char *addr, register struct afs_lock *alock)
242 AFS_STATCNT(osi_SleepR);
243 ReleaseReadLock(alock);
247 /* release a write lock and sleep on an address, atomically */
249 afs_osi_SleepW(register char *addr, register struct afs_lock *alock)
251 AFS_STATCNT(osi_SleepW);
252 ReleaseWriteLock(alock);
256 /* release a write lock and sleep on an address, atomically */
258 afs_osi_SleepS(register char *addr, register struct afs_lock *alock)
260 AFS_STATCNT(osi_SleepS);
261 ReleaseSharedLock(alock);
266 #ifndef AFS_NOBOZO_LOCK
267 /* operations on locks that don't mind if we lock the same thing twice. I'd like to dedicate
268 this function to Sun Microsystems' Version 4.0 virtual memory system, without
269 which this wouldn't have been necessary */
271 afs_BozonLock(struct afs_bozoLock *alock, struct vcache *avc)
273 AFS_STATCNT(afs_BozonLock);
275 if (alock->count == 0) {
276 /* lock not held, we win */
278 alock->proc = (char *)ttoproc(curthread);
280 #ifdef AFS_64BITPOINTER_ENV
281 /* To shut up SGI compiler on remark(1413) warnings. */
282 alock->proc = (char *)(long)MyPidxx;
283 #else /* AFS_64BITPOINTER_ENV */
284 alock->proc = (char *)MyPidxx;
285 #endif /* AFS_64BITPOINTER_ENV */
290 } else if (alock->proc == (char *)ttoproc(curthread)) {
292 #ifdef AFS_64BITPOINTER_ENV
293 /* To shut up SGI compiler on remark(1413) warnings. */
294 } else if (alock->proc == (char *)(long)MyPidxx) {
295 #else /* AFS_64BITPOINTER_ENV */
296 } else if (alock->proc == (char *)MyPidxx) {
297 #endif /* AFS_64BITPOINTER_ENV */
299 /* lock is held, but by us, so we win anyway */
303 /* lock is held, and not by us; we wait */
304 alock->flags |= AFS_BOZONWAITING;
305 afs_osi_Sleep(alock);
310 /* releasing the same type of lock as defined above */
312 afs_BozonUnlock(struct afs_bozoLock *alock, struct vcache *avc)
314 AFS_STATCNT(afs_BozonUnlock);
315 if (alock->count <= 0)
316 osi_Panic("BozoUnlock");
317 if ((--alock->count) == 0) {
318 if (alock->flags & AFS_BOZONWAITING) {
319 alock->flags &= ~AFS_BOZONWAITING;
320 afs_osi_Wakeup(alock);
326 afs_BozonInit(struct afs_bozoLock *alock, struct vcache *avc)
328 AFS_STATCNT(afs_BozonInit);
335 afs_CheckBozonLock(struct afs_bozoLock *alock)
337 AFS_STATCNT(afs_CheckBozonLock);
338 if (alock->count || (alock->flags & AFS_BOZONWAITING))
344 afs_CheckBozonLockBlocking(struct afs_bozoLock *alock)
346 AFS_STATCNT(afs_CheckBozonLockBlocking);
347 if (alock->count || (alock->flags & AFS_BOZONWAITING))
349 if (alock->proc != (char *)ttoproc(curthread))
351 #ifdef AFS_64BITPOINTER_ENV
352 /* To shut up SGI compiler on remark(1413) warnings. */
353 if (alock->proc != (char *)(long)MyPidxx)
354 #else /* AFS_64BITPOINTER_ENV */
355 if (alock->proc != (char *)MyPidxx)
356 #endif /* AFS_64BITPOINTER_ENV */
363 /* Not static - used conditionally if lock tracing is enabled */
365 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
368 struct afs_icl_log *tlp;
369 struct afs_icl_set *tsp;
373 if ((alock) == &afs_icl_lock)
376 ObtainReadLock(&afs_icl_lock);
378 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
379 if ((alock) == &tlp->lock)
381 for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
382 if ((alock) == &tsp->lock)
384 ReleaseReadLock(&afs_icl_lock);
388 afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32,
389 (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG,