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