/*******************************************************************************
*
* Copyright (c) 2004-2010, Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
*
*
*
*******************************************************************************/
package org.jvnet.hudson.test;
/**
* Lock mechanism to let multiple threads execute phases sequentially.
*
* @author Kohsuke Kawaguchi
*/
public class SequenceLock {
/**
* Currently executing phase N.
*/
private int n;
/**
* This thread is executing the phase
*/
private Thread t;
private boolean aborted;
/**
* Blocks until all the previous phases are completed, and returns when the
* specified phase <i>i</i> is started. If the calling thread was executing
* an earlier phase, that phase is marked as completed.
*
* @throws IllegalStateException if the sequential lock protocol is aborted,
* or the thread that owns the current phase has quit.
*/
public synchronized void phase(int i) throws InterruptedException {
done(); // mark the previous phase done
while (i != n) {
if (aborted) {
throw new IllegalStateException("SequenceLock aborted");
}
if (t != null && !t.isAlive()) {
throw new IllegalStateException("Owner thread of the current phase has quit" + t);
}
if (i < n) {
throw new IllegalStateException("Phase " + i + " is already completed");
}
wait();
}
t = Thread.currentThread();
}
/**
* Marks the current phase completed that the calling thread was executing.
*
* <p> This is only necessary when the thread exits the last phase, as
* {@link #phase(int)} call implies the {@link #done()} call.
*/
public synchronized void done() {
if (t == Thread.currentThread()) {
// phase N done
n++;
t = null;
notifyAll();
}
}
/**
* Tell all the threads that this sequencing was aborted. Everyone waiting
* for future phases will receive an error.
*
* <p> Calling this method from the finally block prevents a dead lock if
* one of the participating thread aborts with an exception, as without the
* explicit abort operation, other threads will block forever for a phase
* that'll never come.
*/
public synchronized void abort() {
aborted = true;
notifyAll();
}
}