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(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(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(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(struct afs_lock *lock, int how)
125 osi_timeval32_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(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(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(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(char *addr, 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(char *addr, 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(char *addr, struct afs_lock *alock)
258 AFS_STATCNT(osi_SleepS);
259 ReleaseSharedLock(alock);
263 /* Not static - used conditionally if lock tracing is enabled */
265 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
268 struct afs_icl_log *tlp;
269 struct afs_icl_set *tsp;
273 if ((alock) == &afs_icl_lock)
276 ObtainReadLock(&afs_icl_lock);
278 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
279 if ((alock) == &tlp->lock)
281 for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
282 if ((alock) == &tsp->lock)
284 ReleaseReadLock(&afs_icl_lock);
288 afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32,
289 (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG,