Merge 1.8.0~pre4 packaging into master
[pkg-k5-afs_openafs.git] / src / afs / afs_lock.c
blobf97e6ed65374be0e7ef2cd4dafe69726794d95fa
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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
8 */
10 /*******************************************************************\
11 * *
12 * Information Technology Center *
13 * Carnegie-Mellon University *
14 * *
15 * *
16 * *
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 */
34 int afs_trclock = 0;
36 void Lock_ReleaseR(struct afs_lock *lock);
37 void Lock_ReleaseW(struct afs_lock *lock);
39 void
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;
50 lock->pid_writer = 0;
51 lock->src_indicator = 0;
52 #endif /* INSTRUMENT_LOCKS */
53 lock->time_waiting.tv_sec = 0;
54 lock->time_waiting.tv_usec = 0;
57 void
58 ObtainLock(struct afs_lock *lock, int how,
59 unsigned int src_indicator)
61 switch (how) {
62 case READ_LOCK:
63 if (!((lock)->excl_locked & WRITE_LOCK))
64 (lock)->readers_reading++;
65 else
66 Afs_Lock_Obtain(lock, READ_LOCK);
67 #if defined(INSTRUMENT_LOCKS)
68 (lock)->pid_last_reader = MyPidxx;
69 #endif /* INSTRUMENT_LOCKS */
70 break;
71 case WRITE_LOCK:
72 if (!(lock)->excl_locked && !(lock)->readers_reading)
73 (lock)->excl_locked = WRITE_LOCK;
74 else
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 */
80 break;
81 case SHARED_LOCK:
82 if (!(lock)->excl_locked)
83 (lock)->excl_locked = SHARED_LOCK;
84 else
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 */
90 break;
94 void
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);
122 void
123 Afs_Lock_Obtain(struct afs_lock *lock, int how)
125 osi_timeval_t tt1, tt2, et;
126 afs_uint32 us;
128 AFS_STATCNT(Lock_Obtain);
130 AFS_ASSERT_GLOCK();
131 osi_GetuTime(&tt1);
133 switch (how) {
135 case READ_LOCK:
136 lock->num_waiting++;
137 do {
138 lock->wait_states |= READ_LOCK;
139 afs_osi_Sleep(&lock->readers_reading);
140 } while (lock->excl_locked & WRITE_LOCK);
141 lock->num_waiting--;
142 lock->readers_reading++;
143 break;
145 case WRITE_LOCK:
146 lock->num_waiting++;
147 do {
148 lock->wait_states |= WRITE_LOCK;
149 afs_osi_Sleep(&lock->excl_locked);
150 } while (lock->excl_locked || lock->readers_reading);
151 lock->num_waiting--;
152 lock->excl_locked = WRITE_LOCK;
153 break;
155 case SHARED_LOCK:
156 lock->num_waiting++;
157 do {
158 lock->wait_states |= SHARED_LOCK;
159 afs_osi_Sleep(&lock->excl_locked);
160 } while (lock->excl_locked);
161 lock->num_waiting--;
162 lock->excl_locked = SHARED_LOCK;
163 break;
165 case BOOSTED_LOCK:
166 lock->num_waiting++;
167 do {
168 lock->wait_states |= WRITE_LOCK;
169 afs_osi_Sleep(&lock->excl_locked);
170 } while (lock->readers_reading);
171 lock->num_waiting--;
172 lock->excl_locked = WRITE_LOCK;
173 break;
175 default:
176 osi_Panic("afs locktype");
179 osi_GetuTime(&tt2);
180 afs_stats_GetDiff(et, tt1, tt2);
181 afs_stats_AddTo((lock->time_waiting), et);
182 us = (et.tv_sec << 20) + et.tv_usec;
184 if (afs_trclock) {
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 */
191 void
192 Afs_Lock_ReleaseR(struct afs_lock *lock)
194 AFS_STATCNT(Lock_ReleaseR);
195 AFS_ASSERT_GLOCK();
196 if (lock->wait_states & READ_LOCK) {
197 lock->wait_states &= ~READ_LOCK;
198 afs_osi_Wakeup(&lock->readers_reading);
199 } else {
200 lock->wait_states &= ~EXCL_LOCKS;
201 afs_osi_Wakeup(&lock->excl_locked);
205 /* release a lock, giving preference to new writers */
206 void
207 Afs_Lock_ReleaseW(struct afs_lock *lock)
209 AFS_STATCNT(Lock_ReleaseW);
210 AFS_ASSERT_GLOCK();
211 if (lock->wait_states & EXCL_LOCKS) {
212 lock->wait_states &= ~EXCL_LOCKS;
213 afs_osi_Wakeup(&lock->excl_locked);
214 } else {
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);
228 return 0;
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 */
237 void
238 afs_osi_SleepR(char *addr, struct afs_lock *alock)
240 AFS_STATCNT(osi_SleepR);
241 ReleaseReadLock(alock);
242 afs_osi_Sleep(addr);
245 /* release a write lock and sleep on an address, atomically */
246 void
247 afs_osi_SleepW(char *addr, struct afs_lock *alock)
249 AFS_STATCNT(osi_SleepW);
250 ReleaseWriteLock(alock);
251 afs_osi_Sleep(addr);
254 /* release a write lock and sleep on an address, atomically */
255 void
256 afs_osi_SleepS(char *addr, struct afs_lock *alock)
258 AFS_STATCNT(osi_SleepS);
259 ReleaseSharedLock(alock);
260 afs_osi_Sleep(addr);
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)
267 int traceok;
268 struct afs_icl_log *tlp;
269 struct afs_icl_set *tsp;
271 if (!afs_trclock)
272 return 1;
273 if ((alock) == &afs_icl_lock)
274 return 1;
276 ObtainReadLock(&afs_icl_lock);
277 traceok = 1;
278 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
279 if ((alock) == &tlp->lock)
280 traceok = 0;
281 for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
282 if ((alock) == &tsp->lock)
283 traceok = 0;
284 ReleaseReadLock(&afs_icl_lock);
285 if (!traceok)
286 return 1;
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,
290 (long)type);
291 return 0;