1
/*******************************************************************************
2
* Copyright (c) 2006, 2008 Wind River Systems and others.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* Wind River Systems - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.cdt.dsf.concurrent;
13
import java.util.concurrent.CancellationException;
14
import java.util.concurrent.ExecutionException;
15
import java.util.concurrent.Future;
16
import java.util.concurrent.TimeUnit;
17
import java.util.concurrent.TimeoutException;
18
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
20
import org.eclipse.core.runtime.CoreException;
24
* A convenience class that allows a client to retrieve data from services
25
* synchronously from a non-dispatch thread. This class is different from
26
* a Callable<V> in that it allows the implementation code to calculate
27
* the result in several dispatches, rather than requiring it to return the
28
* data at end of Callable#call method.
32
* class DataQuery extends Query<Data> {
33
* protected void execute(DataRequestMonitor<Data> rm) {
34
* rm.setData(fSlowService.getData());
39
* DsfExecutor executor = getExecutor();
40
* DataQuery query = new DataQuery();
41
* executor.submit(query);
44
* Data data = query.get();
49
* @see java.util.concurrent.Callable
54
abstract public class Query<V> extends DsfRunnable
57
/** The synchronization object for this query */
58
private final Sync fSync = new Sync();
61
* The no-argument constructor
65
public V get() throws InterruptedException, ExecutionException { return fSync.doGet(); }
67
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
68
return fSync.doGet(unit.toNanos(timeout));
72
* Don't try to interrupt the DSF executor thread, just ignore the request
75
public boolean cancel(boolean mayInterruptIfRunning) {
76
return fSync.doCancel();
79
public boolean isCancelled() { return fSync.doIsCancelled(); }
81
public boolean isDone() { return fSync.doIsDone(); }
84
protected void doneException(Throwable t) {
85
fSync.doSetException(t);
88
abstract protected void execute(DataRequestMonitor<V> rm);
94
* Create the executor which is going to handle the completion of the
95
* request monitor. Normally a DSF executor is supplied here which
96
* causes the request monitor to be invoked in a new dispatch loop.
97
* But since the query is a synchronization object, it can handle
98
* the completion of the request in any thread.
99
* Avoiding the use of a DSF executor is very useful because queries are
100
* meant to be used by clients calling from non-dispatch thread, and there
101
* is a chance that a client may execute a query just as a session is being
102
* shut down. In that case, the DSF executor may throw a
103
* RejectedExecutionException which would have to be handled by the query.
105
execute(new DataRequestMonitor<V>(ImmediateExecutor.getInstance(), null) {
107
public void handleCompleted() {
108
if (isSuccess()) fSync.doSet(getData());
109
else fSync.doSetException(new CoreException(getStatus()));
112
} catch(Throwable t) {
114
* Catching the exception here will only work if the exception
115
* happens within the execute. It will not work in cases when
116
* the execute submits other runnables, and the other runnables
117
* encounter the exception.
119
fSync.doSetException(t);
122
* Since we caught the exception, it will not be logged by
123
* DefaultDsfExecutable.afterExecution(). So log it here.
125
DefaultDsfExecutor.logException(t);
130
@SuppressWarnings("serial")
131
final class Sync extends AbstractQueuedSynchronizer {
132
private static final int STATE_RUNNING = 1;
133
private static final int STATE_DONE = 2;
134
private static final int STATE_CANCELLED = 4;
137
private Throwable fException;
139
private boolean ranOrCancelled(int state) {
140
return (state & (STATE_DONE | STATE_CANCELLED)) != 0;
144
protected int tryAcquireShared(int ignore) {
145
return doIsDone()? 1 : -1;
149
protected boolean tryReleaseShared(int ignore) {
153
boolean doIsCancelled() {
154
return getState() == STATE_CANCELLED;
158
return ranOrCancelled(getState());
161
V doGet() throws InterruptedException, ExecutionException {
162
acquireSharedInterruptibly(0);
163
if (getState() == STATE_CANCELLED) throw new CancellationException();
164
if (fException != null) throw new ExecutionException(fException);
168
V doGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
169
if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException();
170
if (getState() == STATE_CANCELLED) throw new CancellationException();
171
if (fException != null) throw new ExecutionException(fException);
178
if (ranOrCancelled(s)) return;
179
if (compareAndSetState(s, STATE_DONE)) break;
185
void doSetException(Throwable t) {
188
if (ranOrCancelled(s)) return;
189
if (compareAndSetState(s, STATE_DONE)) break;
199
if (ranOrCancelled(s)) return false;
200
if (compareAndSetState(s, STATE_CANCELLED)) break;
207
return compareAndSetState(0, STATE_RUNNING);