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