Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.electric.tool.ServerJobManager Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ServerJobManager.java
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.Main;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.id.LibId;
import com.sun.electric.database.id.TechId;
import com.sun.electric.database.variable.EditWindow_;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.technology.Technology;
import com.sun.electric.tool.user.ActivityLogger;
import com.sun.electric.tool.user.ErrorLogger;
import com.sun.electric.tool.user.MessagesStream;
import com.sun.electric.tool.user.User;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
*
*/
public class ServerJobManager {
private static final String CLASS_NAME = Job.class.getName();
private static final int defaultNumThreads = Math.max(2, Runtime.getRuntime().availableProcessors());
private final ReentrantLock lock = new ReentrantLock();
void lock() {
lock.lock();
}
void unlock() {
lock.unlock();
}
/** mutex for database synchronization. */
private final Condition databaseChangesMutex = lock.newCondition();
/** started jobs */
private final ArrayList startedJobs = new ArrayList();
/** waiting jobs */
private final ArrayList waitingJobs = new ArrayList();
private final ServerSocket serverSocket;
// private final ArrayList finishedJobs = new ArrayList();
final ArrayList serverConnections = new ArrayList();
private int passiveConnections;
// private final UserInterface redirectInterface = new UserInterfaceRedirect();
private int numThreads;
private final int maxNumThreads;
private boolean runningChangeJob;
// private boolean guiChanged;
private boolean signalledEThread;
private static int maxNumberOfThreads;
/** Creates a new instance of JobPool */
ServerJobManager(int recommendedNumThreads, String loggingFilePath, boolean pipe, int socketPort) {
maxNumThreads = initThreads(recommendedNumThreads);
maxNumberOfThreads = maxNumThreads;
if (Job.currentUI != null) {
initCurrentUI(Job.currentUI);
}
if (loggingFilePath != null) {
initSnapshotLogging(new File(loggingFilePath));
}
if (pipe) {
initPipe();
}
ServerSocket serverSocket = null;
if (socketPort > 0) {
try {
serverSocket = new ServerSocket(socketPort);
System.out.println("ServerSocket waits for port " + socketPort);
} catch (IOException e) {
System.out.println("ServerSocket mode failure: " + e.getMessage());
}
}
this.serverSocket = serverSocket;
}
ServerJobManager() {
this(0, null, false, 0);
serverConnections.add(new Client(0) {
});
}
private int initThreads(int recommendedNumThreads) {
int maxNumThreads = defaultNumThreads;
if (recommendedNumThreads > 0) {
maxNumThreads = recommendedNumThreads;
}
Job.logger.trace("ServerJobManager.initThreads maxNumThreads=", maxNumThreads);
return maxNumThreads;
}
void initCurrentUI(AbstractUserInterface currentUI) {
lock();
try {
assert currentUI.connectionId == 0;
assert serverConnections.isEmpty();
serverConnections.add(currentUI);
} finally {
unlock();
}
currentUI.startDispatcher();
}
void initSnapshotLogging(File loggingFile) {
StreamClient conn;
lock();
try {
int connectionId = serverConnections.size();
FileOutputStream out = new FileOutputStream(loggingFile);
System.err.println("Writing snapshot log to " + loggingFile);
ActivityLogger.logMessage("Writing snapshot log to " + loggingFile);
conn = new StreamClient(connectionId, null, new BufferedOutputStream(out));
serverConnections.add(conn);
passiveConnections++;
} catch (IOException e) {
System.err.println("Failed to create snapshot log file:" + e.getMessage());
return;
} finally {
unlock();
}
conn.start();
}
void initPipe() {
StreamClient conn;
OutputStream stdout = System.out;
MessagesStream.getMessagesStream();
lock();
try {
int connectionId = serverConnections.size();
conn = new StreamClient(connectionId, System.in, stdout);
serverConnections.add(conn);
} finally {
unlock();
}
conn.start();
}
void connectionClosed() {
lock();
try {
passiveConnections++;
if (passiveConnections == serverConnections.size()) {
try {
ActivityLogger.finished();
} catch (Exception e) {
}
System.exit(0);
}
} finally {
unlock();
}
}
/** Add job to list of jobs */
void addJob(EJob ejob, boolean onMySnapshot) {
lock();
try {
if (onMySnapshot) {
waitingJobs.add(0, ejob);
} else {
waitingJobs.add(ejob);
}
setEJobState(ejob, EJob.State.WAITING, onMySnapshot ? EJob.WAITING_NOW : "waiting");
invokeEThread();
} finally {
unlock();
}
}
/** Remove job from list of jobs */
void removeJob(Job j) {
EJob ejob = j.ejob;
lock();
try {
switch (j.ejob.state) {
case WAITING:
setEJobState(ejob, EJob.State.SERVER_DONE, null);
case SERVER_DONE:
setEJobState(ejob, EJob.State.CLIENT_DONE, null);
case CLIENT_DONE:
// finishedJobs.remove(j.ejob);
// if (!Job.BATCHMODE && !guiChanged)
// SwingUtilities.invokeLater(this);
// guiChanged = true;
break;
}
} finally {
unlock();
}
}
void setProgress(EJob ejob, String progress) {
lock();
try {
if (ejob.state == EJob.State.RUNNING) {
setEJobState(ejob, EJob.State.RUNNING, progress);
}
} finally {
unlock();
}
}
/** get all jobs iterator */
Iterator getAllJobs() {
lock();
try {
ArrayList jobsList = new ArrayList();
for (EJob ejob : startedJobs) {
Job job = ejob.getJob();
if (job != null) {
jobsList.add(job);
}
}
for (EJob ejob : waitingJobs) {
Job job = ejob.getJob();
if (job != null) {
jobsList.add(job);
}
}
return jobsList.iterator();
} finally {
unlock();
}
}
List getAllJobInforms() {
lock();
try {
ArrayList jobsList = new ArrayList();
for (EJob ejob : startedJobs) {
Job job = ejob.getJob();
if (job != null) {
jobsList.add(job.getInform());
} else {
jobsList.add(ejob.getInform());
}
}
for (EJob ejob : waitingJobs) {
Job job = ejob.getJob();
if (job != null) {
jobsList.add(job.getInform());
} else {
jobsList.add(ejob.getInform());
}
}
return jobsList;
} finally {
unlock();
}
}
//--------------------------PRIVATE JOB METHODS--------------------------
private void invokeEThread() {
if (signalledEThread || startedJobs.size() >= maxNumThreads) {
return;
}
if (!canDoIt()) {
return;
}
if (startedJobs.size() < numThreads) {
databaseChangesMutex.signal();
} else {
new EThread(numThreads++);
}
signalledEThread = true;
}
// private EJob selectTerminateIt() {
// lock();
// try {
// for (int i = 0; i < finishedJobs.size(); i++) {
// EJob ejob = finishedJobs.get(i);
// if (ejob.state == EJob.State.CLIENT_DONE) continue;
//// finishedJobs.remove(i);
// return ejob;
// }
// } finally {
// unlock();
// }
// return null;
// }
//
// void wantUpdateGui() {
// lock();
// try {
// this.guiChanged = true;
// } finally {
// unlock();
// }
// }
//
// private boolean guiChanged() {
// lock();
// try {
// boolean b = this.guiChanged;
// this.guiChanged = false;
// return b;
// } finally {
// unlock();
// }
// }
private boolean canDoIt() {
if (waitingJobs.isEmpty()) {
return false;
}
EJob ejob = waitingJobs.get(0);
return startedJobs.isEmpty() || !runningChangeJob && ejob.isExamine();
}
private void setEJobState(EJob ejob, EJob.State newState, String info) {
Job.logger.trace("enter ServerJobManager.setEjobState {} {}", newState, ejob.jobName);
EJob.State oldState = ejob.state;
switch (newState) {
case WAITING:
break;
case RUNNING:
if (oldState == EJob.State.RUNNING) {
assert oldState == EJob.State.RUNNING;
ejob.progress = info;
if (info.equals(EJob.ABORTING)) {
ejob.serverJob.scheduledToAbort = true;
}
}
break;
case SERVER_DONE:
boolean removed;
if (oldState == EJob.State.WAITING) {
removed = waitingJobs.remove(ejob);
} else {
assert oldState == EJob.State.RUNNING;
removed = startedJobs.remove(ejob);
if (startedJobs.isEmpty()) {
runningChangeJob = false;
}
}
assert removed;
// if (Job.threadMode != Job.Mode.BATCH && ejob.client == null)
// finishedJobs.add(ejob);
ejob.state = newState;
Client.fireServerEvent(new Client.EJobEvent(ejob.jobKey, ejob.jobName,
ejob.getJob().getTool(), ejob.jobType, ejob.serializedJob,
ejob.doItOk, ejob.serializedResult, ejob.newSnapshot, ejob.state));
break;
case CLIENT_DONE:
assert oldState == EJob.State.SERVER_DONE;
// if (ejob.clientJob.deleteWhenDone)
// finishedJobs.remove(ejob);
}
ejob.state = newState;
List jobs = getAllJobInforms();
Client.fireServerEvent(new Client.JobQueueEvent(jobs.toArray(new Job.Inform[jobs.size()])));
// if (!Job.BATCHMODE && !guiChanged)
// SwingUtilities.invokeLater(this);
// guiChanged = true;
Job.logger.trace("exiting setJobState");
}
// private boolean isChangeJobQueuedOrRunning() {
// lock();
// try {
// for (EJob ejob: startedJobs) {
// Job job = ejob.getJob();
// if (job != null && job.finished) continue;
// if (ejob.jobType == Job.Type.CHANGE) return true;
// }
// for (EJob ejob: waitingJobs) {
// if (ejob.jobType == Job.Type.CHANGE) return true;
// }
// return false;
// } finally {
// unlock();
// }
// }
public void runLoop(Job initialJob) {
initialJob.startJob();
if (serverSocket == null) {
return;
}
try {
// Wait for connections
for (;;) {
Socket socket = serverSocket.accept();
int connectionId = serverConnections.size();
StreamClient conn;
lock();
try {
conn = new StreamClient(connectionId, socket.getInputStream(), socket.getOutputStream());
serverConnections.add(conn);
} finally {
unlock();
}
System.out.println("Accepted connection " + connectionId);
conn.start();
}
} catch (IOException e) {
e.printStackTrace(System.out);
}
}
// /**
// * This method is executed in Swing thread.
// */
// public void run() {
// assert !Job.BATCHMODE;
// Job.logger.logp(Level.FINE, CLASS_NAME, "run", "ENTER");
// while (guiChanged()) {
// ArrayList jobs = new ArrayList();
// for (Iterator it = Job.getAllJobs(); it.hasNext();) {
// Job j = it.next();
// if (j.getDisplay()) {
// jobs.add(j.getInform());
// }
// }
// JobTree.update(jobs);
// TopLevel.setBusyCursor(isChangeJobQueuedOrRunning());
//// for (;;) {
//// EJob ejob = selectTerminateIt();
//// if (ejob == null) break;
////
//// Job.logger.logp(Level.FINE, CLASS_NAME, "run", "terminate {0}", ejob.jobName);
//// Job.runTerminate(ejob);
//// setEJobState(ejob, EJob.State.CLIENT_DONE, null);
//// Job.logger.logp(Level.FINE, CLASS_NAME, "run", "terminated {0}", ejob.jobName);
//// }
// Job.logger.logp(Level.FINE, CLASS_NAME, "run", "wantToRedoJobTree");
// }
// Job.logger.logp(Level.FINE, CLASS_NAME, "run", "EXIT");
// }
EJob selectEJob() {
lock();
try {
for (;;) {
signalledEThread = false;
// Search for examine
if (canDoIt()) {
EJob ejob = waitingJobs.remove(0);
startedJobs.add(ejob);
if (ejob.isExamine()) {
assert !runningChangeJob;
invokeEThread();
} else {
assert startedJobs.size() == 1;
assert !runningChangeJob;
runningChangeJob = true;
}
setEJobState(ejob, EJob.State.RUNNING, "running");
return ejob;
}
if (Main.isBatch() && startedJobs.isEmpty()) {
ActivityLogger.finished();
System.exit(0);
}
Job.logger.trace("ServerJobManager.selectEJob pause");
databaseChangesMutex.awaitUninterruptibly();
Job.logger.trace("ServerJobManager.selectEJob resume");
}
} finally {
unlock();
}
}
void finishEJob(EJob finishedEJob) {
lock();
try {
setEJobState(finishedEJob, EJob.State.SERVER_DONE, "done");
} finally {
unlock();
}
}
/*private*/ static class UserInterfaceRedirect implements UserInterface {
private final Job.Key jobKey;
private final Client client;
private final EDatabase database;
private final EditingPreferences editingPreferences;
TechId curTechId;
LibId curLibId;
CellId curCellId;
private String progressNote;
private int progressValue = -1;
UserInterfaceRedirect(Job.Key jobKey, EditingPreferences ep) {
this.jobKey = jobKey;
client = Job.serverJobManager.serverConnections.get(jobKey.clientId);
database = jobKey.doItOnServer ? EDatabase.serverDatabase() : EDatabase.clientDatabase();
editingPreferences = ep;
}
UserInterfaceRedirect(Job.Key jobKey, AbstractUserInterface client, EditingPreferences ep) {
this.jobKey = jobKey;
this.client = client;
assert !jobKey.doItOnServer;
database = EDatabase.clientDatabase();
editingPreferences = ep;
}
UserInterfaceRedirect(EDatabase database, EditingPreferences ep) {
jobKey = null;
client = null;
this.database = database;
editingPreferences = ep;
}
void setCurrents(Job job) {
assert jobKey == job.getKey();
curTechId = job.curTechId;
curLibId = job.curLibId;
curCellId = job.curCellId;
}
private static void printStackTrace(String methodName) {
if (!Job.getDebug()) {
return;
}
System.out.println("UserInterface." + methodName + " was called from DatabaseChangesThread");
ActivityLogger.logException(new IllegalStateException());
}
/**
* Method to start the display of a progress dialog.
* @param msg the message to show in the progress dialog.
* @param the file being read (null if not reading a file).
*/
public void startProgressDialog(String msg, String filePath) {
progressValue = -1;
Client.fireServerEvent(new Client.StartProgressDialogEvent(msg, filePath));
}
/**
* Method to stop the progress bar
*/
public void stopProgressDialog() {
progressValue = -1;
Client.fireServerEvent(new Client.StopProgressDialogEvent());
}
/**
* Method to update the progress bar
* @param pct the percentage done (from 0 to 100).
*/
public void setProgressValue(int pct) {
if (pct == progressValue) {
return;
}
progressValue = pct;
Client.fireServerEvent(new Client.ProgressValueEvent(pct));
}
/**
* Method to set a text message in the progress dialog.
* @param message the new progress message.
*/
public void setProgressNote(String message) {
progressNote = message;
progressValue = -1;
Client.fireServerEvent(new Client.ProgressNoteEvent(message));
}
/**
* Method to get text message in the progress dialog.
* @return text message in the progress dialog.
*/
public String getProgressNote() {
return progressNote;
}
public Job.Key getJobKey() {
return jobKey;
}
public EDatabase getDatabase() {
return database;
}
public EditingPreferences lowLevelGetEditingPreferences() {
return editingPreferences;
}
public Technology getCurrentTechnology() {
Technology tech = null;
if (curTechId != null) {
tech = database.getTech(curTechId);
}
if (tech == null) {
tech = database.getTechPool().findTechnology(User.getDefaultTechnology());
}
if (tech == null) {
tech = database.getTechPool().findTechnology("mocmos");
}
return tech;
}
public Library getCurrentLibrary() {
return curLibId != null ? database.getLib(curLibId) : null;
}
public EditWindow_ getCurrentEditWindow_() {
printStackTrace("getCurrentEditWindow");
return null;
}
public EditWindow_ needCurrentEditWindow_() {
printStackTrace("needCurrentEditWindow");
return null;
}
/** Get current cell from current library */
public Cell getCurrentCell() {
return curCellId != null ? database.getCell(curCellId) : null;
}
public Cell needCurrentCell() {
Cell cell = getCurrentCell();
if (cell != null) {
return cell;
}
throw new IllegalStateException("Can't get current Cell in database thread");
}
public void repaintAllWindows() {
printStackTrace("repaintAllWindows");
// Job.currentUI.repaintAllWindows();
}
public void adjustReferencePoint(Cell cell, double cX, double cY) {
// Job.currentUI.adjustReferencePoint(cell, cX, cY);
}
;
public int getDefaultTextSize() {
return 14;
}
public EditWindow_ displayCell(Cell cell) {
throw new IllegalStateException();
}
public void termLogging(final ErrorLogger logger, boolean explain, boolean terminate) {
Client.fireServerEvent(new Client.TermLoggingEvent(logger, explain, terminate));
}
public void updateNetworkErrors(Cell cell, List errors) {
throw new IllegalStateException();
}
public void updateIncrementalDRCErrors(Cell cell, List errors) {
throw new IllegalStateException();
}
/**
* Method to return the error message associated with the current error.
* Highlights associated graphics if "showhigh" is nonzero.
*/
public String reportLog(ErrorLogger.MessageLog log, boolean showhigh, boolean separateWindow, int position) {
printStackTrace("reportLog");
// return the error message
return log.getMessageString();
}
/**
* Method to show an error message.
* @param message the error message to show.
* @param title the title of a dialog with the error message.
*/
public void showErrorMessage(String message, String title) {
Client.fireServerEvent(new Client.ShowMessageEvent(client, message, title, true));
}
/**
* Method to show an informational message.
* @param message the message to show.
* @param title the title of a dialog with the message.
*/
public void showInformationMessage(String message, String title) {
Client.fireServerEvent(new Client.ShowMessageEvent(client, message, title, false));
}
/**
* Method print a message.
* @param message the message to show.
* @param newLine add new line after the message
*/
public void printMessage(String message, boolean newLine) {
if (newLine) {
message += "\n";
}
Client.fireServerEvent(new Client.PrintEvent(client, message));
}
/**
* Method to start saving messages.
* @param filePath file to save
*/
public void saveMessages(String filePath) {
Client.fireServerEvent(new Client.SavePrintEvent(client, filePath));
}
/**
* Method to beep.
*/
public void beep() {
Client.fireServerEvent(new Client.BeepEvent());
}
/**
* Method to show a message and ask for confirmation.
* @param message the message to show.
* @return true if "yes" was selected, false if "no" was selected.
*/
public boolean confirmMessage(Object message) {
printStackTrace("confirmMessage");
return true;
}
/**
* Method to ask for a choice among possibilities.
* @param message the message to show.
* @param title the title of the dialog with the query.
* @param choices an array of choices to present, each in a button.
* @param defaultChoice the default choice.
* @return the index into the choices array that was selected.
*/
public int askForChoice(String message, String title, String[] choices, String defaultChoice) {
throw new IllegalStateException(message);
}
/**
* Method to ask for a line of text.
* @param message the prompt message.
* @param title the title of a dialog with the message.
* @param def the default response.
* @return the string (null if cancelled).
*/
public String askForInput(Object message, String title, String def) {
throw new IllegalStateException();
}
/**
* Save current state of highlights and return its ID.
*/
public int saveHighlights() {
return -1;
}
/**
* Restore state of highlights by its ID.
* @param highlightsId id of saved highlights.
*/
public void restoreHighlights(int highlightsId) {
}
/**
* Show status of undo/redo buttons
* @param newUndoEnabled new status of undo button.
* @param newRedoEnabled new status of redo button.
*/
public void showUndoRedoStatus(boolean newUndoEnabled, boolean newRedoEnabled) {
}
}
public static int getDefaultNumberOfThreads() {
return defaultNumThreads;
}
public static int getMaxNumberOfThreads() {
return maxNumberOfThreads;
}
}