Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / afs_lock.c
CommitLineData
805e021f
CE
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 */
34int afs_trclock = 0;
35
36void Lock_ReleaseR(struct afs_lock *lock);
37void Lock_ReleaseW(struct afs_lock *lock);
38
39void
40Lock_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
57void
58ObtainLock(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
94void
95ReleaseLock(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
122void
123Afs_Lock_Obtain(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 */
191void
192Afs_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 */
206void
207Afs_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/*
221Wait for some change in the lock status.
222void 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 */
237void
238afs_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 */
246void
247afs_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 */
255void
256afs_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 */
264int
265Afs_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}