1 /* 2 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.ch; 27 28 import java.nio.channels.*; 29 import java.util.concurrent.*; 30 import java.io.IOException; 31 32 /** 33 * A Future for a pending I/O operation. A PendingFuture allows for the 34 * attachment of an additional arbitrary context object and a timer task. 35 */ 36 37 final class PendingFuture<V,A> implements Future<V> { 38 39 private final AsynchronousChannel channel; 40 private final CompletionHandler<V,? super A> handler; 41 private final A attachment; 42 43 // true if result (or exception) is available 44 private volatile boolean haveResult; 45 private volatile V result; 46 private volatile Throwable exc; 47 48 // latch for waiting (created lazily if needed) 49 private CountDownLatch latch; 50 51 // optional timer task that is cancelled when result becomes available 52 private Future<?> timeoutTask; 53 54 // optional context object 55 private volatile Object context; 56 PendingFuture(AsynchronousChannel channel, CompletionHandler<V,? super A> handler, A attachment, Object context)57 PendingFuture(AsynchronousChannel channel, 58 CompletionHandler<V,? super A> handler, 59 A attachment, 60 Object context) 61 { 62 this.channel = channel; 63 this.handler = handler; 64 this.attachment = attachment; 65 this.context = context; 66 } 67 PendingFuture(AsynchronousChannel channel, CompletionHandler<V,? super A> handler, A attachment)68 PendingFuture(AsynchronousChannel channel, 69 CompletionHandler<V,? super A> handler, 70 A attachment) 71 { 72 this.channel = channel; 73 this.handler = handler; 74 this.attachment = attachment; 75 } 76 PendingFuture(AsynchronousChannel channel)77 PendingFuture(AsynchronousChannel channel) { 78 this(channel, null, null); 79 } 80 PendingFuture(AsynchronousChannel channel, Object context)81 PendingFuture(AsynchronousChannel channel, Object context) { 82 this(channel, null, null, context); 83 } 84 channel()85 AsynchronousChannel channel() { 86 return channel; 87 } 88 handler()89 CompletionHandler<V,? super A> handler() { 90 return handler; 91 } 92 attachment()93 A attachment() { 94 return attachment; 95 } 96 setContext(Object context)97 void setContext(Object context) { 98 this.context = context; 99 } 100 getContext()101 Object getContext() { 102 return context; 103 } 104 setTimeoutTask(Future<?> task)105 void setTimeoutTask(Future<?> task) { 106 synchronized (this) { 107 if (haveResult) { 108 task.cancel(false); 109 } else { 110 this.timeoutTask = task; 111 } 112 } 113 } 114 115 // creates latch if required; return true if caller needs to wait prepareForWait()116 private boolean prepareForWait() { 117 synchronized (this) { 118 if (haveResult) { 119 return false; 120 } else { 121 if (latch == null) 122 latch = new CountDownLatch(1); 123 return true; 124 } 125 } 126 } 127 128 /** 129 * Sets the result, or a no-op if the result or exception is already set. 130 */ setResult(V res)131 void setResult(V res) { 132 synchronized (this) { 133 if (haveResult) 134 return; 135 result = res; 136 haveResult = true; 137 if (timeoutTask != null) 138 timeoutTask.cancel(false); 139 if (latch != null) 140 latch.countDown(); 141 } 142 } 143 144 /** 145 * Sets the result, or a no-op if the result or exception is already set. 146 */ setFailure(Throwable x)147 void setFailure(Throwable x) { 148 if (!(x instanceof IOException) && !(x instanceof SecurityException)) 149 x = new IOException(x); 150 synchronized (this) { 151 if (haveResult) 152 return; 153 exc = x; 154 haveResult = true; 155 if (timeoutTask != null) 156 timeoutTask.cancel(false); 157 if (latch != null) 158 latch.countDown(); 159 } 160 } 161 162 /** 163 * Sets the result 164 */ setResult(V res, Throwable x)165 void setResult(V res, Throwable x) { 166 if (x == null) { 167 setResult(res); 168 } else { 169 setFailure(x); 170 } 171 } 172 173 @Override get()174 public V get() throws ExecutionException, InterruptedException { 175 if (!haveResult) { 176 boolean needToWait = prepareForWait(); 177 if (needToWait) 178 latch.await(); 179 } 180 if (exc != null) { 181 if (exc instanceof CancellationException) 182 throw new CancellationException(); 183 throw new ExecutionException(exc); 184 } 185 return result; 186 } 187 188 @Override get(long timeout, TimeUnit unit)189 public V get(long timeout, TimeUnit unit) 190 throws ExecutionException, InterruptedException, TimeoutException 191 { 192 if (!haveResult) { 193 boolean needToWait = prepareForWait(); 194 if (needToWait) 195 if (!latch.await(timeout, unit)) throw new TimeoutException(); 196 } 197 if (exc != null) { 198 if (exc instanceof CancellationException) 199 throw new CancellationException(); 200 throw new ExecutionException(exc); 201 } 202 return result; 203 } 204 exception()205 Throwable exception() { 206 return (exc instanceof CancellationException) ? null : exc; 207 } 208 value()209 V value() { 210 return result; 211 } 212 213 @Override isCancelled()214 public boolean isCancelled() { 215 return (exc instanceof CancellationException); 216 } 217 218 @Override isDone()219 public boolean isDone() { 220 return haveResult; 221 } 222 223 @Override cancel(boolean mayInterruptIfRunning)224 public boolean cancel(boolean mayInterruptIfRunning) { 225 synchronized (this) { 226 if (haveResult) 227 return false; // already completed 228 229 // notify channel 230 if (channel() instanceof Cancellable) 231 ((Cancellable)channel()).onCancel(this); 232 233 // set result and cancel timer 234 exc = new CancellationException(); 235 haveResult = true; 236 if (timeoutTask != null) 237 timeoutTask.cancel(false); 238 } 239 240 // close channel if forceful cancel 241 if (mayInterruptIfRunning) { 242 try { 243 channel().close(); 244 } catch (IOException ignore) { } 245 } 246 247 // release waiters 248 if (latch != null) 249 latch.countDown(); 250 return true; 251 } 252 } 253