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