| /******************************************************************************* |
| * 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); |
| } |
| } |