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 #ifdef AFS_PTHREAD_ENV
17 # include <opr/lock.h>
21 #define UBIK_INTERNALS 1
26 * Locks hang off of each transaction, with all the transaction hanging off of
27 * the appropriate dbase. This package expects to be used in a two-phase locking
28 * protocol, so it doesn't provide a way to release anything but all of the locks in the
31 * At present, it doesn't support the setting of more than one byte-position lock at a time, that is
32 * the length field must be 1. This doesn't mean that a single transaction can't set more than
35 * It is the responsibility of the user to avoid deadlock by setting locks in a partial order.
37 * #EWOULDBLOCK has been replaced in this file by #EAGAIN. Many Unix's but not
38 * all (eg. HP) do not replace #EWOULDBLOCK with #EAGAIN. The bad news is this
39 * goes over the wire. The good news is that the code path is never triggered
40 * as it requires ulock_getLock to be called with await = 0. And ulock_SetLock
41 * isn't even used in this code base. Since NT doesn't have a native
42 * #EAGAIN, we are replacing all instances of #EWOULDBLOCK with #EAGAIN.
46 #define WouldReadBlock(lock)\
47 ((((lock)->excl_locked & WRITE_LOCK) || (lock)->wait_states) ? 0 : 1)
48 #define WouldWriteBlock(lock)\
49 ((((lock)->excl_locked & WRITE_LOCK) || (lock)->readers_reading) ? 0 : 1)
63 * \brief Set a transaction lock.
64 * \param atype is #LOCKREAD or #LOCKWRITE.
65 * \param await is TRUE if you want to wait for the lock instead of returning
68 * \note The #DBHOLD lock must be held.
71 ulock_getLock(struct ubik_trans *atrans, int atype, int await)
73 struct ubik_dbase *dbase = atrans->dbase;
75 if ((atype != LOCKREAD) && (atype != LOCKWRITE))
78 if (atrans->flags & TRDONE)
81 if (atype != LOCKREAD && (atrans->flags & TRREADWRITE)) {
85 if (atrans->locktype != 0) {
86 ubik_print("Ubik: Internal Error: attempted to take lock twice\n");
91 *ubik_print("Ubik: DEBUG: Thread 0x%x request %s lock\n", lwp_cpptr,
92 * ((atype == LOCKREAD) ? "READ" : "WRITE"));
95 /* Check if the lock would would block */
96 if (!await && !(atrans->flags & TRREADWRITE)) {
97 if (atype == LOCKREAD) {
98 if (WouldReadBlock(&rwlock))
101 if (WouldWriteBlock(&rwlock))
106 /* Create new lock record and add to spec'd transaction:
107 * locktype. This field also tells us if the thread is
108 * waiting for a lock: It will be equal to LOCKWAIT.
110 atrans->locktype = LOCKWAIT;
112 if (atrans->flags & TRREADWRITE) {
113 /* noop; don't actually lock anything for TRREADWRITE */
114 } else if (atype == LOCKREAD) {
115 ObtainReadLock(&rwlock);
117 ObtainWriteLock(&rwlock);
120 atrans->locktype = atype;
123 *ubik_print("Ubik: DEBUG: Thread 0x%x took %s lock\n", lwp_cpptr,
124 * ((atype == LOCKREAD) ? "READ" : "WRITE"));
130 * \brief Release the transaction lock.
133 ulock_relLock(struct ubik_trans *atrans)
135 if (atrans->locktype == LOCKWRITE && (atrans->flags & TRREADWRITE)) {
136 ubik_print("Ubik: Internal Error: unlocking write lock with "
141 if (atrans->flags & TRREADWRITE) {
142 /* noop, TRREADWRITE means we don't actually lock anything */
143 } else if (atrans->locktype == LOCKREAD) {
144 ReleaseReadLock(&rwlock);
145 } else if (atrans->locktype == LOCKWRITE) {
146 ReleaseWriteLock(&rwlock);
150 *ubik_print("Ubik: DEBUG: Thread 0x%x %s unlock\n", lwp_cpptr,
151 * ((atrans->locktype == LOCKREAD) ? "READ" : "WRITE"));
154 atrans->locktype = 0;
159 * \brief debugging hooks
162 ulock_Debug(struct ubik_debug *aparm)
164 aparm->anyReadLocks = rwlock.readers_reading;
165 aparm->anyWriteLocks = ((rwlock.excl_locked == WRITE_LOCK) ? 1 : 0);