2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
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. *
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 /*******************************************************************\
24 * Information Technology Center *
25 * Carnegie-Mellon University *
29 \*******************************************************************/
32 * Locking routines for Vice.
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
;
60 Lock_Obtain(struct Lock
*lock
, int how
)
64 case READ_LOCK
: lock
->num_waiting
++;
66 lock
-> wait_states
|= READ_LOCK
;
67 LWP_WaitProcess(&lock
->readers_reading
);
68 } while (lock
->excl_locked
& WRITE_LOCK
);
70 lock
->readers_reading
++;
73 case WRITE_LOCK
: lock
->num_waiting
++;
75 lock
-> wait_states
|= WRITE_LOCK
;
76 LWP_WaitProcess(&lock
->excl_locked
);
77 } while (lock
->excl_locked
|| lock
->readers_reading
);
79 lock
->excl_locked
= WRITE_LOCK
;
82 case SHARED_LOCK
: lock
->num_waiting
++;
84 lock
->wait_states
|= SHARED_LOCK
;
85 LWP_WaitProcess(&lock
->excl_locked
);
86 } while (lock
->excl_locked
);
88 lock
->excl_locked
= SHARED_LOCK
;
91 case BOOSTED_LOCK
: lock
->num_waiting
++;
93 lock
->wait_states
|= WRITE_LOCK
;
94 LWP_WaitProcess(&lock
->excl_locked
);
95 } while (lock
->readers_reading
);
97 lock
->excl_locked
= WRITE_LOCK
;
100 default: printf("Can't happen, bad LOCK type: %d\n", how
);
105 /* release a lock, giving preference to new readers */
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
);
114 lock
->wait_states
&= ~EXCL_LOCKS
;
115 LWP_NoYieldSignal(&lock
->excl_locked
);
119 /* release a lock, giving preference to new writers */
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
);
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 */
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 */
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 */
156 LWP_WaitProcessS(char *addr
, struct Lock
*alock
)
158 ReleaseSharedLock(alock
);
159 LWP_WaitProcess(addr
);
162 #ifndef HAVE___FUNCTION__
163 #define __FUNCTION__ "unknown"
166 #define PANICPRINT(msg) fprintf(stderr,"Panic in %s at %s:%d: %s\n", __FUNCTION__, __FILE__, __LINE__, msg)
169 WillBlock (struct Lock
*lock
, int how
)
173 return ((lock
)->excl_locked
& WRITE_LOCK
) || (lock
)->wait_states
;
175 return (lock
)->excl_locked
|| (lock
)->readers_reading
;
177 return (lock
)->excl_locked
|| (lock
)->wait_states
;
179 PANICPRINT("unknown locking type");
180 return 1; /* Block if unknown */
185 ObtainOneLock(struct Lock
*lock
, int how
)
189 if (!WillBlock(lock
, how
))
190 (lock
) -> readers_reading
++;
192 Lock_Obtain(lock
, how
);
196 if (!WillBlock(lock
, how
))
197 (lock
) -> excl_locked
= how
;
199 Lock_Obtain(lock
, how
);
202 PANICPRINT("unknown locking type");
203 fprintf(stderr
,"%d\n",how
);
208 ReleaseOneLock(struct Lock
*lock
, int how
)
212 if (!--(lock
)->readers_reading
&& (lock
)->wait_states
)
216 (lock
)->excl_locked
&= ~WRITE_LOCK
;
217 if ((lock
)->wait_states
) Lock_ReleaseR(lock
);
220 (lock
)->excl_locked
&= ~(SHARED_LOCK
| WRITE_LOCK
);
221 if ((lock
)->wait_states
) Lock_ReleaseR(lock
);
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.
235 _ObtainTwoLocks(struct Lock
*lock1
, int how1
,
236 struct Lock
*lock2
, int how2
)
238 struct timeval timeout
;
241 timeout
.tv_usec
= 1000;
244 ObtainOneLock(lock1
, how1
);
245 if (WillBlock(lock2
, how2
)) {
246 ReleaseOneLock(lock1
, how1
);
247 IOMGR_Select(0, 0, 0, 0, &timeout
);
250 ObtainOneLock(lock2
, how2
);