linux-updates-20060309
[openafs.git] / src / afs / afs_lock.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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  */
9
10 /*******************************************************************\
11 *                                                                   *
12 *       Information Technology Center                               *
13 *       Carnegie-Mellon University                                  *
14 *                                                                   *
15 *                                                                   *
16 *                                                                   *
17 \*******************************************************************/
18
19
20 /*
21         Locking routines for Vice.
22
23 */
24
25 #include <afsconfig.h>
26 #include "afs/param.h"
27
28 RCSID
29     ("$Header$");
30
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 */
34
35 /* probably needed if lock_trace is enabled - should ifdef */
36 int afs_trclock = 0;
37
38 void Lock_Obtain();
39 void Lock_ReleaseR();
40 void Lock_ReleaseW();
41
42 void
43 Lock_Init(register struct afs_lock *lock)
44 {
45
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;
53     lock->pid_writer = 0;
54     lock->src_indicator = 0;
55 #endif /* INSTRUMENT_LOCKS */
56     lock->time_waiting.tv_sec = 0;
57     lock->time_waiting.tv_usec = 0;
58 }
59 \f
60 void
61 ObtainLock(register struct afs_lock *lock, int how,
62            unsigned int src_indicator)
63 {
64     switch (how) {
65     case READ_LOCK:
66         if (!((lock)->excl_locked & WRITE_LOCK))
67             (lock)->readers_reading++;
68         else
69             Afs_Lock_Obtain(lock, READ_LOCK);
70 #if defined(INSTRUMENT_LOCKS)
71         (lock)->pid_last_reader = MyPidxx;
72 #endif /* INSTRUMENT_LOCKS */
73         break;
74     case WRITE_LOCK:
75         if (!(lock)->excl_locked && !(lock)->readers_reading)
76             (lock)->excl_locked = WRITE_LOCK;
77         else
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 */
83         break;
84     case SHARED_LOCK:
85         if (!(lock)->excl_locked)
86             (lock)->excl_locked = SHARED_LOCK;
87         else
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 */
93         break;
94     }
95 }
96
97 void
98 ReleaseLock(register struct afs_lock *lock, int how)
99 {
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);
107         }
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);
122     }
123 }
124
125 void
126 Afs_Lock_Obtain(register struct afs_lock *lock, int how)
127 {
128     osi_timeval_t tt1, tt2, et;
129     afs_uint32 us;
130
131     AFS_STATCNT(Lock_Obtain);
132
133     AFS_ASSERT_GLOCK();
134     osi_GetuTime(&tt1);
135
136     switch (how) {
137
138     case READ_LOCK:
139         lock->num_waiting++;
140         do {
141             lock->wait_states |= READ_LOCK;
142             afs_osi_Sleep(&lock->readers_reading);
143         } while (lock->excl_locked & WRITE_LOCK);
144         lock->num_waiting--;
145         lock->readers_reading++;
146         break;
147
148     case WRITE_LOCK:
149         lock->num_waiting++;
150         do {
151             lock->wait_states |= WRITE_LOCK;
152             afs_osi_Sleep(&lock->excl_locked);
153         } while (lock->excl_locked || lock->readers_reading);
154         lock->num_waiting--;
155         lock->excl_locked = WRITE_LOCK;
156         break;
157
158     case SHARED_LOCK:
159         lock->num_waiting++;
160         do {
161             lock->wait_states |= SHARED_LOCK;
162             afs_osi_Sleep(&lock->excl_locked);
163         } while (lock->excl_locked);
164         lock->num_waiting--;
165         lock->excl_locked = SHARED_LOCK;
166         break;
167
168     case BOOSTED_LOCK:
169         lock->num_waiting++;
170         do {
171             lock->wait_states |= WRITE_LOCK;
172             afs_osi_Sleep(&lock->excl_locked);
173         } while (lock->readers_reading);
174         lock->num_waiting--;
175         lock->excl_locked = WRITE_LOCK;
176         break;
177
178     default:
179         osi_Panic("afs locktype");
180     }
181
182     osi_GetuTime(&tt2);
183     afs_stats_GetDiff(et, tt1, tt2);
184     afs_stats_AddTo((lock->time_waiting), et);
185     us = (et.tv_sec << 20) + et.tv_usec;
186
187     if (afs_trclock) {
188         afs_Trace3(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_INT32, us,
189                    ICL_TYPE_POINTER, lock, ICL_TYPE_INT32, how);
190     }
191 }
192
193 /* release a lock, giving preference to new readers */
194 void
195 Afs_Lock_ReleaseR(register struct afs_lock *lock)
196 {
197     AFS_STATCNT(Lock_ReleaseR);
198     AFS_ASSERT_GLOCK();
199     if (lock->wait_states & READ_LOCK) {
200         lock->wait_states &= ~READ_LOCK;
201         afs_osi_Wakeup(&lock->readers_reading);
202     } else {
203         lock->wait_states &= ~EXCL_LOCKS;
204         afs_osi_Wakeup(&lock->excl_locked);
205     }
206 }
207
208 /* release a lock, giving preference to new writers */
209 void
210 Afs_Lock_ReleaseW(register struct afs_lock *lock)
211 {
212     AFS_STATCNT(Lock_ReleaseW);
213     AFS_ASSERT_GLOCK();
214     if (lock->wait_states & EXCL_LOCKS) {
215         lock->wait_states &= ~EXCL_LOCKS;
216         afs_osi_Wakeup(&lock->excl_locked);
217     } else {
218         lock->wait_states &= ~READ_LOCK;
219         afs_osi_Wakeup(&lock->readers_reading);
220     }
221 }
222
223 /*
224 Wait for some change in the lock status.
225 void Lock_Wait(register struct afs_lock *lock)
226 {
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);
231     return 0;
232 }
233 */
234
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.
237  */
238
239 /* release a write lock and sleep on an address, atomically */
240 void
241 afs_osi_SleepR(register char *addr, register struct afs_lock *alock)
242 {
243     AFS_STATCNT(osi_SleepR);
244     ReleaseReadLock(alock);
245     afs_osi_Sleep(addr);
246 }
247
248 /* release a write lock and sleep on an address, atomically */
249 void
250 afs_osi_SleepW(register char *addr, register struct afs_lock *alock)
251 {
252     AFS_STATCNT(osi_SleepW);
253     ReleaseWriteLock(alock);
254     afs_osi_Sleep(addr);
255 }
256
257 /* release a write lock and sleep on an address, atomically */
258 void
259 afs_osi_SleepS(register char *addr, register struct afs_lock *alock)
260 {
261     AFS_STATCNT(osi_SleepS);
262     ReleaseSharedLock(alock);
263     afs_osi_Sleep(addr);
264 }
265
266
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 */
271 void
272 afs_BozonLock(struct afs_bozoLock *alock, struct vcache *avc)
273 {
274     AFS_STATCNT(afs_BozonLock);
275     while (1) {
276         if (alock->count == 0) {
277             /* lock not held, we win */
278 #ifdef  AFS_SUN5_ENV
279             alock->proc = (char *)ttoproc(curthread);
280 #else
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 */
287 #endif
288             alock->count = 1;
289             return;
290 #ifdef  AFS_SUN5_ENV
291         } else if (alock->proc == (char *)ttoproc(curthread)) {
292 #else
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 */
299 #endif
300             /* lock is held, but by us, so we win anyway */
301             alock->count++;
302             return;
303         } else {
304             /* lock is held, and not by us; we wait */
305             alock->flags |= AFS_BOZONWAITING;
306             afs_osi_Sleep(alock);
307         }
308     }
309 }
310
311 /* releasing the same type of lock as defined above */
312 void
313 afs_BozonUnlock(struct afs_bozoLock *alock, struct vcache *avc)
314 {
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);
322         }
323     }
324 }
325
326 void
327 afs_BozonInit(struct afs_bozoLock *alock, struct vcache *avc)
328 {
329     AFS_STATCNT(afs_BozonInit);
330     alock->count = 0;
331     alock->flags = 0;
332     alock->proc = NULL;
333 }
334
335 int
336 afs_CheckBozonLock(struct afs_bozoLock *alock)
337 {
338     AFS_STATCNT(afs_CheckBozonLock);
339     if (alock->count || (alock->flags & AFS_BOZONWAITING))
340         return 1;
341     return 0;
342 }
343
344 int
345 afs_CheckBozonLockBlocking(struct afs_bozoLock *alock)
346 {
347     AFS_STATCNT(afs_CheckBozonLockBlocking);
348     if (alock->count || (alock->flags & AFS_BOZONWAITING))
349 #ifdef AFS_SUN5_ENV
350         if (alock->proc != (char *)ttoproc(curthread))
351 #else
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 */
358 #endif
359             return 1;
360     return 0;
361 }
362 #endif
363
364 /* Not static - used conditionally if lock tracing is enabled */
365 int
366 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
367 {
368     int traceok;
369     struct afs_icl_log *tlp;
370     struct afs_icl_set *tsp;
371
372     if (!afs_trclock)
373         return 1;
374     if ((alock) == &afs_icl_lock)
375         return 1;
376
377     ObtainReadLock(&afs_icl_lock);
378     traceok = 1;
379     for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
380         if ((alock) == &tlp->lock)
381             traceok = 0;
382     for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
383         if ((alock) == &tsp->lock)
384             traceok = 0;
385     ReleaseReadLock(&afs_icl_lock);
386     if (!traceok)
387         return 1;
388
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,
391                (long)type);
392     return 0;
393 }