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
12 /*******************************************************************\
14 * Information Technology Center *
15 * Carnegie-Mellon University *
19 \*******************************************************************/
23 Locking routines for Vice.
27 #include "../afs/param.h" /* Should be always first */
28 #include "../afs/sysincludes.h" /* Standard vendor system headers */
29 #include "../afs/afsincludes.h" /* Afs-based standard headers */
30 #include "../afs/afs_stats.h" /* afs statistics */
47 register struct afs_lock *lock;
50 AFS_STATCNT(Lock_Init);
51 lock -> readers_reading = 0;
52 lock -> excl_locked = 0;
53 lock -> wait_states = 0;
54 lock -> num_waiting = 0;
55 #if defined(INSTRUMENT_LOCKS)
56 lock->pid_last_reader = 0;
58 lock->src_indicator = 0;
59 #endif /* INSTRUMENT_LOCKS */
60 lock->time_waiting.tv_sec = 0;
61 lock->time_waiting.tv_usec = 0;
64 void ObtainLock(lock, how, src_indicator)
65 register struct afs_lock *lock;
67 unsigned int src_indicator;
71 if (!((lock)->excl_locked & WRITE_LOCK))
72 (lock) -> readers_reading++;
74 Afs_Lock_Obtain(lock, READ_LOCK);
75 #if defined(INSTRUMENT_LOCKS)
76 (lock)->pid_last_reader = MyPidxx;
77 #endif /* INSTRUMENT_LOCKS */
80 if (!(lock)->excl_locked && !(lock)->readers_reading)
81 (lock) -> excl_locked = WRITE_LOCK;
83 Afs_Lock_Obtain(lock, WRITE_LOCK);
84 #if defined(INSTRUMENT_LOCKS)
85 (lock)->pid_writer = MyPidxx;
86 (lock)->src_indicator = src_indicator;
87 #endif /* INSTRUMENT_LOCKS */
90 if (!(lock)->excl_locked)
91 (lock) -> excl_locked = SHARED_LOCK;
93 Afs_Lock_Obtain(lock, SHARED_LOCK);
94 #if defined(INSTRUMENT_LOCKS)
95 (lock)->pid_writer = MyPidxx;
96 (lock)->src_indicator = src_indicator;
97 #endif /* INSTRUMENT_LOCKS */
102 void ReleaseLock(lock, how)
103 register struct afs_lock *lock;
106 if (how == READ_LOCK) {
107 if (!--lock->readers_reading && lock->wait_states)
109 #if defined(INSTRUMENT_LOCKS)
110 if ( lock->pid_last_reader == MyPidxx )
111 lock->pid_last_reader = 0;
112 #endif /* INSTRUMENT_LOCKS */
113 Afs_Lock_ReleaseW(lock);
115 } else if (how == WRITE_LOCK) {
116 lock->excl_locked &= ~WRITE_LOCK;
117 #if defined(INSTRUMENT_LOCKS)
118 lock->pid_writer = 0;
119 #endif /* INSTRUMENT_LOCKS */
120 if (lock->wait_states) Afs_Lock_ReleaseR(lock);
121 } else if (how == SHARED_LOCK) {
122 lock->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);
123 #if defined(INSTRUMENT_LOCKS)
124 lock->pid_writer = 0;
125 #endif /* INSTRUMENT_LOCKS */
126 if (lock->wait_states) Afs_Lock_ReleaseR(lock);
130 Afs_Lock_Obtain(lock, how)
131 register struct afs_lock *lock;
134 osi_timeval_t tt1, tt2, et;
136 AFS_STATCNT(Lock_Obtain);
143 case READ_LOCK: lock->num_waiting++;
145 lock -> wait_states |= READ_LOCK;
146 afs_osi_Sleep(&lock->readers_reading);
147 } while (lock->excl_locked & WRITE_LOCK);
149 lock->readers_reading++;
152 case WRITE_LOCK: lock->num_waiting++;
154 lock -> wait_states |= WRITE_LOCK;
155 afs_osi_Sleep(&lock->excl_locked);
156 } while (lock->excl_locked || lock->readers_reading);
158 lock->excl_locked = WRITE_LOCK;
161 case SHARED_LOCK: lock->num_waiting++;
163 lock->wait_states |= SHARED_LOCK;
164 afs_osi_Sleep(&lock->excl_locked);
165 } while (lock->excl_locked);
167 lock->excl_locked = SHARED_LOCK;
170 case BOOSTED_LOCK: lock->num_waiting++;
172 lock->wait_states |= WRITE_LOCK;
173 afs_osi_Sleep(&lock->excl_locked);
174 } while (lock->readers_reading);
176 lock->excl_locked = WRITE_LOCK;
179 default: osi_Panic("afs locktype");
183 afs_stats_GetDiff(et, tt1, tt2);
184 afs_stats_AddTo((lock->time_waiting), et);
187 afs_Trace2(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_POINTER, lock,
188 ICL_TYPE_INT32, how);
192 /* release a lock, giving preference to new readers */
193 Afs_Lock_ReleaseR(lock)
194 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);
203 lock->wait_states &= ~EXCL_LOCKS;
204 afs_osi_Wakeup(&lock->excl_locked);
208 /* release a lock, giving preference to new writers */
209 Afs_Lock_ReleaseW(lock)
210 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);
219 lock->wait_states &= ~READ_LOCK;
220 afs_osi_Wakeup(&lock->readers_reading);
225 Wait for some change in the lock status.
227 register struct afs_lock *lock; {
228 AFS_STATCNT(Lock_Wait);
229 if (lock->readers_reading || lock->excl_locked) return 1;
230 lock->wait_states |= READ_LOCK;
231 afs_osi_Sleep(&lock->readers_reading);
236 /* These next guys exist to provide an interface to drop a lock atomically with
237 * blocking. They're trivial to do in a non-preemptive LWP environment.
240 /* release a write lock and sleep on an address, atomically */
241 afs_osi_SleepR(addr, alock)
243 register struct afs_lock *alock; {
244 AFS_STATCNT(osi_SleepR);
245 ReleaseReadLock(alock);
249 /* release a write lock and sleep on an address, atomically */
250 afs_osi_SleepW(addr, alock)
252 register struct afs_lock *alock; {
253 AFS_STATCNT(osi_SleepW);
254 ReleaseWriteLock(alock);
258 /* release a write lock and sleep on an address, atomically */
259 afs_osi_SleepS(addr, alock)
261 register struct afs_lock *alock; {
262 AFS_STATCNT(osi_SleepS);
263 ReleaseSharedLock(alock);
268 #ifndef AFS_NOBOZO_LOCK
269 /* operations on locks that don't mind if we lock the same thing twice. I'd like to dedicate
270 this function to Sun Microsystems' Version 4.0 virtual memory system, without
271 which this wouldn't have been necessary */
272 void afs_BozonLock(alock, avc)
274 struct afs_bozoLock *alock; {
275 AFS_STATCNT(afs_BozonLock);
277 if (alock->count == 0) {
278 /* lock not held, we win */
280 alock->proc = (char *) ttoproc(curthread);
282 #ifdef AFS_64BITPOINTER_ENV
283 /* To shut up SGI compiler on remark(1413) warnings. */
284 alock->proc = (char *) (long)MyPidxx;
285 #else /* AFS_64BITPOINTER_ENV */
286 alock->proc = (char *) MyPidxx;
287 #endif /* AFS_64BITPOINTER_ENV */
292 } else if (alock->proc == (char *) ttoproc(curthread)) {
294 #ifdef AFS_64BITPOINTER_ENV
295 /* To shut up SGI compiler on remark(1413) warnings. */
296 } else if (alock->proc == (char *) (long)MyPidxx) {
297 #else /* AFS_64BITPOINTER_ENV */
298 } else if (alock->proc == (char *) MyPidxx) {
299 #endif /* AFS_64BITPOINTER_ENV */
301 /* lock is held, but by us, so we win anyway */
306 /* lock is held, and not by us; we wait */
307 alock->flags |= AFS_BOZONWAITING;
308 afs_osi_Sleep(alock);
313 /* releasing the same type of lock as defined above */
314 void afs_BozonUnlock(alock, avc)
316 struct afs_bozoLock *alock; {
317 AFS_STATCNT(afs_BozonUnlock);
318 if (alock->count <= 0)
319 osi_Panic("BozoUnlock");
320 if ((--alock->count) == 0) {
321 if (alock->flags & AFS_BOZONWAITING) {
322 alock->flags &= ~AFS_BOZONWAITING;
323 afs_osi_Wakeup(alock);
328 void afs_BozonInit(alock, avc)
330 struct afs_bozoLock *alock; {
331 AFS_STATCNT(afs_BozonInit);
334 alock->proc = (char *) 0;
337 afs_CheckBozonLock(alock)
338 struct afs_bozoLock *alock; {
339 AFS_STATCNT(afs_CheckBozonLock);
340 if (alock->count || (alock->flags & AFS_BOZONWAITING))
345 afs_CheckBozonLockBlocking(alock)
346 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 */