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 */
43 Lock_Init(register struct afs_lock *lock)
46 AFS_STATCNT(Lock_Init);
47 lock->readers_reading = 0;
48 lock->excl_locked = 0;
49 lock->wait_states = 0;
50 lock->num_waiting = 0;
51 #if defined(INSTRUMENT_LOCKS)
52 lock->pid_last_reader = 0;
54 lock->src_indicator = 0;
55 #endif /* INSTRUMENT_LOCKS */
56 lock->time_waiting.tv_sec = 0;
57 lock->time_waiting.tv_usec = 0;
61 ObtainLock(register struct afs_lock *lock, int how,
62 unsigned int src_indicator)
66 if (!((lock)->excl_locked & WRITE_LOCK))
67 (lock)->readers_reading++;
69 Afs_Lock_Obtain(lock, READ_LOCK);
70 #if defined(INSTRUMENT_LOCKS)
71 (lock)->pid_last_reader = MyPidxx;
72 #endif /* INSTRUMENT_LOCKS */
75 if (!(lock)->excl_locked && !(lock)->readers_reading)
76 (lock)->excl_locked = WRITE_LOCK;
78 Afs_Lock_Obtain(lock, WRITE_LOCK);
79 #if defined(INSTRUMENT_LOCKS)
80 (lock)->pid_writer = MyPidxx;
81 (lock)->src_indicator = src_indicator;
82 #endif /* INSTRUMENT_LOCKS */
85 if (!(lock)->excl_locked)
86 (lock)->excl_locked = SHARED_LOCK;
88 Afs_Lock_Obtain(lock, SHARED_LOCK);
89 #if defined(INSTRUMENT_LOCKS)
90 (lock)->pid_writer = MyPidxx;
91 (lock)->src_indicator = src_indicator;
92 #endif /* INSTRUMENT_LOCKS */
98 ReleaseLock(register struct afs_lock *lock, int how)
100 if (how == READ_LOCK) {
101 if (!--lock->readers_reading && lock->wait_states) {
102 #if defined(INSTRUMENT_LOCKS)
103 if (lock->pid_last_reader == MyPidxx)
104 lock->pid_last_reader = 0;
105 #endif /* INSTRUMENT_LOCKS */
106 Afs_Lock_ReleaseW(lock);
108 } else if (how == WRITE_LOCK) {
109 lock->excl_locked &= ~WRITE_LOCK;
110 #if defined(INSTRUMENT_LOCKS)
111 lock->pid_writer = 0;
112 #endif /* INSTRUMENT_LOCKS */
113 if (lock->wait_states)
114 Afs_Lock_ReleaseR(lock);
115 } else if (how == SHARED_LOCK) {
116 lock->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);
117 #if defined(INSTRUMENT_LOCKS)
118 lock->pid_writer = 0;
119 #endif /* INSTRUMENT_LOCKS */
120 if (lock->wait_states)
121 Afs_Lock_ReleaseR(lock);
126 Afs_Lock_Obtain(register struct afs_lock *lock, int how)
128 osi_timeval_t tt1, tt2, et;
131 AFS_STATCNT(Lock_Obtain);
141 lock->wait_states |= READ_LOCK;
142 afs_osi_Sleep(&lock->readers_reading);
143 } while (lock->excl_locked & WRITE_LOCK);
145 lock->readers_reading++;
151 lock->wait_states |= WRITE_LOCK;
152 afs_osi_Sleep(&lock->excl_locked);
153 } while (lock->excl_locked || lock->readers_reading);
155 lock->excl_locked = WRITE_LOCK;
161 lock->wait_states |= SHARED_LOCK;
162 afs_osi_Sleep(&lock->excl_locked);
163 } while (lock->excl_locked);
165 lock->excl_locked = SHARED_LOCK;
171 lock->wait_states |= WRITE_LOCK;
172 afs_osi_Sleep(&lock->excl_locked);
173 } while (lock->readers_reading);
175 lock->excl_locked = WRITE_LOCK;
179 osi_Panic("afs locktype");
183 afs_stats_GetDiff(et, tt1, tt2);
184 afs_stats_AddTo((lock->time_waiting), et);
185 us = (et.tv_sec << 20) + et.tv_usec;
188 afs_Trace3(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_INT32, us,
189 ICL_TYPE_POINTER, lock, ICL_TYPE_INT32, how);
193 /* release a lock, giving preference to new readers */
195 Afs_Lock_ReleaseR(register struct afs_lock *lock)
197 AFS_STATCNT(Lock_ReleaseR);
199 if (lock->wait_states & READ_LOCK) {
200 lock->wait_states &= ~READ_LOCK;
201 afs_osi_Wakeup(&lock->readers_reading);
203 lock->wait_states &= ~EXCL_LOCKS;
204 afs_osi_Wakeup(&lock->excl_locked);
208 /* release a lock, giving preference to new writers */
210 Afs_Lock_ReleaseW(register struct afs_lock *lock)
212 AFS_STATCNT(Lock_ReleaseW);
214 if (lock->wait_states & EXCL_LOCKS) {
215 lock->wait_states &= ~EXCL_LOCKS;
216 afs_osi_Wakeup(&lock->excl_locked);
218 lock->wait_states &= ~READ_LOCK;
219 afs_osi_Wakeup(&lock->readers_reading);
224 Wait for some change in the lock status.
225 void Lock_Wait(register struct afs_lock *lock)
227 AFS_STATCNT(Lock_Wait);
228 if (lock->readers_reading || lock->excl_locked) return 1;
229 lock->wait_states |= READ_LOCK;
230 afs_osi_Sleep(&lock->readers_reading);
235 /* These next guys exist to provide an interface to drop a lock atomically with
236 * blocking. They're trivial to do in a non-preemptive LWP environment.
239 /* release a write lock and sleep on an address, atomically */
241 afs_osi_SleepR(register char *addr, register struct afs_lock *alock)
243 AFS_STATCNT(osi_SleepR);
244 ReleaseReadLock(alock);
248 /* release a write lock and sleep on an address, atomically */
250 afs_osi_SleepW(register char *addr, register struct afs_lock *alock)
252 AFS_STATCNT(osi_SleepW);
253 ReleaseWriteLock(alock);
257 /* release a write lock and sleep on an address, atomically */
259 afs_osi_SleepS(register char *addr, register struct afs_lock *alock)
261 AFS_STATCNT(osi_SleepS);
262 ReleaseSharedLock(alock);
267 #ifndef AFS_NOBOZO_LOCK
268 /* operations on locks that don't mind if we lock the same thing twice. I'd like to dedicate
269 this function to Sun Microsystems' Version 4.0 virtual memory system, without
270 which this wouldn't have been necessary */
272 afs_BozonLock(struct afs_bozoLock *alock, struct vcache *avc)
274 AFS_STATCNT(afs_BozonLock);
276 if (alock->count == 0) {
277 /* lock not held, we win */
279 alock->proc = (char *)ttoproc(curthread);
281 #ifdef AFS_64BITPOINTER_ENV
282 /* To shut up SGI compiler on remark(1413) warnings. */
283 alock->proc = (char *)(long)MyPidxx;
284 #else /* AFS_64BITPOINTER_ENV */
285 alock->proc = (char *)MyPidxx;
286 #endif /* AFS_64BITPOINTER_ENV */
291 } else if (alock->proc == (char *)ttoproc(curthread)) {
293 #ifdef AFS_64BITPOINTER_ENV
294 /* To shut up SGI compiler on remark(1413) warnings. */
295 } else if (alock->proc == (char *)(long)MyPidxx) {
296 #else /* AFS_64BITPOINTER_ENV */
297 } else if (alock->proc == (char *)MyPidxx) {
298 #endif /* AFS_64BITPOINTER_ENV */
300 /* lock is held, but by us, so we win anyway */
304 /* lock is held, and not by us; we wait */
305 alock->flags |= AFS_BOZONWAITING;
306 afs_osi_Sleep(alock);
311 /* releasing the same type of lock as defined above */
313 afs_BozonUnlock(struct afs_bozoLock *alock, struct vcache *avc)
315 AFS_STATCNT(afs_BozonUnlock);
316 if (alock->count <= 0)
317 osi_Panic("BozoUnlock");
318 if ((--alock->count) == 0) {
319 if (alock->flags & AFS_BOZONWAITING) {
320 alock->flags &= ~AFS_BOZONWAITING;
321 afs_osi_Wakeup(alock);
327 afs_BozonInit(struct afs_bozoLock *alock, struct vcache *avc)
329 AFS_STATCNT(afs_BozonInit);
336 afs_CheckBozonLock(struct afs_bozoLock *alock)
338 AFS_STATCNT(afs_CheckBozonLock);
339 if (alock->count || (alock->flags & AFS_BOZONWAITING))
345 afs_CheckBozonLockBlocking(struct afs_bozoLock *alock)
347 AFS_STATCNT(afs_CheckBozonLockBlocking);
348 if (alock->count || (alock->flags & AFS_BOZONWAITING))
350 if (alock->proc != (char *)ttoproc(curthread))
352 #ifdef AFS_64BITPOINTER_ENV
353 /* To shut up SGI compiler on remark(1413) warnings. */
354 if (alock->proc != (char *)(long)MyPidxx)
355 #else /* AFS_64BITPOINTER_ENV */
356 if (alock->proc != (char *)MyPidxx)
357 #endif /* AFS_64BITPOINTER_ENV */
364 /* Not static - used conditionally if lock tracing is enabled */
366 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
369 struct afs_icl_log *tlp;
370 struct afs_icl_set *tsp;
374 if ((alock) == &afs_icl_lock)
377 ObtainReadLock(&afs_icl_lock);
379 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
380 if ((alock) == &tlp->lock)
382 for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
383 if ((alock) == &tsp->lock)
385 ReleaseReadLock(&afs_icl_lock);
389 afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32,
390 (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG,