*** empty log message ***
[arla.git] / lwp / lock.c
blob9483a111fb876ffe80dc5ffb2fa82c6891175e5b
1 /*
2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
4 * *
5 * Permission to use, copy, modify, and distribute this software and its *
6 * documentation for any purpose and without fee is hereby granted, *
7 * provided that the above copyright notice appear in all copies and *
8 * that both that copyright notice and this permission notice appear in *
9 * supporting documentation, and that the name of IBM not be used in *
10 * advertising or publicity pertaining to distribution of the software *
11 * without specific, written prior permission. *
12 * *
13 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
15 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
16 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
17 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
18 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
19 ****************************************************************************
22 /*******************************************************************\
23 * *
24 * Information Technology Center *
25 * Carnegie-Mellon University *
26 * *
27 * *
28 * *
29 \*******************************************************************/
32 * Locking routines for Vice.
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 RCSID("$Id$");
38 #endif
39 #include "lwp.h"
40 #include "lock.h"
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <sys/time.h>
46 #define FALSE 0
47 #define TRUE 1
49 void
50 Lock_Init(struct Lock *lock)
52 lock -> readers_reading = 0;
53 lock -> excl_locked = 0;
54 lock -> wait_states = 0;
55 lock -> num_waiting = 0;
56 lock -> thread_index = LWP_INVALIDTHREADID;
59 void
60 Lock_Obtain(struct Lock *lock, int how)
62 switch (how) {
64 case READ_LOCK: lock->num_waiting++;
65 do {
66 lock -> wait_states |= READ_LOCK;
67 LWP_WaitProcess(&lock->readers_reading);
68 } while (lock->excl_locked & WRITE_LOCK);
69 lock->num_waiting--;
70 lock->readers_reading++;
71 break;
73 case WRITE_LOCK: lock->num_waiting++;
74 do {
75 lock -> wait_states |= WRITE_LOCK;
76 LWP_WaitProcess(&lock->excl_locked);
77 } while (lock->excl_locked || lock->readers_reading);
78 lock->num_waiting--;
79 lock->excl_locked = WRITE_LOCK;
80 break;
82 case SHARED_LOCK: lock->num_waiting++;
83 do {
84 lock->wait_states |= SHARED_LOCK;
85 LWP_WaitProcess(&lock->excl_locked);
86 } while (lock->excl_locked);
87 lock->num_waiting--;
88 lock->excl_locked = SHARED_LOCK;
89 break;
91 case BOOSTED_LOCK: lock->num_waiting++;
92 do {
93 lock->wait_states |= WRITE_LOCK;
94 LWP_WaitProcess(&lock->excl_locked);
95 } while (lock->readers_reading);
96 lock->num_waiting--;
97 lock->excl_locked = WRITE_LOCK;
98 break;
100 default: printf("Can't happen, bad LOCK type: %d\n", how);
101 abort();
105 /* release a lock, giving preference to new readers */
106 void
107 Lock_ReleaseR(struct Lock *lock)
109 if (lock->wait_states & READ_LOCK) {
110 lock->wait_states &= ~READ_LOCK;
111 LWP_NoYieldSignal(&lock->readers_reading);
113 else {
114 lock->wait_states &= ~EXCL_LOCKS;
115 LWP_NoYieldSignal(&lock->excl_locked);
119 /* release a lock, giving preference to new writers */
120 void
121 Lock_ReleaseW(struct Lock *lock)
123 if (lock->wait_states & EXCL_LOCKS) {
124 lock->wait_states &= ~EXCL_LOCKS;
125 LWP_NoYieldSignal(&lock->excl_locked);
127 else {
128 lock->wait_states &= ~READ_LOCK;
129 LWP_NoYieldSignal(&lock->readers_reading);
134 * These next guys exist to provide an interface to drop a lock atomically with
135 * blocking. They're trivial to do in a non-preemptive LWP environment.
138 /* release a write lock and sleep on an address, atomically */
139 void
140 LWP_WaitProcessR(char *addr, struct Lock *alock)
142 ReleaseReadLock(alock);
143 LWP_WaitProcess(addr);
146 /* release a write lock and sleep on an address, atomically */
147 void
148 LWP_WaitProcessW(char *addr, struct Lock *alock)
150 ReleaseWriteLock(alock);
151 LWP_WaitProcess(addr);
154 /* release a write lock and sleep on an address, atomically */
155 void
156 LWP_WaitProcessS(char *addr, struct Lock *alock)
158 ReleaseSharedLock(alock);
159 LWP_WaitProcess(addr);
162 #ifndef HAVE___FUNCTION__
163 #define __FUNCTION__ "unknown"
164 #endif
166 #define PANICPRINT(msg) fprintf(stderr,"Panic in %s at %s:%d: %s\n", __FUNCTION__, __FILE__, __LINE__, msg)
168 static int
169 WillBlock (struct Lock *lock, int how)
171 switch (how) {
172 case READ_LOCK:
173 return ((lock)->excl_locked & WRITE_LOCK) || (lock)->wait_states;
174 case WRITE_LOCK:
175 return (lock)->excl_locked || (lock)->readers_reading;
176 case SHARED_LOCK:
177 return (lock)->excl_locked || (lock)->wait_states;
178 default:
179 PANICPRINT("unknown locking type");
180 return 1; /* Block if unknown */
184 static void
185 ObtainOneLock(struct Lock *lock, int how)
187 switch (how) {
188 case READ_LOCK:
189 if (!WillBlock(lock, how))
190 (lock) -> readers_reading++;
191 else
192 Lock_Obtain(lock, how);
193 break;
194 case WRITE_LOCK:
195 case SHARED_LOCK:
196 if (!WillBlock(lock, how))
197 (lock) -> excl_locked = how;
198 else
199 Lock_Obtain(lock, how);
200 break;
201 default:
202 PANICPRINT("unknown locking type");
203 fprintf(stderr,"%d\n",how);
207 static void
208 ReleaseOneLock(struct Lock *lock, int how)
210 switch(how) {
211 case READ_LOCK:
212 if (!--(lock)->readers_reading && (lock)->wait_states)
213 Lock_ReleaseW(lock);
214 break;
215 case WRITE_LOCK:
216 (lock)->excl_locked &= ~WRITE_LOCK;
217 if ((lock)->wait_states) Lock_ReleaseR(lock);
218 break;
219 case SHARED_LOCK:
220 (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);
221 if ((lock)->wait_states) Lock_ReleaseR(lock);
222 break;
223 default:
224 PANICPRINT("unknown locking type");
229 * Obtains two locks in a secure fashion (that's the idea)
231 * Takes two locks and two locking modes as parameters.
234 void
235 _ObtainTwoLocks(struct Lock *lock1, int how1,
236 struct Lock *lock2, int how2)
238 struct timeval timeout;
240 timeout.tv_sec = 0;
241 timeout.tv_usec = 1000;
243 start:
244 ObtainOneLock(lock1, how1);
245 if (WillBlock(lock2, how2)) {
246 ReleaseOneLock(lock1, how1);
247 IOMGR_Select(0, 0, 0, 0, &timeout);
248 goto start;
249 } else {
250 ObtainOneLock(lock2, how2);