DEVEL15-linux-warning-reduction-20090318
[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_ReleaseR(struct afs_lock *lock);
39 void Lock_ReleaseW(struct afs_lock *lock);
40
41 void
42 Lock_Init(register struct afs_lock *lock)
43 {
44
45     AFS_STATCNT(Lock_Init);
46     lock->readers_reading = 0;
47     lock->excl_locked = 0;
48     lock->wait_states = 0;
49     lock->num_waiting = 0;
50 #if defined(INSTRUMENT_LOCKS)
51     lock->pid_last_reader = 0;
52     lock->pid_writer = 0;
53     lock->src_indicator = 0;
54 #endif /* INSTRUMENT_LOCKS */
55     lock->time_waiting.tv_sec = 0;
56     lock->time_waiting.tv_usec = 0;
57 }
58 \f
59 void
60 ObtainLock(register struct afs_lock *lock, int how,
61            unsigned int src_indicator)
62 {
63     switch (how) {
64     case READ_LOCK:
65         if (!((lock)->excl_locked & WRITE_LOCK))
66             (lock)->readers_reading++;
67         else
68             Afs_Lock_Obtain(lock, READ_LOCK);
69 #if defined(INSTRUMENT_LOCKS)
70         (lock)->pid_last_reader = MyPidxx;
71 #endif /* INSTRUMENT_LOCKS */
72         break;
73     case WRITE_LOCK:
74         if (!(lock)->excl_locked && !(lock)->readers_reading)
75             (lock)->excl_locked = WRITE_LOCK;
76         else
77             Afs_Lock_Obtain(lock, WRITE_LOCK);
78 #if defined(INSTRUMENT_LOCKS)
79         (lock)->pid_writer = MyPidxx;
80         (lock)->src_indicator = src_indicator;
81 #endif /* INSTRUMENT_LOCKS */
82         break;
83     case SHARED_LOCK:
84         if (!(lock)->excl_locked)
85             (lock)->excl_locked = SHARED_LOCK;
86         else
87             Afs_Lock_Obtain(lock, SHARED_LOCK);
88 #if defined(INSTRUMENT_LOCKS)
89         (lock)->pid_writer = MyPidxx;
90         (lock)->src_indicator = src_indicator;
91 #endif /* INSTRUMENT_LOCKS */
92         break;
93     }
94 }
95
96 void
97 ReleaseLock(register struct afs_lock *lock, int how)
98 {
99     if (how == READ_LOCK) {
100         if (!--lock->readers_reading && lock->wait_states) {
101 #if defined(INSTRUMENT_LOCKS)
102             if (lock->pid_last_reader == MyPidxx)
103                 lock->pid_last_reader = 0;
104 #endif /* INSTRUMENT_LOCKS */
105             Afs_Lock_ReleaseW(lock);
106         }
107     } else if (how == WRITE_LOCK) {
108         lock->excl_locked &= ~WRITE_LOCK;
109 #if defined(INSTRUMENT_LOCKS)
110         lock->pid_writer = 0;
111 #endif /* INSTRUMENT_LOCKS */
112         if (lock->wait_states)
113             Afs_Lock_ReleaseR(lock);
114     } else if (how == SHARED_LOCK) {
115         lock->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);
116 #if defined(INSTRUMENT_LOCKS)
117         lock->pid_writer = 0;
118 #endif /* INSTRUMENT_LOCKS */
119         if (lock->wait_states)
120             Afs_Lock_ReleaseR(lock);
121     }
122 }
123
124 void
125 Afs_Lock_Obtain(register struct afs_lock *lock, int how)
126 {
127     osi_timeval_t tt1, tt2, et;
128     afs_uint32 us;
129
130     AFS_STATCNT(Lock_Obtain);
131
132     AFS_ASSERT_GLOCK();
133     osi_GetuTime(&tt1);
134
135     switch (how) {
136
137     case READ_LOCK:
138         lock->num_waiting++;
139         do {
140             lock->wait_states |= READ_LOCK;
141             afs_osi_Sleep(&lock->readers_reading);
142         } while (lock->excl_locked & WRITE_LOCK);
143         lock->num_waiting--;
144         lock->readers_reading++;
145         break;
146
147     case WRITE_LOCK:
148         lock->num_waiting++;
149         do {
150             lock->wait_states |= WRITE_LOCK;
151             afs_osi_Sleep(&lock->excl_locked);
152         } while (lock->excl_locked || lock->readers_reading);
153         lock->num_waiting--;
154         lock->excl_locked = WRITE_LOCK;
155         break;
156
157     case SHARED_LOCK:
158         lock->num_waiting++;
159         do {
160             lock->wait_states |= SHARED_LOCK;
161             afs_osi_Sleep(&lock->excl_locked);
162         } while (lock->excl_locked);
163         lock->num_waiting--;
164         lock->excl_locked = SHARED_LOCK;
165         break;
166
167     case BOOSTED_LOCK:
168         lock->num_waiting++;
169         do {
170             lock->wait_states |= WRITE_LOCK;
171             afs_osi_Sleep(&lock->excl_locked);
172         } while (lock->readers_reading);
173         lock->num_waiting--;
174         lock->excl_locked = WRITE_LOCK;
175         break;
176
177     default:
178         osi_Panic("afs locktype");
179     }
180
181     osi_GetuTime(&tt2);
182     afs_stats_GetDiff(et, tt1, tt2);
183     afs_stats_AddTo((lock->time_waiting), et);
184     us = (et.tv_sec << 20) + et.tv_usec;
185
186     if (afs_trclock) {
187         afs_Trace3(afs_iclSetp, CM_TRACE_LOCKSLEPT, ICL_TYPE_INT32, us,
188                    ICL_TYPE_POINTER, lock, ICL_TYPE_INT32, how);
189     }
190 }
191
192 /* release a lock, giving preference to new readers */
193 void
194 Afs_Lock_ReleaseR(register struct afs_lock *lock)
195 {
196     AFS_STATCNT(Lock_ReleaseR);
197     AFS_ASSERT_GLOCK();
198     if (lock->wait_states & READ_LOCK) {
199         lock->wait_states &= ~READ_LOCK;
200         afs_osi_Wakeup(&lock->readers_reading);
201     } else {
202         lock->wait_states &= ~EXCL_LOCKS;
203         afs_osi_Wakeup(&lock->excl_locked);
204     }
205 }
206
207 /* release a lock, giving preference to new writers */
208 void
209 Afs_Lock_ReleaseW(register struct afs_lock *lock)
210 {
211     AFS_STATCNT(Lock_ReleaseW);
212     AFS_ASSERT_GLOCK();
213     if (lock->wait_states & EXCL_LOCKS) {
214         lock->wait_states &= ~EXCL_LOCKS;
215         afs_osi_Wakeup(&lock->excl_locked);
216     } else {
217         lock->wait_states &= ~READ_LOCK;
218         afs_osi_Wakeup(&lock->readers_reading);
219     }
220 }
221
222 /*
223 Wait for some change in the lock status.
224 void Lock_Wait(register struct afs_lock *lock)
225 {
226     AFS_STATCNT(Lock_Wait);
227     if (lock->readers_reading || lock->excl_locked) return 1;
228     lock->wait_states |= READ_LOCK;
229     afs_osi_Sleep(&lock->readers_reading);
230     return 0;
231 }
232 */
233
234 /* These next guys exist to provide an interface to drop a lock atomically with
235  * blocking.  They're trivial to do in a non-preemptive LWP environment.
236  */
237
238 /* release a write lock and sleep on an address, atomically */
239 void
240 afs_osi_SleepR(register char *addr, register struct afs_lock *alock)
241 {
242     AFS_STATCNT(osi_SleepR);
243     ReleaseReadLock(alock);
244     afs_osi_Sleep(addr);
245 }
246
247 /* release a write lock and sleep on an address, atomically */
248 void
249 afs_osi_SleepW(register char *addr, register struct afs_lock *alock)
250 {
251     AFS_STATCNT(osi_SleepW);
252     ReleaseWriteLock(alock);
253     afs_osi_Sleep(addr);
254 }
255
256 /* release a write lock and sleep on an address, atomically */
257 void
258 afs_osi_SleepS(register char *addr, register struct afs_lock *alock)
259 {
260     AFS_STATCNT(osi_SleepS);
261     ReleaseSharedLock(alock);
262     afs_osi_Sleep(addr);
263 }
264
265
266 #ifndef AFS_NOBOZO_LOCK
267 /* operations on locks that don't mind if we lock the same thing twice.  I'd like to dedicate
268     this function to Sun Microsystems' Version 4.0 virtual memory system, without
269     which this wouldn't have been necessary */
270 void
271 afs_BozonLock(struct afs_bozoLock *alock, struct vcache *avc)
272 {
273     AFS_STATCNT(afs_BozonLock);
274     while (1) {
275         if (alock->count == 0) {
276             /* lock not held, we win */
277 #ifdef  AFS_SUN5_ENV
278             alock->proc = (char *)ttoproc(curthread);
279 #else
280 #ifdef AFS_64BITPOINTER_ENV
281             /* To shut up SGI compiler on remark(1413) warnings. */
282             alock->proc = (char *)(long)MyPidxx;
283 #else /* AFS_64BITPOINTER_ENV */
284             alock->proc = (char *)MyPidxx;
285 #endif /* AFS_64BITPOINTER_ENV */
286 #endif
287             alock->count = 1;
288             return;
289 #ifdef  AFS_SUN5_ENV
290         } else if (alock->proc == (char *)ttoproc(curthread)) {
291 #else
292 #ifdef AFS_64BITPOINTER_ENV
293             /* To shut up SGI compiler on remark(1413) warnings. */
294         } else if (alock->proc == (char *)(long)MyPidxx) {
295 #else /* AFS_64BITPOINTER_ENV */
296         } else if (alock->proc == (char *)MyPidxx) {
297 #endif /* AFS_64BITPOINTER_ENV */
298 #endif
299             /* lock is held, but by us, so we win anyway */
300             alock->count++;
301             return;
302         } else {
303             /* lock is held, and not by us; we wait */
304             alock->flags |= AFS_BOZONWAITING;
305             afs_osi_Sleep(alock);
306         }
307     }
308 }
309
310 /* releasing the same type of lock as defined above */
311 void
312 afs_BozonUnlock(struct afs_bozoLock *alock, struct vcache *avc)
313 {
314     AFS_STATCNT(afs_BozonUnlock);
315     if (alock->count <= 0)
316         osi_Panic("BozoUnlock");
317     if ((--alock->count) == 0) {
318         if (alock->flags & AFS_BOZONWAITING) {
319             alock->flags &= ~AFS_BOZONWAITING;
320             afs_osi_Wakeup(alock);
321         }
322     }
323 }
324
325 void
326 afs_BozonInit(struct afs_bozoLock *alock, struct vcache *avc)
327 {
328     AFS_STATCNT(afs_BozonInit);
329     alock->count = 0;
330     alock->flags = 0;
331     alock->proc = NULL;
332 }
333
334 int
335 afs_CheckBozonLock(struct afs_bozoLock *alock)
336 {
337     AFS_STATCNT(afs_CheckBozonLock);
338     if (alock->count || (alock->flags & AFS_BOZONWAITING))
339         return 1;
340     return 0;
341 }
342
343 int
344 afs_CheckBozonLockBlocking(struct afs_bozoLock *alock)
345 {
346     AFS_STATCNT(afs_CheckBozonLockBlocking);
347     if (alock->count || (alock->flags & AFS_BOZONWAITING))
348 #ifdef AFS_SUN5_ENV
349         if (alock->proc != (char *)ttoproc(curthread))
350 #else
351 #ifdef AFS_64BITPOINTER_ENV
352         /* To shut up SGI compiler on remark(1413) warnings. */
353         if (alock->proc != (char *)(long)MyPidxx)
354 #else /* AFS_64BITPOINTER_ENV */
355         if (alock->proc != (char *)MyPidxx)
356 #endif /* AFS_64BITPOINTER_ENV */
357 #endif
358             return 1;
359     return 0;
360 }
361 #endif
362
363 /* Not static - used conditionally if lock tracing is enabled */
364 int
365 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
366 {
367     int traceok;
368     struct afs_icl_log *tlp;
369     struct afs_icl_set *tsp;
370
371     if (!afs_trclock)
372         return 1;
373     if ((alock) == &afs_icl_lock)
374         return 1;
375
376     ObtainReadLock(&afs_icl_lock);
377     traceok = 1;
378     for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
379         if ((alock) == &tlp->lock)
380             traceok = 0;
381     for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
382         if ((alock) == &tsp->lock)
383             traceok = 0;
384     ReleaseReadLock(&afs_icl_lock);
385     if (!traceok)
386         return 1;
387
388     afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32,
389                (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG,
390                (long)type);
391     return 0;
392 }