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 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <sys/types.h>
24 #define UBIK_INTERNALS 1
29 * Locks hang off of each transaction, with all the transaction hanging off of
30 * the appropriate dbase. This package expects to be used in a two-phase locking
31 * protocol, so it doesn't provide a way to release anything but all of the locks in the
34 * At present, it doesn't support the setting of more than one byte-position lock at a time, that is
35 * the length field must be 1. This doesn't mean that a single transaction can't set more than
38 * It is the responsibility of the user to avoid deadlock by setting locks in a partial order.
40 * #EWOULDBLOCK has been replaced in this file by #EAGAIN. Many Unix's but not
41 * all (eg. HP) do not replace #EWOULDBLOCK with #EAGAIN. The bad news is this
42 * goes over the wire. The good news is that the code path is never triggered
43 * as it requires ulock_getLock to be called with await = 0. And ulock_SetLock
44 * isn't even used in this code base. Since NT doesn't have a native
45 * #EAGAIN, we are replacing all instances of #EWOULDBLOCK with #EAGAIN.
49 #define WouldReadBlock(lock)\
50 ((((lock)->excl_locked & WRITE_LOCK) || (lock)->wait_states) ? 0 : 1)
51 #define WouldWriteBlock(lock)\
52 ((((lock)->excl_locked & WRITE_LOCK) || (lock)->readers_reading) ? 0 : 1)
58 * \brief Set a transaction lock.
59 * \param atype is #LOCKREAD or #LOCKWRITE.
60 * \param await is TRUE if you want to wait for the lock instead of returning
63 * \note The #DBHOLD lock must be held.
65 ulock_getLock(atrans, atype, await)
66 struct ubik_trans *atrans;
69 struct ubik_dbase *dbase = atrans->dbase;
71 /* On first pass, initialize the lock */
77 if ((atype != LOCKREAD) && (atype != LOCKWRITE))
80 if (atrans->flags & TRDONE)
83 if (atrans->locktype != 0) {
84 ubik_print("Ubik: Internal Error: attempted to take lock twice\n");
89 *ubik_print("Ubik: DEBUG: Thread 0x%x request %s lock\n", lwp_cpptr,
90 * ((atype == LOCKREAD) ? "READ" : "WRITE"));
93 /* Check if the lock would would block */
95 if (atype == LOCKREAD) {
96 if (WouldReadBlock(&rwlock))
99 if (WouldWriteBlock(&rwlock))
104 /* Create new lock record and add to spec'd transaction:
105 * #if defined(UBIK_PAUSE)
106 * * locktype. Before doing that, set TRSETLOCK,
107 * * to tell udisk_end that another thread (us) is waiting.
109 * * locktype. This field also tells us if the thread is
110 * * waiting for a lock: It will be equal to LOCKWAIT.
113 #if defined(UBIK_PAUSE)
114 if (atrans->flags & TRSETLOCK) {
115 printf("Ubik: Internal Error: TRSETLOCK already set?\n");
118 atrans->flags |= TRSETLOCK;
120 atrans->locktype = LOCKWAIT;
121 #endif /* UBIK_PAUSE */
123 if (atype == LOCKREAD) {
124 ObtainReadLock(&rwlock);
126 ObtainWriteLock(&rwlock);
129 atrans->locktype = atype;
130 #if defined(UBIK_PAUSE)
131 atrans->flags &= ~TRSETLOCK;
133 /* We don't do this here, because this can only happen in SDISK_Lock,
134 * and there's already code there to catch this condition.
136 if (atrans->flags & TRSTALE) {
141 #endif /* UBIK_PAUSE */
144 *ubik_print("Ubik: DEBUG: Thread 0x%x took %s lock\n", lwp_cpptr,
145 * ((atype == LOCKREAD) ? "READ" : "WRITE"));
151 * \brief Release the transaction lock.
154 ulock_relLock(atrans)
155 struct ubik_trans *atrans;
160 if (atrans->locktype == LOCKREAD) {
161 ReleaseReadLock(&rwlock);
162 } else if (atrans->locktype == LOCKWRITE) {
163 ReleaseWriteLock(&rwlock);
167 *ubik_print("Ubik: DEBUG: Thread 0x%x %s unlock\n", lwp_cpptr,
168 * ((atrans->locktype == LOCKREAD) ? "READ" : "WRITE"));
171 atrans->locktype = 0;
176 * \brief debugging hooks
179 struct ubik_debug *aparm;
182 aparm->anyReadLocks = 0;
183 aparm->anyWriteLocks = 0;
185 aparm->anyReadLocks = rwlock.readers_reading;
186 aparm->anyWriteLocks = ((rwlock.excl_locked == WRITE_LOCK) ? 1 : 0);