| /******************************************************************************* |
| * Copyright (c) 2012 Tilera Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * William R. Swanson (Tilera Corporation) |
| *******************************************************************************/ |
| |
| package org.eclipse.cdt.visualizer.ui.util; |
| |
| import java.util.concurrent.Callable; |
| |
| /** |
| * Runnable object that returns a result object. |
| * |
| * This is like Future<V> from the concurrent package, |
| * but with a few less bells and whistles. |
| * |
| * Intended to be used, for example, as follows: |
| * |
| * RunnableWithResult<X> runnable = new RunnableWithResult<X>() { |
| * public X call() { |
| * ... do work, return an X object ... |
| * } |
| * } |
| * |
| * Thread thread = new Thread(runnable); |
| * thread.start(); |
| * X result = runnable.getResult(0); |
| * |
| * or, to run it on the UI thread... |
| * |
| * GUIUtils.execAndWait(runnable); |
| * X result = runnable.getResult(0); |
| * |
| * Note: if you're invoking this from the UI thread, |
| * it's important to use execAndWait(), so that the runnable |
| * gets a turn on the event loop, otherwise you'll hang the UI! |
| * |
| */ |
| public class RunnableWithResult<V> implements Runnable, Callable<V> { |
| // --- members --- |
| |
| /** Result to return */ |
| protected V m_result = null; |
| |
| /** Whether run() has completed */ |
| protected boolean m_done = false; |
| |
| // --- constructors/destructors --- |
| |
| /** Constructor. */ |
| public RunnableWithResult() { |
| } |
| |
| /** Dispose method. */ |
| public void dispose() { |
| m_result = null; |
| } |
| |
| // --- accessors --- |
| |
| /** Sets result value */ |
| public void setResult(V result) { |
| m_result = result; |
| } |
| |
| /** Gets result value. */ |
| public V getResult() { |
| return m_result; |
| } |
| |
| // --- Runnable implementation --- |
| |
| /** Run method. |
| * Derived types should override call() rather than this method. |
| */ |
| @Override |
| public void run() { |
| m_done = false; |
| setResult(call()); |
| m_done = true; |
| synchronized (this) { |
| notifyAll(); |
| } |
| } |
| |
| // --- Callable implementation --- |
| |
| /** Method that returns the value. |
| * Default implementation returns null. |
| */ |
| @Override |
| public V call() { |
| return null; |
| } |
| |
| // --- methods --- |
| |
| /** Waits for result and returns it. */ |
| public V waitForResult() { |
| return waitForResult(0, null); |
| } |
| |
| /** Waits for result and returns it. */ |
| public V waitForResult(long timeout) { |
| return waitForResult(timeout, null); |
| } |
| |
| /** Waits for result and returns it. |
| * Returns null if specified timeout is exceeded. |
| */ |
| public V waitForResult(long timeout, V defaultValue) { |
| V result = defaultValue; |
| try { |
| if (timeout == 0) { |
| // wait forever |
| // (guard against spurious thread wakeup -- see wait() Javadoc) |
| while (!m_done) { |
| synchronized (this) { |
| this.wait(0); |
| } |
| } |
| } else { |
| // wait until specified timeout |
| // (guard against spurious thread wakeup -- see wait() Javadoc) |
| long then = now(); |
| long waitstep = timeout / 10; |
| if (waitstep == 0) |
| waitstep = 1; |
| do { |
| synchronized (this) { |
| this.wait(waitstep); |
| } |
| } while (!m_done && ((now() - then) < timeout)); |
| } |
| } catch (InterruptedException e) { |
| } |
| if (m_done) |
| result = getResult(); |
| return result; |
| } |
| |
| /** Returns current time in milliseconds. */ |
| protected static long now() { |
| return System.currentTimeMillis(); |
| } |
| } |