|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.nio.ch; |
|
|
|
import java.nio.channels.*; |
|
import java.util.concurrent.*; |
|
import java.io.IOException; |
|
|
|
/** |
|
* A Future for a pending I/O operation. A PendingFuture allows for the |
|
* attachment of an additional arbitrary context object and a timer task. |
|
*/ |
|
|
|
final class PendingFuture<V,A> implements Future<V> { |
|
|
|
private final AsynchronousChannel channel; |
|
private final CompletionHandler<V,? super A> handler; |
|
private final A attachment; |
|
|
|
|
|
private volatile boolean haveResult; |
|
private volatile V result; |
|
private volatile Throwable exc; |
|
|
|
|
|
private CountDownLatch latch; |
|
|
|
|
|
private Future<?> timeoutTask; |
|
|
|
|
|
private volatile Object context; |
|
|
|
PendingFuture(AsynchronousChannel channel, |
|
CompletionHandler<V,? super A> handler, |
|
A attachment, |
|
Object context) |
|
{ |
|
this.channel = channel; |
|
this.handler = handler; |
|
this.attachment = attachment; |
|
this.context = context; |
|
} |
|
|
|
PendingFuture(AsynchronousChannel channel, |
|
CompletionHandler<V,? super A> handler, |
|
A attachment) |
|
{ |
|
this.channel = channel; |
|
this.handler = handler; |
|
this.attachment = attachment; |
|
} |
|
|
|
PendingFuture(AsynchronousChannel channel) { |
|
this(channel, null, null); |
|
} |
|
|
|
PendingFuture(AsynchronousChannel channel, Object context) { |
|
this(channel, null, null, context); |
|
} |
|
|
|
AsynchronousChannel channel() { |
|
return channel; |
|
} |
|
|
|
CompletionHandler<V,? super A> handler() { |
|
return handler; |
|
} |
|
|
|
A attachment() { |
|
return attachment; |
|
} |
|
|
|
void setContext(Object context) { |
|
this.context = context; |
|
} |
|
|
|
Object getContext() { |
|
return context; |
|
} |
|
|
|
void setTimeoutTask(Future<?> task) { |
|
synchronized (this) { |
|
if (haveResult) { |
|
task.cancel(false); |
|
} else { |
|
this.timeoutTask = task; |
|
} |
|
} |
|
} |
|
|
|
|
|
private boolean prepareForWait() { |
|
synchronized (this) { |
|
if (haveResult) { |
|
return false; |
|
} else { |
|
if (latch == null) |
|
latch = new CountDownLatch(1); |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
void setResult(V res) { |
|
synchronized (this) { |
|
if (haveResult) |
|
return; |
|
result = res; |
|
haveResult = true; |
|
if (timeoutTask != null) |
|
timeoutTask.cancel(false); |
|
if (latch != null) |
|
latch.countDown(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
void setFailure(Throwable x) { |
|
if (!(x instanceof IOException) && !(x instanceof SecurityException)) |
|
x = new IOException(x); |
|
synchronized (this) { |
|
if (haveResult) |
|
return; |
|
exc = x; |
|
haveResult = true; |
|
if (timeoutTask != null) |
|
timeoutTask.cancel(false); |
|
if (latch != null) |
|
latch.countDown(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
void setResult(V res, Throwable x) { |
|
if (x == null) { |
|
setResult(res); |
|
} else { |
|
setFailure(x); |
|
} |
|
} |
|
|
|
@Override |
|
public V get() throws ExecutionException, InterruptedException { |
|
if (!haveResult) { |
|
boolean needToWait = prepareForWait(); |
|
if (needToWait) |
|
latch.await(); |
|
} |
|
if (exc != null) { |
|
if (exc instanceof CancellationException) |
|
throw new CancellationException(); |
|
throw new ExecutionException(exc); |
|
} |
|
return result; |
|
} |
|
|
|
@Override |
|
public V get(long timeout, TimeUnit unit) |
|
throws ExecutionException, InterruptedException, TimeoutException |
|
{ |
|
if (!haveResult) { |
|
boolean needToWait = prepareForWait(); |
|
if (needToWait) |
|
if (!latch.await(timeout, unit)) throw new TimeoutException(); |
|
} |
|
if (exc != null) { |
|
if (exc instanceof CancellationException) |
|
throw new CancellationException(); |
|
throw new ExecutionException(exc); |
|
} |
|
return result; |
|
} |
|
|
|
Throwable exception() { |
|
return (exc instanceof CancellationException) ? null : exc; |
|
} |
|
|
|
V value() { |
|
return result; |
|
} |
|
|
|
@Override |
|
public boolean isCancelled() { |
|
return (exc instanceof CancellationException); |
|
} |
|
|
|
@Override |
|
public boolean isDone() { |
|
return haveResult; |
|
} |
|
|
|
@Override |
|
public boolean cancel(boolean mayInterruptIfRunning) { |
|
synchronized (this) { |
|
if (haveResult) |
|
return false; |
|
|
|
|
|
if (channel() instanceof Cancellable) |
|
((Cancellable)channel()).onCancel(this); |
|
|
|
|
|
exc = new CancellationException(); |
|
haveResult = true; |
|
if (timeoutTask != null) |
|
timeoutTask.cancel(false); |
|
} |
|
|
|
|
|
if (mayInterruptIfRunning) { |
|
try { |
|
channel().close(); |
|
} catch (IOException ignore) { } |
|
} |
|
|
|
|
|
if (latch != null) |
|
latch.countDown(); |
|
return true; |
|
} |
|
} |