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