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 private static final CancellationException CANCELLED = 39 new CancellationException(); 40 41 private final AsynchronousChannel channel; 42 private final CompletionHandler<V,? super A> handler; 43 private final A attachment; 44 45 // true if result (or exception) is available 46 private volatile boolean haveResult; 47 private volatile V result; 48 private volatile Throwable exc; 49 50 // latch for waiting (created lazily if needed) 51 private CountDownLatch latch; 52 53 // optional timer task that is cancelled when result becomes available 54 private Future<?> timeoutTask; 55 56 // optional context object 57 private volatile Object context; 58 PendingFuture(AsynchronousChannel channel, CompletionHandler<V,? super A> handler, A attachment, Object context)59 PendingFuture(AsynchronousChannel channel, 60 CompletionHandler<V,? super A> handler, 61 A attachment, 62 Object context) 63 { 64 this.channel = channel; 65 this.handler = handler; 66 this.attachment = attachment; 67 this.context = context; 68 } 69 PendingFuture(AsynchronousChannel channel, CompletionHandler<V,? super A> handler, A attachment)70 PendingFuture(AsynchronousChannel channel, 71 CompletionHandler<V,? super A> handler, 72 A attachment) 73 { 74 this.channel = channel; 75 this.handler = handler; 76 this.attachment = attachment; 77 } 78 PendingFuture(AsynchronousChannel channel)79 PendingFuture(AsynchronousChannel channel) { 80 this(channel, null, null); 81 } 82 PendingFuture(AsynchronousChannel channel, Object context)83 PendingFuture(AsynchronousChannel channel, Object context) { 84 this(channel, null, null, context); 85 } 86 channel()87 AsynchronousChannel channel() { 88 return channel; 89 } 90 handler()91 CompletionHandler<V,? super A> handler() { 92 return handler; 93 } 94 attachment()95 A attachment() { 96 return attachment; 97 } 98 setContext(Object context)99 void setContext(Object context) { 100 this.context = context; 101 } 102 getContext()103 Object getContext() { 104 return context; 105 } 106 setTimeoutTask(Future<?> task)107 void setTimeoutTask(Future<?> task) { 108 synchronized (this) { 109 if (haveResult) { 110 task.cancel(false); 111 } else { 112 this.timeoutTask = task; 113 } 114 } 115 } 116 117 // creates latch if required; return true if caller needs to wait prepareForWait()118 private boolean prepareForWait() { 119 synchronized (this) { 120 if (haveResult) { 121 return false; 122 } else { 123 if (latch == null) 124 latch = new CountDownLatch(1); 125 return true; 126 } 127 } 128 } 129 130 /** 131 * Sets the result, or a no-op if the result or exception is already set. 132 */ setResult(V res)133 void setResult(V res) { 134 synchronized (this) { 135 if (haveResult) 136 return; 137 result = res; 138 haveResult = true; 139 if (timeoutTask != null) 140 timeoutTask.cancel(false); 141 if (latch != null) 142 latch.countDown(); 143 } 144 } 145 146 /** 147 * Sets the result, or a no-op if the result or exception is already set. 148 */ setFailure(Throwable x)149 void setFailure(Throwable x) { 150 if (!(x instanceof IOException) && !(x instanceof SecurityException)) 151 x = new IOException(x); 152 synchronized (this) { 153 if (haveResult) 154 return; 155 exc = x; 156 haveResult = true; 157 if (timeoutTask != null) 158 timeoutTask.cancel(false); 159 if (latch != null) 160 latch.countDown(); 161 } 162 } 163 164 /** 165 * Sets the result 166 */ setResult(V res, Throwable x)167 void setResult(V res, Throwable x) { 168 if (x == null) { 169 setResult(res); 170 } else { 171 setFailure(x); 172 } 173 } 174 175 @Override get()176 public V get() throws ExecutionException, InterruptedException { 177 if (!haveResult) { 178 boolean needToWait = prepareForWait(); 179 if (needToWait) 180 latch.await(); 181 } 182 if (exc != null) { 183 if (exc == CANCELLED) 184 throw new CancellationException(); 185 throw new ExecutionException(exc); 186 } 187 return result; 188 } 189 190 @Override get(long timeout, TimeUnit unit)191 public V get(long timeout, TimeUnit unit) 192 throws ExecutionException, InterruptedException, TimeoutException 193 { 194 if (!haveResult) { 195 boolean needToWait = prepareForWait(); 196 if (needToWait) 197 if (!latch.await(timeout, unit)) throw new TimeoutException(); 198 } 199 if (exc != null) { 200 if (exc == CANCELLED) 201 throw new CancellationException(); 202 throw new ExecutionException(exc); 203 } 204 return result; 205 } 206 exception()207 Throwable exception() { 208 return (exc != CANCELLED) ? exc : null; 209 } 210 value()211 V value() { 212 return result; 213 } 214 215 @Override isCancelled()216 public boolean isCancelled() { 217 return (exc == CANCELLED); 218 } 219 220 @Override isDone()221 public boolean isDone() { 222 return haveResult; 223 } 224 225 @Override cancel(boolean mayInterruptIfRunning)226 public boolean cancel(boolean mayInterruptIfRunning) { 227 synchronized (this) { 228 if (haveResult) 229 return false; // already completed 230 231 // notify channel 232 if (channel() instanceof Cancellable) 233 ((Cancellable)channel()).onCancel(this); 234 235 // set result and cancel timer 236 exc = CANCELLED; 237 haveResult = true; 238 if (timeoutTask != null) 239 timeoutTask.cancel(false); 240 } 241 242 // close channel if forceful cancel 243 if (mayInterruptIfRunning) { 244 try { 245 channel().close(); 246 } catch (IOException ignore) { } 247 } 248 249 // release waiters 250 if (latch != null) 251 latch.countDown(); 252 return true; 253 } 254 } 255