1 /**
2 * AUTOHIT 2003
3 * Copyright Erich P Gatejen (c) 1989,1997,2003,2004
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Additional license information can be found in the documentation.
19 * @author Erich P Gatejen
20 */
21 package autohit.common;
22 import autohit.common.Constants;
23
24 /**
25 * Process monitors. There are three seperate monitors:<code>
26 * 1- Locks: spinlocks on a shared lock monitor. Includes the redlight,
27 * greenlight function.
28 * 2- Signals: A cummulative signal, much like a semaphore.
29 * 3- Rendezous: Between two threads.
30 * Each of the three monitors do not effect each other.
31 * </code>
32 *
33 * @author Erich P. Gatejen
34 * @version 1.0
35 * <i>Version History</i>
36 * <code>EPG - Rewrite - 16May03</code>
37 */
38 public class ProcessMonitor extends Object {
39
40 private int lockcount;
41 private int owner;
42 private int signals;
43 private boolean green;
44 private boolean meeting;
45 private Object rsync; // for the rendezous synchronization
46 private Object ssync; // for the signal synchronization
47
48 /**
49 * Default constructor. It will create the monitor that
50 * is unlocked.
51 */
52 public ProcessMonitor() {
53 owner = Constants.NO_OWNER;
54 green = true;
55 meeting = false;
56 rsync = new Object();
57 ssync = new Object();
58 }
59
60 /**
61 * Lock monitor. Try to lock it. If it already locked by
62 * another thread, it will return false. If it is locked
63 * by the current thread, the lockcount will be incremented, and
64 * it will return true. If it is not locked, it will be locked and
65 * owned by the current thread.
66 *
67 * @return true if it locks, false it is already locked by another thread.
68 */
69 public synchronized boolean lock() {
70
71 int me = ThreadContext.get();
72 if ((owner != Constants.NO_OWNER) && (owner != me)) {
73 return false;
74 }
75 owner = me;
76 lockcount++;
77 return true;
78 }
79
80 /**
81 * Knock the spinlock down one. If it hits zero, the lock is
82 * removed. If the lock is owned by another thread, it will return
83 * false, otherwise it will return true--even if the spinlock hasn't
84 * hit zero.
85 * @return true for success, false for owned by another thread.
86 */
87 public synchronized boolean unlock() {
88
89 if ((owner != Constants.NO_OWNER) && (owner != ThreadContext.get())) {
90 return false;
91 }
92
93 lockcount--;
94 if (lockcount <= 0) {
95 lockcount = 0;
96 owner = Constants.NO_OWNER;
97 this.notifyAll();
98 }
99 return true;
100 }
101
102 /**
103 * Cancel all locks. Returns false if the lock is owned by
104 * another thread.
105 * @return true for success, otherwise false
106 */
107 public synchronized boolean free() {
108
109 if ((owner != Constants.NO_OWNER) || (owner != ThreadContext.get())) {
110 return false;
111 }
112 owner = Constants.NO_OWNER;
113 lockcount = 0;
114 this.notifyAll();
115 return true;
116 }
117
118 /**
119 * Wait for a lock.
120 * @return true for success, otherwise false
121 * TODO Look into the localized synchronization
122 */
123 public void waitlock() {
124
125 // The notify's are just a kick
126
127 int me = ThreadContext.get();
128 if ((owner != Constants.NO_OWNER) && (owner != me)) {
129
130 // Wait for it.
131 while (owner != Constants.NO_OWNER) {
132 try {
133 // TODO Is sync in waitlock() going to cause deadlock?
134 synchronized (this) {
135 this.wait();
136 }
137 } catch (InterruptedException e) {
138 }
139 }
140 owner = me;
141 lockcount++;
142 synchronized (this) {
143 this.notifyAll();
144 }
145
146 } else {
147 // I own it, so just up the spinlock.
148 lockcount++;
149 synchronized (this) {
150 this.notify();
151 }
152 }
153 }
154
155 /**
156 * Wait for the green light.
157 */
158 public void stoplight() {
159
160 // Wait for it.
161 while (!green) {
162 try {
163 // TODO Is sync in stoplight() going to cause deadlock?
164 synchronized (this) {
165 this.wait();
166 }
167 } catch (InterruptedException e) {
168 }
169 }
170 //synchronized (this) { // I don't think I need this.
171 // this.notifyAll();
172 //}
173 }
174
175 /**
176 * Turn on the green light.
177 */
178 public synchronized void green() {
179 green = true;
180 this.notifyAll();
181 }
182
183 /**
184 * Turn on the green light.
185 */
186 public synchronized void red() {
187 green = false;
188 this.notifyAll();
189 }
190
191 /**
192 * Wait for a signal. It's pretty mch a semaphore.
193 */
194 public void waitSignal() throws InterruptedException {
195
196 // lock on the ssync object. if there is a singal
197 // already, just decrement it and return.
198 synchronized (ssync) {
199
200 while (signals < 1) {
201 ssync.wait();
202 }
203 signals--;
204 }
205 }
206
207 /**
208 * Send a signal. They are cummulative and independent of the other
209 * monitors.
210 */
211 public void signal() {
212
213 synchronized (ssync) {
214 signals++;
215 ssync.notifyAll();
216 }
217 }
218
219 /**
220 * Rendevous between two threads-- not signal. The first in the
221 * door will wait for the second. You should only use this for synchronization
222 * between two threads--NO MORE THAN TWO!
223 */
224 public void rendezous() {
225
226 boolean wait;
227
228 synchronized (rsync) {
229 if (meeting == false)
230 wait = true;
231 else
232 wait = false;
233
234 if (wait) {
235 meeting = true;
236 try {
237 rsync.wait();
238 } catch (Exception e) {
239 // dont care
240 }
241 } else {
242 meeting = false;
243 rsync.notify();
244 }
245 }
246 }
247
248 }
|