All Downloads are FREE. Search and download functionalities are using the official Maven repository.

marytts.modules.ProcessTimeoutDestroyer Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2000-2006 DFKI GmbH.
 * All Rights Reserved.  Use is subject to license terms.
 *
 * This file is part of MARY TTS.
 *
 * MARY TTS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 */
package marytts.modules;

// Log4j Logging classes
import java.io.IOException;

import marytts.util.MaryUtils;

import org.apache.log4j.Logger;

/**
 * Destroy a given process if timeout occurs. This is used to monitor whether an external module gets stuck.
 * 
 * @author Marc Schröder
 */

public class ProcessTimeoutDestroyer extends Thread {
	private boolean listening = false;
	private boolean exit = false;
	private ExternalModule module = null;
	private Thread customer = null;
	private long timeLimit = 0;
	private boolean didDestroy = false;
	private Logger logger;

	public ProcessTimeoutDestroyer(ExternalModule module) {
		this.module = module;
		logger = MaryUtils.getLogger(module.name() + " timer");
		// The timer threads must have a higher priority than the
		// normal threads, in order to make sure they are processed
		// before any other.
		setPriority(getPriority() + 1);
	}

	public synchronized Process getProcess() {
		return module.getProcess();
	}

	public synchronized long getTimeLimit() {
		return timeLimit;
	}

	private synchronized Thread getCustomer() {
		return customer;
	}

	private synchronized boolean shouldExit() {
		return exit;
	}

	/**
	 * A timelimit > 0 will cause the timeout-destroy procedure to be started. The thread setting the timelimit will be the
	 * only one whose call to resetTimeLimit() is taken into account. If a new thread sets a new time limit while the
	 * old one is still running, the old one is silently stopped, and the new one is started as if the old one was not there.
	 * 
	 * @see #resetTimeLimit
	 * @param timeLimit
	 *            timeLimit
	 */
	public synchronized void setTimeLimit(long timeLimit) {
		if (timeLimit <= 0)
			return; // or throw an Exception????
		this.timeLimit = timeLimit;
		this.customer = Thread.currentThread();
		notify();
	}

	/**
	 * Reset the time limit to 0. Only the thread who initiated the latest time limit can also take it back. If another thread
	 * tries to reset the time limit, it is ignored.
	 */
	public synchronized void resetTimeLimit() {
		if (customer == Thread.currentThread()) { // whoever set the time limit
			doResetTimeLimit();
			notify();
		}
		// Any other thread trying to reset the time limit
		// is ignored.
	}

	private synchronized void doResetTimeLimit() {
		timeLimit = 0;
		customer = null;
	}

	public synchronized void pleaseExit() {
		exit = true;
		notify(); // this is used here only because
		// the value of exit is verified after a
		// notification has been received.
	}

	private synchronized void doDestroy() {
		Process process = getProcess();
		if (process != null) {
			try {
				process.getOutputStream().close();
				process.getInputStream().close();
				process.getErrorStream().close();
			} catch (IOException e) {
				logger.info("Problems destroying process: ", e);
			}
			process.destroy();
		}
		// If process is null, it has already been destroyed.
		didDestroy = true;
	}

	public synchronized boolean didDestroy() {
		boolean d = didDestroy;
		didDestroy = false;
		return d;
	}

	// If this is synchronized, it can cause deadlock:
	public void makeSureWereReady() {
		while (!listening) {
			Thread.yield();
		}
	}

	public synchronized void doWait(long time) {
		try {
			listening = true; // just before the wait(), indicate were ready
			wait(time);
		} catch (InterruptedException e) {
			logger.warn("Wait interrupted: ", e);
		}
	}

	public void run() {
		while (true) {
			Thread orderingCustomer = getCustomer();
			if (orderingCustomer == null) {
				logger.info("Waiting for timer request.");
			} else {
				logger.info("Received timer request: " + getTimeLimit() + " ms.");
			}
			doWait(getTimeLimit());
			if (shouldExit()) {
				logger.info("Exiting.");
				return;
			}
			if (getCustomer() == null) { // timer was reset before timeout
				logger.info("Normal operation, timer stopped.");
			} else if (getCustomer() == orderingCustomer) {
				logger.info("Timeout occurred. Destroying Process.");
				// OK, the serious case
				doDestroy();
				doResetTimeLimit();
			}
			// Else, a different customer. Just forget about old request,
			// and deal with new one.
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy