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