448985324f356e5201c030d2670ab2c30881bfcb
[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(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
57 void
58 ObtainLock(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(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(struct afs_lock *lock, int how)
124 {
125     osi_timeval32_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(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(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(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(char *addr, 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(char *addr, 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(char *addr, struct afs_lock *alock)
257 {
258     AFS_STATCNT(osi_SleepS);
259     ReleaseSharedLock(alock);
260     afs_osi_Sleep(addr);
261 }
262
263 /* Not static - used conditionally if lock tracing is enabled */
264 int
265 Afs_Lock_Trace(int op, struct afs_lock *alock, int type, char *file, int line)
266 {
267     int traceok;
268     struct afs_icl_log *tlp;
269     struct afs_icl_set *tsp;
270
271     if (!afs_trclock)
272         return 1;
273     if ((alock) == &afs_icl_lock)
274         return 1;
275
276     ObtainReadLock(&afs_icl_lock);
277     traceok = 1;
278     for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp)
279         if ((alock) == &tlp->lock)
280             traceok = 0;
281     for (tsp = afs_icl_allSets; tsp; tsp = tsp->nextp)
282         if ((alock) == &tsp->lock)
283             traceok = 0;
284     ReleaseReadLock(&afs_icl_lock);
285     if (!traceok)
286         return 1;
287
288     afs_Trace4(afs_iclSetp, op, ICL_TYPE_STRING, (long)file, ICL_TYPE_INT32,
289                (long)line, ICL_TYPE_POINTER, (long)alock, ICL_TYPE_LONG,
290                (long)type);
291     return 0;
292 }