ubik: convert ubik_print to ViceLog
[openafs.git] / src / ubik / 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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include <afs/opr.h>
16 #ifdef AFS_PTHREAD_ENV
17 # include <opr/lock.h>
18 #endif
19 #include <lock.h>
20 #include <afs/afsutil.h>
21
22 #define UBIK_INTERNALS 1
23 #include "ubik.h"
24 #include "ubik_int.h"
25
26 /*! \file
27  * Locks hang off of each transaction, with all the transaction hanging off of
28  * the appropriate dbase.  This package expects to be used in a two-phase locking
29  * protocol, so it doesn't provide a way to release anything but all of the locks in the
30  * transaction.
31  *
32  * At present, it doesn't support the setting of more than one byte-position lock at a time, that is
33  * the length field must be 1.  This doesn't mean that a single transaction can't set more than
34  * one lock, however.
35  *
36  * It is the responsibility of the user to avoid deadlock by setting locks in a partial order.
37  *
38  * #EWOULDBLOCK has been replaced in this file by #EAGAIN. Many Unix's but not
39  * all (eg. HP) do not replace #EWOULDBLOCK with #EAGAIN. The bad news is this
40  * goes over the wire. The good news is that the code path is never triggered
41  * as it requires ulock_getLock to be called with await = 0. And ulock_SetLock
42  * isn't even used in this code base. Since NT doesn't have a native
43  * #EAGAIN, we are replacing all instances of #EWOULDBLOCK with #EAGAIN.
44  *
45  */
46
47 #define WouldReadBlock(lock)\
48   ((((lock)->excl_locked & WRITE_LOCK) || (lock)->wait_states) ? 0 : 1)
49 #define WouldWriteBlock(lock)\
50   ((((lock)->excl_locked & WRITE_LOCK) || (lock)->readers_reading) ? 0 : 1)
51
52 struct Lock rwlock;
53
54 /*!
55  * \Initialize locks
56  */
57 void
58 ulock_Init(void)
59 {
60     Lock_Init(&rwlock);
61 }
62
63 /*!
64  * \brief Set a transaction lock.
65  * \param atype is #LOCKREAD or #LOCKWRITE.
66  * \param await is TRUE if you want to wait for the lock instead of returning
67  * #EWOULDBLOCK.
68  *
69  * \note The #DBHOLD lock must be held.
70  */
71 extern int
72 ulock_getLock(struct ubik_trans *atrans, int atype, int await)
73 {
74     struct ubik_dbase *dbase = atrans->dbase;
75
76     if ((atype != LOCKREAD) && (atype != LOCKWRITE))
77         return EINVAL;
78
79     if (atrans->flags & TRDONE)
80         return UDONE;
81
82     if (atype != LOCKREAD && (atrans->flags & TRREADWRITE)) {
83         return EINVAL;
84     }
85
86     if (atrans->locktype != 0) {
87         ViceLog(0, ("Ubik: Internal Error: attempted to take lock twice\n"));
88         abort();
89     }
90
91 /*
92  *ViceLog(0, ("Ubik: DEBUG: Thread 0x%x request %s lock\n", lwp_cpptr,
93  *           ((atype == LOCKREAD) ? "READ" : "WRITE")));
94  */
95
96     /* Check if the lock would would block */
97     if (!await && !(atrans->flags & TRREADWRITE)) {
98         if (atype == LOCKREAD) {
99             if (WouldReadBlock(&rwlock))
100                 return EAGAIN;
101         } else {
102             if (WouldWriteBlock(&rwlock))
103                 return EAGAIN;
104         }
105     }
106
107     /* Create new lock record and add to spec'd transaction:
108      * locktype. This field also tells us if the thread is
109      * waiting for a lock: It will be equal to LOCKWAIT.
110      */
111     atrans->locktype = LOCKWAIT;
112     DBRELE(dbase);
113     if (atrans->flags & TRREADWRITE) {
114         /* noop; don't actually lock anything for TRREADWRITE */
115     } else if (atype == LOCKREAD) {
116         ObtainReadLock(&rwlock);
117     } else {
118         ObtainWriteLock(&rwlock);
119     }
120     DBHOLD(dbase);
121     atrans->locktype = atype;
122
123 /*
124  *ViceLog(0, ("Ubik: DEBUG: Thread 0x%x took %s lock\n", lwp_cpptr,
125  *           ((atype == LOCKREAD) ? "READ" : "WRITE")));
126  */
127     return 0;
128 }
129
130 /*!
131  * \brief Release the transaction lock.
132  */
133 void
134 ulock_relLock(struct ubik_trans *atrans)
135 {
136     if (atrans->locktype == LOCKWRITE && (atrans->flags & TRREADWRITE)) {
137         ViceLog(0, ("Ubik: Internal Error: unlocking write lock with "
138                    "TRREADWRITE?\n"));
139         abort();
140     }
141
142     if (atrans->flags & TRREADWRITE) {
143         /* noop, TRREADWRITE means we don't actually lock anything */
144     } else if (atrans->locktype == LOCKREAD) {
145         ReleaseReadLock(&rwlock);
146     } else if (atrans->locktype == LOCKWRITE) {
147         ReleaseWriteLock(&rwlock);
148     }
149
150 /*
151  *ViceLog(0, ("Ubik: DEBUG: Thread 0x%x %s unlock\n", lwp_cpptr,
152  *           ((atrans->locktype == LOCKREAD) ? "READ" : "WRITE")));
153  */
154
155     atrans->locktype = 0;
156     return;
157 }
158
159 /*!
160  * \brief debugging hooks
161  */
162 void
163 ulock_Debug(struct ubik_debug *aparm)
164 {
165     aparm->anyReadLocks = rwlock.readers_reading;
166     aparm->anyWriteLocks = ((rwlock.excl_locked == WRITE_LOCK) ? 1 : 0);
167 }