blob: da3d53265c42588affb9f3d0613a7344af6b5266 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2006 IBM Corporation and others.
* 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:
* IBM - Initial API and implementation
*******************************************************************************/
package org.eclipse.core.tests.harness;
import junit.framework.Assert;
/**
* This class acts as an implementation of a barrier that is appropriate for
* concurrency test cases that want to fail if a thread fails to achieve a
* particular state in a reasonable amount of time. This prevents test suites
* from hanging indefinitely if a concurrency bug is found that would normally
* result in an indefinite hang.
*/
public class TestBarrier {
/**
* Convience status constant that can be interpreted differently by each
* test.
*/
public static final int STATUS_BLOCKED = 6;
/**
* Convience status constant that can be interpreted differently by each
* test.
*/
public static final int STATUS_DONE = 5;
/**
* Convience status constant that can be interpreted differently by each
* test.
*/
public static final int STATUS_RUNNING = 3;
/**
* Convience status constant that can be interpreted differently by each
* test.
*/
public static final int STATUS_START = 1;
/**
* Convience status constant that can be interpreted differently by each
* test.
*/
public static final int STATUS_WAIT_FOR_DONE = 4;
/**
* Convience status constant that can be interpreted differently by each
* test.
*/
public static final int STATUS_WAIT_FOR_RUN = 2;
/**
* Convience status constant that can be interpreted differently by each
* test.
*/
public static final int STATUS_WAIT_FOR_START = 0;
private final int myIndex;
/**
* The status array and index for this barrier object
*/
private final int[] myStatus;
/**
* Blocks the calling thread until the status integer at the given index
* is set to the given value. Fails if the status change does not occur in
* a reasonable amount of time.
* @param statuses the array of statuses that represent the states of
* an array of jobs or threads
* @param index the index into the statuses array that the calling
* thread is waiting for
* @param status the status that the calling thread should wait for
*/
private static void doWaitForStatus(int[] statuses, int index, int status, int timeout) {
int i = 0;
while (statuses[index] != status) {
try {
Thread.yield();
Thread.sleep(100);
Thread.yield();
} catch (InterruptedException e) {
//ignore
}
//sanity test to avoid hanging tests
Assert.assertTrue("Timeout waiting for status to change from " + getStatus(statuses[index]) + " to " + getStatus(status), i++ < timeout);
}
}
private static String getStatus(int status) {
switch (status) {
case STATUS_WAIT_FOR_START :
return "WAIT_FOR_START";
case STATUS_START :
return "START";
case STATUS_WAIT_FOR_RUN :
return "WAIT_FOR_RUN";
case STATUS_RUNNING :
return "RUNNING";
case STATUS_WAIT_FOR_DONE :
return "WAIT_FOR_DONE";
case STATUS_DONE :
return "DONE";
case STATUS_BLOCKED :
return "BLOCKED";
default :
return "UNKNOWN_STATUS";
}
}
public static void waitForStatus(int[] location, int status) {
doWaitForStatus(location, 0, status, 100);
}
/**
* Blocks the current thread until the given variable is set to the given
* value Times out after a predefined period to avoid hanging tests
*/
public static void waitForStatus(int[] location, int index, int status) {
doWaitForStatus(location, index, status, 100);
}
/**
* Creates a new test barrier suitable for a single thread
*/
public TestBarrier() {
this(new int[1], 0);
}
/**
* Creates a new test barrier on the provided status array, suitable for
* acting as a barrier for multiple threads.
*/
public TestBarrier(int[] location, int index) {
this.myStatus = location;
this.myIndex = index;
}
/**
* Sets this barrier object's status.
*/
public void setStatus(int status) {
myStatus[myIndex] = status;
}
/**
* Blocks the current thread until the receiver's status is set to the given
* value. Times out after a predefined period to avoid hanging tests
*/
public void waitForStatus(int status) {
waitForStatus(myStatus, myIndex, status);
}
/**
* The same as other barrier methods, except it will not fail if the job
* does not start in a "reasonable" time. This is only appropriate for tests
* that are explicitly very long running.
*/
public void waitForStatusNoFail(int status) {
doWaitForStatus(myStatus, myIndex, status, 100000);
}
}