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"
30 #include "../afs/sysincludes.h" /* Standard vendor system headers */
31 #include "../afs/afsincludes.h" /* Afs-based standard headers */
32 #include "../afs/afs_stats.h" /* afs statistics */
34 /* probably needed if lock_trace is enabled - should ifdef */
41 void Lock_Init(register struct afs_lock *lock)
44 AFS_STATCNT(Lock_Init);
45 lock -> readers_reading = 0;
46 lock -> excl_locked = 0;
47 lock -> wait_states = 0;
48 lock -> num_waiting = 0;
49 #if defined(INSTRUMENT_LOCKS)
50 lock->pid_last_reader = 0;
52 lock->src_indicator = 0;
53 #endif /* INSTRUMENT_LOCKS */
54 lock->time_waiting.tv_sec = 0;
55 lock->time_waiting.tv_usec = 0;
58 void 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 */
94 void ReleaseLock(register struct afs_lock *lock, int how)
96 if (how == READ_LOCK) {
97 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) Afs_Lock_ReleaseR(lock);
111 } else if (how == SHARED_LOCK) {
112 lock->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);
113 #if defined(INSTRUMENT_LOCKS)
114 lock->pid_writer = 0;
115 #endif /* INSTRUMENT_LOCKS */
116 if (lock->wait_states) Afs_Lock_ReleaseR(lock);
120 void Afs_Lock_Obtain(register struct afs_lock *lock, int how)
122 osi_timeval_t tt1, tt2, et;
124 AFS_STATCNT(Lock_Obtain);
131 case READ_LOCK: lock->num_waiting++;
133 lock -> wait_states |= READ_LOCK;
134 afs_osi_Sleep(&lock->readers_reading);
135 } while (lock->excl_locked & WRITE_LOCK);
137 lock->readers_reading++;
140 case WRITE_LOCK: lock->num_waiting++;
142 lock -> wait_states |= WRITE_LOCK;
143 afs_osi_Sleep(&lock->excl_locked);
144 } while (lock->excl_locked || lock->readers_reading);
146 lock->excl_locked = WRITE_LOCK;
149 case SHARED_LOCK: lock->num_waiting++;
151 lock->wait_states |= SHARED_LOCK;
152 afs_osi_Sleep(&lock->excl_locked);
153 } while (lock->excl_locked);
155 lock->excl_locked = SHARED_LOCK;
158 case BOOSTED_LOCK: lock->num_waiting++;
160 lock->wait_states |= WRITE_LOCK;
161 afs_osi_Sleep(&lock->excl_locked);
162 } while (lock->readers_reading);
164 lock->excl_locked = WRITE_LOCK;
167 default: osi_Panic("afs locktype");
171 afs_stats_GetDiff(et, tt1, tt2);
172 afs_stats_AddTo((lock->time_waiting), et);
175 afs_Trace2(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_POINTER, lock,
176 ICL_TYPE_INT32, how);
180 /* release a lock, giving preference to new readers */
181 void Afs_Lock_ReleaseR(register struct afs_lock *lock)
183 AFS_STATCNT(Lock_ReleaseR);
185 if (lock->wait_states & READ_LOCK) {
186 lock->wait_states &= ~READ_LOCK;
187 afs_osi_Wakeup(&lock->readers_reading);
190 lock->wait_states &= ~EXCL_LOCKS;
191 afs_osi_Wakeup(&lock->excl_locked);
195 /* release a lock, giving preference to new writers */
196 void Afs_Lock_ReleaseW(register struct afs_lock *lock)
198 AFS_STATCNT(Lock_ReleaseW);
200 if (lock->wait_states & EXCL_LOCKS) {
201 lock->wait_states &= ~EXCL_LOCKS;
202 afs_osi_Wakeup(&lock->excl_locked);
205 lock->wait_states &= ~READ_LOCK;
206 afs_osi_Wakeup(&lock->readers_reading);
211 Wait for some change in the lock status.
212 void Lock_Wait(register struct afs_lock *lock)
214 AFS_STATCNT(Lock_Wait);
215 if (lock->readers_reading || lock->excl_locked) return 1;
216 lock->wait_states |= READ_LOCK;
217 afs_osi_Sleep(&lock->readers_reading);
222 /* These next guys exist to provide an interface to drop a lock atomically with
223 * blocking. They're trivial to do in a non-preemptive LWP environment.
226 /* release a write lock and sleep on an address, atomically */
227 void afs_osi_SleepR(register char *addr, register struct afs_lock *alock)
229 AFS_STATCNT(osi_SleepR);
230 ReleaseReadLock(alock);
234 /* release a write lock and sleep on an address, atomically */
235 void afs_osi_SleepW(register char *addr, register struct afs_lock *alock)
237 AFS_STATCNT(osi_SleepW);
238 ReleaseWriteLock(alock);
242 /* release a write lock and sleep on an address, atomically */
243 void afs_osi_SleepS(register char *addr, register struct afs_lock *alock)
245 AFS_STATCNT(osi_SleepS);
246 ReleaseSharedLock(alock);
251 #ifndef AFS_NOBOZO_LOCK
252 /* operations on locks that don't mind if we lock the same thing twice. I'd like to dedicate
253 this function to Sun Microsystems' Version 4.0 virtual memory system, without
254 which this wouldn't have been necessary */
255 void afs_BozonLock(struct afs_bozoLock *alock, struct vcache *avc)
257 AFS_STATCNT(afs_BozonLock);
259 if (alock->count == 0) {
260 /* lock not held, we win */
262 alock->proc = (char *) ttoproc(curthread);
264 #ifdef AFS_64BITPOINTER_ENV
265 /* To shut up SGI compiler on remark(1413) warnings. */
266 alock->proc = (char *) (long)MyPidxx;
267 #else /* AFS_64BITPOINTER_ENV */
268 alock->proc = (char *) MyPidxx;
269 #endif /* AFS_64BITPOINTER_ENV */
274 } else if (alock->proc == (char *) ttoproc(curthread)) {
276 #ifdef AFS_64BITPOINTER_ENV
277 /* To shut up SGI compiler on remark(1413) warnings. */
278 } else if (alock->proc == (char *) (long)MyPidxx) {
279 #else /* AFS_64BITPOINTER_ENV */
280 } else if (alock->proc == (char *) MyPidxx) {
281 #endif /* AFS_64BITPOINTER_ENV */
283 /* lock is held, but by us, so we win anyway */
288 /* lock is held, and not by us; we wait */
289 alock->flags |= AFS_BOZONWAITING;
290 afs_osi_Sleep(alock);
295 /* releasing the same type of lock as defined above */
296 void afs_BozonUnlock(struct afs_bozoLock *alock, struct vcache *avc)
298 AFS_STATCNT(afs_BozonUnlock);
299 if (alock->count <= 0)
300 osi_Panic("BozoUnlock");
301 if ((--alock->count) == 0) {
302 if (alock->flags & AFS_BOZONWAITING) {
303 alock->flags &= ~AFS_BOZONWAITING;
304 afs_osi_Wakeup(alock);
309 void afs_BozonInit(struct afs_bozoLock *alock, struct vcache *avc)
311 AFS_STATCNT(afs_BozonInit);
317 int afs_CheckBozonLock(struct afs_bozoLock *alock)
319 AFS_STATCNT(afs_CheckBozonLock);
320 if (alock->count || (alock->flags & AFS_BOZONWAITING))
325 int afs_CheckBozonLockBlocking(struct afs_bozoLock *alock)
327 AFS_STATCNT(afs_CheckBozonLockBlocking);
328 if (alock->count || (alock->flags & AFS_BOZONWAITING))
330 if (alock->proc != (char *) ttoproc(curthread))
332 #ifdef AFS_64BITPOINTER_ENV
333 /* To shut up SGI compiler on remark(1413) warnings. */
334 if (alock->proc != (char *) (long)MyPidxx)
335 #else /* AFS_64BITPOINTER_ENV */
336 if (alock->proc != (char *) MyPidxx)
337 #endif /* AFS_64BITPOINTER_ENV */
344 /* Not static - used conditionally if lock tracing is enabled */
345 int Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
348 struct afs_icl_log *tlp;
349 struct afs_icl_set *tsp;
351 if (!afs_trclock) return 1;
352 if ((alock) == &afs_icl_lock) return 1;
354 ObtainReadLock(&afs_icl_lock);
356 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
357 if ((alock) == &tlp->lock) traceok = 0;
358 for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
359 if ((alock) == &tsp->lock) traceok = 0;
360 ReleaseReadLock(&afs_icl_lock);
361 if (!traceok) return 1;
363 afs_Trace4(afs_iclSetp, op,
364 ICL_TYPE_STRING, (long)file,
365 ICL_TYPE_INT32, (long)line,
366 ICL_TYPE_POINTER, (long)alock,
367 ICL_TYPE_LONG, (long)type);