Source code for /engineering/autohit-2003/src/autohit/common/ProcessMonitor.javaOriginal file ProcessMonitor.java
   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 }