afsconfig-and-rcsid-all-around-20010705
[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 <afs/param.h>
11 #include <afsconfig.h>
12
13 RCSID("$Header$");
14
15 #include <sys/types.h>
16 #ifndef AFS_NT40_ENV
17 #include <sys/file.h>
18 #endif
19 #include <errno.h>
20 #include <lock.h>
21 #include <rx/xdr.h>
22
23 #define UBIK_INTERNALS 1
24 #include "ubik.h"
25 #include "ubik_int.h"
26
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 int         rwlockinit=1;
54
55 /* Set a transaction lock.  Atype is LOCKREAD or LOCKWRITE, await is
56  * true if you want to wait for the lock instead of returning
57  * EWOULDLBOCK.
58  *
59  * The DBHOLD lock must be held.
60  */
61 ulock_getLock(atrans, atype, await)
62   struct ubik_trans *atrans;
63   int               atype, await;
64 {
65   struct ubik_trans *tt;
66   struct ubik_dbase *dbase=atrans->dbase;
67
68   /* On first pass, initialize the lock */
69   if (rwlockinit) {
70      Lock_Init(&rwlock);
71      rwlockinit = 0;
72   }
73
74   if ((atype != LOCKREAD) && (atype != LOCKWRITE))
75      return EINVAL;
76
77   if (atrans->flags & TRDONE)
78      return UDONE;
79
80   if (atrans->locktype != 0) {
81      ubik_print("Ubik: Internal Error: attempted to take lock twice\n");
82      abort();
83   }
84
85 /*
86  *ubik_print("Ubik: DEBUG: Thread 0x%x request %s lock\n", lwp_cpptr,
87  *           ((atype == LOCKREAD) ? "READ" : "WRITE"));
88  */
89
90   /* Check if the lock would would block */
91   if (!await) {
92      if (atype == LOCKREAD) {
93         if (WouldReadBlock(&rwlock))  return EAGAIN;
94      } else {
95         if (WouldWriteBlock(&rwlock)) return EAGAIN;
96      }
97   }
98
99   /* Create new lock record and add to spec'd transaction:
100    * locktype. This field also tells us if the thread is 
101    * waiting for a lock: It will be equal to LOCKWAIT.
102    */
103   atrans->locktype = LOCKWAIT;
104   DBRELE(dbase);
105   if (atype == LOCKREAD) {
106      ObtainReadLock(&rwlock);
107   } else {
108      ObtainWriteLock(&rwlock);
109   }
110   DBHOLD(dbase);
111   atrans->locktype = atype;
112
113 /*
114  *ubik_print("Ubik: DEBUG: Thread 0x%x took %s lock\n", lwp_cpptr,
115  *           ((atype == LOCKREAD) ? "READ" : "WRITE"));
116  */
117   return 0;
118 }
119
120 /* Release the transaction lock */
121 ulock_relLock(atrans)
122   struct ubik_trans *atrans;
123 {
124   if (rwlockinit) return EINVAL;
125
126   if (atrans->locktype == LOCKREAD) {
127      ReleaseReadLock(&rwlock);
128   } else if (atrans->locktype == LOCKWRITE) {
129      ReleaseWriteLock(&rwlock);
130   }
131
132 /*
133  *ubik_print("Ubik: DEBUG: Thread 0x%x %s unlock\n", lwp_cpptr,
134  *           ((atrans->locktype == LOCKREAD) ? "READ" : "WRITE"));
135  */
136
137   atrans->locktype = 0;
138 }
139
140 /* debugging hooks */
141 ulock_Debug(aparm)
142   struct ubik_debug *aparm;
143 {
144   if (rwlockinit) {
145      aparm->anyReadLocks  = 0;
146      aparm->anyWriteLocks = 0;
147   } else {
148      aparm->anyReadLocks  = rwlock.readers_reading;
149      aparm->anyWriteLocks = ((rwlock.excl_locked == WRITE_LOCK) ? 1 : 0);
150   }
151 }
152