2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /*******************************************************************\
12 * Information Technology Center *
13 * Carnegie-Mellon University *
17 \*******************************************************************/
21 Locking routines for Vice.
25 #include <afsconfig.h>
26 #include "afs/param.h"
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 */
33 /* probably needed if lock_trace is enabled - should ifdef */
36 void Lock_ReleaseR(struct afs_lock
*lock
);
37 void Lock_ReleaseW(struct afs_lock
*lock
);
40 Lock_Init(struct afs_lock
*lock
)
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;
51 lock
->src_indicator
= 0;
52 #endif /* INSTRUMENT_LOCKS */
53 lock
->time_waiting
.tv_sec
= 0;
54 lock
->time_waiting
.tv_usec
= 0;
58 ObtainLock(struct afs_lock
*lock
, int how
,
59 unsigned int src_indicator
)
63 if (!((lock
)->excl_locked
& WRITE_LOCK
))
64 (lock
)->readers_reading
++;
66 Afs_Lock_Obtain(lock
, READ_LOCK
);
67 #if defined(INSTRUMENT_LOCKS)
68 (lock
)->pid_last_reader
= MyPidxx
;
69 #endif /* INSTRUMENT_LOCKS */
72 if (!(lock
)->excl_locked
&& !(lock
)->readers_reading
)
73 (lock
)->excl_locked
= WRITE_LOCK
;
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 */
82 if (!(lock
)->excl_locked
)
83 (lock
)->excl_locked
= SHARED_LOCK
;
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 */
95 ReleaseLock(struct afs_lock
*lock
, int how
)
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
);
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
);
123 Afs_Lock_Obtain(struct afs_lock
*lock
, int how
)
125 osi_timeval_t tt1
, tt2
, et
;
128 AFS_STATCNT(Lock_Obtain
);
138 lock
->wait_states
|= READ_LOCK
;
139 afs_osi_Sleep(&lock
->readers_reading
);
140 } while (lock
->excl_locked
& WRITE_LOCK
);
142 lock
->readers_reading
++;
148 lock
->wait_states
|= WRITE_LOCK
;
149 afs_osi_Sleep(&lock
->excl_locked
);
150 } while (lock
->excl_locked
|| lock
->readers_reading
);
152 lock
->excl_locked
= WRITE_LOCK
;
158 lock
->wait_states
|= SHARED_LOCK
;
159 afs_osi_Sleep(&lock
->excl_locked
);
160 } while (lock
->excl_locked
);
162 lock
->excl_locked
= SHARED_LOCK
;
168 lock
->wait_states
|= WRITE_LOCK
;
169 afs_osi_Sleep(&lock
->excl_locked
);
170 } while (lock
->readers_reading
);
172 lock
->excl_locked
= WRITE_LOCK
;
176 osi_Panic("afs locktype");
180 afs_stats_GetDiff(et
, tt1
, tt2
);
181 afs_stats_AddTo((lock
->time_waiting
), et
);
182 us
= (et
.tv_sec
<< 20) + et
.tv_usec
;
185 afs_Trace3(afs_iclSetp
, CM_TRACE_LOCKSLEPT
, ICL_TYPE_INT32
, us
,
186 ICL_TYPE_POINTER
, lock
, ICL_TYPE_INT32
, how
);
190 /* release a lock, giving preference to new readers */
192 Afs_Lock_ReleaseR(struct afs_lock
*lock
)
194 AFS_STATCNT(Lock_ReleaseR
);
196 if (lock
->wait_states
& READ_LOCK
) {
197 lock
->wait_states
&= ~READ_LOCK
;
198 afs_osi_Wakeup(&lock
->readers_reading
);
200 lock
->wait_states
&= ~EXCL_LOCKS
;
201 afs_osi_Wakeup(&lock
->excl_locked
);
205 /* release a lock, giving preference to new writers */
207 Afs_Lock_ReleaseW(struct afs_lock
*lock
)
209 AFS_STATCNT(Lock_ReleaseW
);
211 if (lock
->wait_states
& EXCL_LOCKS
) {
212 lock
->wait_states
&= ~EXCL_LOCKS
;
213 afs_osi_Wakeup(&lock
->excl_locked
);
215 lock
->wait_states
&= ~READ_LOCK
;
216 afs_osi_Wakeup(&lock
->readers_reading
);
221 Wait for some change in the lock status.
222 void Lock_Wait(struct afs_lock *lock)
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);
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.
236 /* release a write lock and sleep on an address, atomically */
238 afs_osi_SleepR(char *addr
, struct afs_lock
*alock
)
240 AFS_STATCNT(osi_SleepR
);
241 ReleaseReadLock(alock
);
245 /* release a write lock and sleep on an address, atomically */
247 afs_osi_SleepW(char *addr
, struct afs_lock
*alock
)
249 AFS_STATCNT(osi_SleepW
);
250 ReleaseWriteLock(alock
);
254 /* release a write lock and sleep on an address, atomically */
256 afs_osi_SleepS(char *addr
, struct afs_lock
*alock
)
258 AFS_STATCNT(osi_SleepS
);
259 ReleaseSharedLock(alock
);
263 /* Not static - used conditionally if lock tracing is enabled */
265 Afs_Lock_Trace(int op
, struct afs_lock
*alock
, int type
, char *file
, int line
)
268 struct afs_icl_log
*tlp
;
269 struct afs_icl_set
*tsp
;
273 if ((alock
) == &afs_icl_lock
)
276 ObtainReadLock(&afs_icl_lock
);
278 for (tlp
= afs_icl_allLogs
; tlp
; tlp
= tlp
->nextp
)
279 if ((alock
) == &tlp
->lock
)
281 for (tsp
= afs_icl_allSets
; tsp
; tsp
= tsp
->nextp
)
282 if ((alock
) == &tsp
->lock
)
284 ReleaseReadLock(&afs_icl_lock
);
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
,