1 32 33 package edu.rice.cs.util.newjvm; 34 35 import edu.rice.cs.util.Log; 36 import edu.rice.cs.util.UnexpectedException; 37 import edu.rice.cs.drjava.config.FileOption; 38 39 import java.rmi.*; 40 import java.rmi.server.*; 41 import java.io.*; 42 import java.util.Arrays ; 43 44 49 public abstract class AbstractMasterJVM 50 implements MasterRemote { 51 52 public static final Log _log = new Log("MasterSlave.txt", false); 53 54 55 protected volatile String _waitForQuitThreadName = "Wait for SlaveJVM Exit Thread"; 56 57 60 61 protected final Object _masterJVMLock = new Object (); 62 63 private static final String RUNNER = SlaveJVMRunner.class.getName(); 64 65 66 private volatile SlaveRemote _slave; 67 68 69 private volatile boolean _startupInProgress = false; 70 71 74 private volatile boolean _quitOnStartup = false; 75 76 79 82 private volatile MasterRemote _masterStub = null; 83 84 87 private volatile File _masterStubFile; 88 89 90 private final String _slaveClassName; 91 92 95 private volatile Thread _monitorThread; 96 97 100 105 protected AbstractMasterJVM(String slaveClassName) { 106 _slaveClassName = slaveClassName; 107 _slave = null; 108 _monitorThread = null; 109 110 _log.log(this + " CREATED"); 111 112 System.setProperty("java.rmi.server.hostname", "127.0.0.1"); 114 } 115 116 119 protected abstract void handleSlaveConnected(); 120 121 124 protected abstract void handleSlaveQuit(int status); 125 126 129 protected final void invokeSlave() throws IOException, RemoteException { 130 invokeSlave(new String [0], FileOption.NULL_FILE); 131 } 132 133 137 protected final void invokeSlave(String [] jvmArgs, File workDir) throws IOException, RemoteException { 138 invokeSlave(jvmArgs, System.getProperty("java.class.path"), workDir); 139 } 140 141 146 protected final void invokeSlave(final String [] jvmArgs, final String cp, final File workDir) throws IOException, 147 RemoteException { 148 149 synchronized(_masterJVMLock) { 151 try { while (_startupInProgress || _monitorThread != null) _masterJVMLock.wait(); } 152 catch(InterruptedException e) { throw new UnexpectedException(e); } 153 _startupInProgress = true; 154 } 155 156 _log.log(this + ".invokeSlave(...) called"); 157 158 161 162 if (_masterStub == null) { 163 try { _masterStub = (MasterRemote) UnicastRemoteObject.exportObject(this); } 164 catch (RemoteException re) { 165 javax.swing.JOptionPane.showMessageDialog(null, edu.rice.cs.util.StringOps.getStackTrace(re)); 166 _log.log(this + " threw " + re); 167 throw new UnexpectedException(re); } 169 _log.log(this + " EXPORTed Master JVM"); 170 171 _masterStubFile = File.createTempFile("DrJava-remote-stub", ".tmp"); 172 _masterStubFile.deleteOnExit(); 173 174 FileOutputStream fstream = new FileOutputStream(_masterStubFile); 176 ObjectOutputStream ostream = new ObjectOutputStream(fstream); 177 ostream.writeObject(_masterStub); 178 ostream.flush(); 179 fstream.close(); 180 ostream.close(); 181 } 182 183 final String [] args = new String [] { _masterStubFile.getAbsolutePath(), _slaveClassName }; 184 185 _monitorThread = new Thread (_waitForQuitThreadName) { 188 public void run() { 189 try { 190 191 _log.log(AbstractMasterJVM.this + " is STARTING a Slave JVM with args " + Arrays.asList(args)); 192 193 final Process process = ExecJVM.runJVM(RUNNER, args, cp, jvmArgs, workDir); 194 _log.log(AbstractMasterJVM.this + " CREATED Slave JVM process " + process + " with " + asString()); 195 196 int status = process.waitFor(); 197 _log.log(process + " DIED under control of " + asString() + " with status " + status); 198 synchronized(_masterJVMLock) { 199 if (_startupInProgress) { 200 _log.log("Process " + process + " died while starting up"); 201 204 slaveQuitDuringStartup(status); 205 } 206 if (_slave != null) { _slave = null; 208 } 209 _monitorThread = null; 210 _masterJVMLock.notifyAll(); } 212 213 handleSlaveQuit(status); 215 } 216 catch(NoSuchObjectException e) { throw new UnexpectedException(e); } 217 catch(InterruptedException e) { throw new UnexpectedException(e); } 218 catch(IOException e) { throw new UnexpectedException(e); } 219 } 220 private String asString() { return "MonitorThread@" + Integer.toHexString(hashCode()); } 221 }; 222 _monitorThread.start(); 224 } 225 226 227 public void waitSlaveDone() { 228 try { synchronized(_masterJVMLock) { while (_monitorThread != null) _masterJVMLock.wait(); }} 229 catch(InterruptedException e) { throw new UnexpectedException(e); } 230 } 231 232 235 protected void slaveQuitDuringStartup(int status) { 236 _startupInProgress = false; 238 _quitOnStartup = false; 239 _monitorThread = null; 240 } 241 242 245 public abstract void errorStartingSlave(Throwable cause) throws RemoteException; 246 247 248 public void checkStillAlive() { } 249 250 251 public void registerSlave(SlaveRemote slave) throws RemoteException { 252 _log.log(this + " registering Slave " + slave); 253 254 boolean quitSlavePending; 256 synchronized(_masterJVMLock) { 257 _slave = slave; 258 _startupInProgress = false; 259 260 _log.log(this + " calling handleSlaveConnected()"); 261 262 handleSlaveConnected(); 263 264 quitSlavePending = _quitOnStartup; 265 if (_quitOnStartup) { 266 _quitOnStartup = false; 268 } 269 } 270 if (quitSlavePending) { 271 _log.log(this + " Executing deferred quitSlave() that was called during startUp"); 272 quitSlave(); } 274 } 275 276 277 public void dispose() throws RemoteException { 278 _log.log(this + ".dispose() called; slaveRemote is " + _slave); 279 if (_startupInProgress) _log.log(this + ".dispose() is KILLing startUp in process; dying slave reference does not yet exist"); 280 SlaveRemote dyingSlave; 281 synchronized(_masterJVMLock) { 282 _masterStub = null; 283 if (_monitorThread != null) _monitorThread = null; 284 dyingSlave = _slave; _slave = null; 286 287 _log.log(this + ".dispose() UNEXPORTing " + this); 290 UnicastRemoteObject.unexportObject(this, true); 291 } 292 if (dyingSlave != null) { 293 _log.log(this + ".dispose() QUITing " + dyingSlave); 294 dyingSlave.quit(); } 296 } 297 298 301 protected final void quitSlave() throws RemoteException { 302 SlaveRemote dyingSlave; 303 synchronized(_masterJVMLock) { 304 if (isStartupInProgress()) { 305 307 _quitOnStartup = true; 308 return; 309 } 310 else if (_slave == null) { 311 _log.log(this + " called quitSlave() when no slave was running"); 312 return; 313 } 314 else { 315 dyingSlave = _slave; 316 _slave = null; 317 } 318 } 319 dyingSlave.quit(); } 321 322 323 protected final SlaveRemote getSlave() { return _slave; } 324 325 326 protected boolean isStartupInProgress() { return _startupInProgress; } 327 } 328 | Popular Tags |