1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.util.concurrent;
17
18 import io.netty.util.internal.InternalThreadLocalMap;
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.StringUtil;
21 import io.netty.util.internal.SystemPropertyUtil;
22 import io.netty.util.internal.ThrowableUtil;
23 import io.netty.util.internal.logging.InternalLogger;
24 import io.netty.util.internal.logging.InternalLoggerFactory;
25
26 import java.util.concurrent.CancellationException;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.TimeoutException;
30 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
31
32 import static io.netty.util.internal.ObjectUtil.checkNotNull;
33 import static java.util.concurrent.TimeUnit.MILLISECONDS;
34
35 public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
36 private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultPromise.class);
37 private static final InternalLogger rejectedExecutionLogger =
38 InternalLoggerFactory.getInstance(DefaultPromise.class.getName() + ".rejectedExecution");
39 private static final int MAX_LISTENER_STACK_DEPTH = Math.min(8,
40 SystemPropertyUtil.getInt("io.netty.defaultPromise.maxListenerStackDepth", 8));
41 @SuppressWarnings("rawtypes")
42 private static final AtomicReferenceFieldUpdater<DefaultPromise, Object> RESULT_UPDATER =
43 AtomicReferenceFieldUpdater.newUpdater(DefaultPromise.class, Object.class, "result");
44 private static final Object SUCCESS = new Object();
45 private static final Object UNCANCELLABLE = new Object();
46 private static final CauseHolder CANCELLATION_CAUSE_HOLDER = new CauseHolder(
47 StacklessCancellationException.newInstance(DefaultPromise.class, "cancel(...)"));
48 private static final StackTraceElement[] CANCELLATION_STACK = CANCELLATION_CAUSE_HOLDER.cause.getStackTrace();
49
50 private volatile Object result;
51 private final EventExecutor executor;
52
53
54
55
56
57
58 private GenericFutureListener<? extends Future<?>> listener;
59 private DefaultFutureListeners listeners;
60
61
62
63 private short waiters;
64
65
66
67
68
69 private boolean notifyingListeners;
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public DefaultPromise(EventExecutor executor) {
84 this.executor = checkNotNull(executor, "executor");
85 }
86
87
88
89
90 protected DefaultPromise() {
91
92 executor = null;
93 }
94
95 @Override
96 public Promise<V> setSuccess(V result) {
97 if (setSuccess0(result)) {
98 return this;
99 }
100 throw new IllegalStateException("complete already: " + this);
101 }
102
103 @Override
104 public boolean trySuccess(V result) {
105 return setSuccess0(result);
106 }
107
108 @Override
109 public Promise<V> setFailure(Throwable cause) {
110 if (setFailure0(cause)) {
111 return this;
112 }
113 throw new IllegalStateException("complete already: " + this, cause);
114 }
115
116 @Override
117 public boolean tryFailure(Throwable cause) {
118 return setFailure0(cause);
119 }
120
121 @Override
122 public boolean setUncancellable() {
123 if (RESULT_UPDATER.compareAndSet(this, null, UNCANCELLABLE)) {
124 return true;
125 }
126 Object result = this.result;
127 return !isDone0(result) || !isCancelled0(result);
128 }
129
130 @Override
131 public boolean isSuccess() {
132 Object result = this.result;
133 return result != null && result != UNCANCELLABLE && !(result instanceof CauseHolder);
134 }
135
136 @Override
137 public boolean isCancellable() {
138 return result == null;
139 }
140
141 private static final class LeanCancellationException extends CancellationException {
142 private static final long serialVersionUID = 2794674970981187807L;
143
144
145 @Override
146 public Throwable fillInStackTrace() {
147 setStackTrace(CANCELLATION_STACK);
148 return this;
149 }
150
151 @Override
152 public String toString() {
153 return CancellationException.class.getName();
154 }
155 }
156
157 @Override
158 public Throwable cause() {
159 return cause0(result);
160 }
161
162 private Throwable cause0(Object result) {
163 if (!(result instanceof CauseHolder)) {
164 return null;
165 }
166 if (result == CANCELLATION_CAUSE_HOLDER) {
167 CancellationException ce = new LeanCancellationException();
168 if (RESULT_UPDATER.compareAndSet(this, CANCELLATION_CAUSE_HOLDER, new CauseHolder(ce))) {
169 return ce;
170 }
171 result = this.result;
172 }
173 return ((CauseHolder) result).cause;
174 }
175
176 @Override
177 public Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
178 checkNotNull(listener, "listener");
179
180 synchronized (this) {
181 addListener0(listener);
182 }
183
184 if (isDone()) {
185 notifyListeners();
186 }
187
188 return this;
189 }
190
191 @Override
192 public Promise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners) {
193 checkNotNull(listeners, "listeners");
194
195 synchronized (this) {
196 for (GenericFutureListener<? extends Future<? super V>> listener : listeners) {
197 if (listener == null) {
198 break;
199 }
200 addListener0(listener);
201 }
202 }
203
204 if (isDone()) {
205 notifyListeners();
206 }
207
208 return this;
209 }
210
211 @Override
212 public Promise<V> removeListener(final GenericFutureListener<? extends Future<? super V>> listener) {
213 checkNotNull(listener, "listener");
214
215 synchronized (this) {
216 removeListener0(listener);
217 }
218
219 return this;
220 }
221
222 @Override
223 public Promise<V> removeListeners(final GenericFutureListener<? extends Future<? super V>>... listeners) {
224 checkNotNull(listeners, "listeners");
225
226 synchronized (this) {
227 for (GenericFutureListener<? extends Future<? super V>> listener : listeners) {
228 if (listener == null) {
229 break;
230 }
231 removeListener0(listener);
232 }
233 }
234
235 return this;
236 }
237
238 @Override
239 public Promise<V> await() throws InterruptedException {
240 if (isDone()) {
241 return this;
242 }
243
244 if (Thread.interrupted()) {
245 throw new InterruptedException(toString());
246 }
247
248 checkDeadLock();
249
250 synchronized (this) {
251 while (!isDone()) {
252 incWaiters();
253 try {
254 wait();
255 } finally {
256 decWaiters();
257 }
258 }
259 }
260 return this;
261 }
262
263 @Override
264 public Promise<V> awaitUninterruptibly() {
265 if (isDone()) {
266 return this;
267 }
268
269 checkDeadLock();
270
271 boolean interrupted = false;
272 synchronized (this) {
273 while (!isDone()) {
274 incWaiters();
275 try {
276 wait();
277 } catch (InterruptedException e) {
278
279 interrupted = true;
280 } finally {
281 decWaiters();
282 }
283 }
284 }
285
286 if (interrupted) {
287 Thread.currentThread().interrupt();
288 }
289
290 return this;
291 }
292
293 @Override
294 public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
295 return await0(unit.toNanos(timeout), true);
296 }
297
298 @Override
299 public boolean await(long timeoutMillis) throws InterruptedException {
300 return await0(MILLISECONDS.toNanos(timeoutMillis), true);
301 }
302
303 @Override
304 public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
305 try {
306 return await0(unit.toNanos(timeout), false);
307 } catch (InterruptedException e) {
308
309 throw new InternalError();
310 }
311 }
312
313 @Override
314 public boolean awaitUninterruptibly(long timeoutMillis) {
315 try {
316 return await0(MILLISECONDS.toNanos(timeoutMillis), false);
317 } catch (InterruptedException e) {
318
319 throw new InternalError();
320 }
321 }
322
323 @SuppressWarnings("unchecked")
324 @Override
325 public V getNow() {
326 Object result = this.result;
327 if (result instanceof CauseHolder || result == SUCCESS || result == UNCANCELLABLE) {
328 return null;
329 }
330 return (V) result;
331 }
332
333 @SuppressWarnings("unchecked")
334 @Override
335 public V get() throws InterruptedException, ExecutionException {
336 Object result = this.result;
337 if (!isDone0(result)) {
338 await();
339 result = this.result;
340 }
341 if (result == SUCCESS || result == UNCANCELLABLE) {
342 return null;
343 }
344 Throwable cause = cause0(result);
345 if (cause == null) {
346 return (V) result;
347 }
348 if (cause instanceof CancellationException) {
349 throw (CancellationException) cause;
350 }
351 throw new ExecutionException(cause);
352 }
353
354 @SuppressWarnings("unchecked")
355 @Override
356 public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
357 Object result = this.result;
358 if (!isDone0(result)) {
359 if (!await(timeout, unit)) {
360 throw new TimeoutException();
361 }
362 result = this.result;
363 }
364 if (result == SUCCESS || result == UNCANCELLABLE) {
365 return null;
366 }
367 Throwable cause = cause0(result);
368 if (cause == null) {
369 return (V) result;
370 }
371 if (cause instanceof CancellationException) {
372 throw (CancellationException) cause;
373 }
374 throw new ExecutionException(cause);
375 }
376
377
378
379
380
381
382 @Override
383 public boolean cancel(boolean mayInterruptIfRunning) {
384 if (RESULT_UPDATER.compareAndSet(this, null, CANCELLATION_CAUSE_HOLDER)) {
385 if (checkNotifyWaiters()) {
386 notifyListeners();
387 }
388 return true;
389 }
390 return false;
391 }
392
393 @Override
394 public boolean isCancelled() {
395 return isCancelled0(result);
396 }
397
398 @Override
399 public boolean isDone() {
400 return isDone0(result);
401 }
402
403 @Override
404 public Promise<V> sync() throws InterruptedException {
405 await();
406 rethrowIfFailed();
407 return this;
408 }
409
410 @Override
411 public Promise<V> syncUninterruptibly() {
412 awaitUninterruptibly();
413 rethrowIfFailed();
414 return this;
415 }
416
417 @Override
418 public String toString() {
419 return toStringBuilder().toString();
420 }
421
422 protected StringBuilder toStringBuilder() {
423 StringBuilder buf = new StringBuilder(64)
424 .append(StringUtil.simpleClassName(this))
425 .append('@')
426 .append(Integer.toHexString(hashCode()));
427
428 Object result = this.result;
429 if (result == SUCCESS) {
430 buf.append("(success)");
431 } else if (result == UNCANCELLABLE) {
432 buf.append("(uncancellable)");
433 } else if (result instanceof CauseHolder) {
434 buf.append("(failure: ")
435 .append(((CauseHolder) result).cause)
436 .append(')');
437 } else if (result != null) {
438 buf.append("(success: ")
439 .append(result)
440 .append(')');
441 } else {
442 buf.append("(incomplete)");
443 }
444
445 return buf;
446 }
447
448
449
450
451
452
453
454
455
456 protected EventExecutor executor() {
457 return executor;
458 }
459
460 protected void checkDeadLock() {
461 EventExecutor e = executor();
462 if (e != null && e.inEventLoop()) {
463 throw new BlockingOperationException(toString());
464 }
465 }
466
467
468
469
470
471
472
473
474
475
476 protected static void notifyListener(
477 EventExecutor eventExecutor, final Future<?> future, final GenericFutureListener<?> listener) {
478 notifyListenerWithStackOverFlowProtection(
479 checkNotNull(eventExecutor, "eventExecutor"),
480 checkNotNull(future, "future"),
481 checkNotNull(listener, "listener"));
482 }
483
484 private void notifyListeners() {
485 EventExecutor executor = executor();
486 if (executor.inEventLoop()) {
487 final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
488 final int stackDepth = threadLocals.futureListenerStackDepth();
489 if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
490 threadLocals.setFutureListenerStackDepth(stackDepth + 1);
491 try {
492 notifyListenersNow();
493 } finally {
494 threadLocals.setFutureListenerStackDepth(stackDepth);
495 }
496 return;
497 }
498 }
499
500 safeExecute(executor, new Runnable() {
501 @Override
502 public void run() {
503 notifyListenersNow();
504 }
505 });
506 }
507
508
509
510
511
512
513 private static void notifyListenerWithStackOverFlowProtection(final EventExecutor executor,
514 final Future<?> future,
515 final GenericFutureListener<?> listener) {
516 if (executor.inEventLoop()) {
517 final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
518 final int stackDepth = threadLocals.futureListenerStackDepth();
519 if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
520 threadLocals.setFutureListenerStackDepth(stackDepth + 1);
521 try {
522 notifyListener0(future, listener);
523 } finally {
524 threadLocals.setFutureListenerStackDepth(stackDepth);
525 }
526 return;
527 }
528 }
529
530 safeExecute(executor, new Runnable() {
531 @Override
532 public void run() {
533 notifyListener0(future, listener);
534 }
535 });
536 }
537
538 private void notifyListenersNow() {
539 GenericFutureListener listener;
540 DefaultFutureListeners listeners;
541 synchronized (this) {
542 listener = this.listener;
543 listeners = this.listeners;
544
545 if (notifyingListeners || (listener == null && listeners == null)) {
546 return;
547 }
548 notifyingListeners = true;
549 if (listener != null) {
550 this.listener = null;
551 } else {
552 this.listeners = null;
553 }
554 }
555 for (;;) {
556 if (listener != null) {
557 notifyListener0(this, listener);
558 } else {
559 notifyListeners0(listeners);
560 }
561 synchronized (this) {
562 if (this.listener == null && this.listeners == null) {
563
564
565 notifyingListeners = false;
566 return;
567 }
568 listener = this.listener;
569 listeners = this.listeners;
570 if (listener != null) {
571 this.listener = null;
572 } else {
573 this.listeners = null;
574 }
575 }
576 }
577 }
578
579 private void notifyListeners0(DefaultFutureListeners listeners) {
580 GenericFutureListener<?>[] a = listeners.listeners();
581 int size = listeners.size();
582 for (int i = 0; i < size; i ++) {
583 notifyListener0(this, a[i]);
584 }
585 }
586
587 @SuppressWarnings({ "unchecked", "rawtypes" })
588 private static void notifyListener0(Future future, GenericFutureListener l) {
589 try {
590 l.operationComplete(future);
591 } catch (Throwable t) {
592 if (logger.isWarnEnabled()) {
593 logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", t);
594 }
595 }
596 }
597
598 private void addListener0(GenericFutureListener<? extends Future<? super V>> listener) {
599 if (this.listener == null) {
600 if (listeners == null) {
601 this.listener = listener;
602 } else {
603 listeners.add(listener);
604 }
605 } else {
606 assert listeners == null;
607 listeners = new DefaultFutureListeners(this.listener, listener);
608 this.listener = null;
609 }
610 }
611
612 private void removeListener0(GenericFutureListener<? extends Future<? super V>> toRemove) {
613 if (listener == toRemove) {
614 listener = null;
615 } else if (listeners != null) {
616 listeners.remove(toRemove);
617
618 if (listeners.size() == 0) {
619 listeners = null;
620 }
621 }
622 }
623
624 private boolean setSuccess0(V result) {
625 return setValue0(result == null ? SUCCESS : result);
626 }
627
628 private boolean setFailure0(Throwable cause) {
629 return setValue0(new CauseHolder(checkNotNull(cause, "cause")));
630 }
631
632 private boolean setValue0(Object objResult) {
633 if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
634 RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
635 if (checkNotifyWaiters()) {
636 notifyListeners();
637 }
638 return true;
639 }
640 return false;
641 }
642
643
644
645
646
647 private synchronized boolean checkNotifyWaiters() {
648 if (waiters > 0) {
649 notifyAll();
650 }
651 return listener != null || listeners != null;
652 }
653
654 private void incWaiters() {
655 if (waiters == Short.MAX_VALUE) {
656 throw new IllegalStateException("too many waiters: " + this);
657 }
658 ++waiters;
659 }
660
661 private void decWaiters() {
662 --waiters;
663 }
664
665 private void rethrowIfFailed() {
666 Throwable cause = cause();
667 if (cause == null) {
668 return;
669 }
670
671 PlatformDependent.throwException(cause);
672 }
673
674 private boolean await0(long timeoutNanos, boolean interruptable) throws InterruptedException {
675 if (isDone()) {
676 return true;
677 }
678
679 if (timeoutNanos <= 0) {
680 return isDone();
681 }
682
683 if (interruptable && Thread.interrupted()) {
684 throw new InterruptedException(toString());
685 }
686
687 checkDeadLock();
688
689
690
691 final long startTime = System.nanoTime();
692 synchronized (this) {
693 boolean interrupted = false;
694 try {
695 long waitTime = timeoutNanos;
696 while (!isDone() && waitTime > 0) {
697 incWaiters();
698 try {
699 wait(waitTime / 1000000, (int) (waitTime % 1000000));
700 } catch (InterruptedException e) {
701 if (interruptable) {
702 throw e;
703 } else {
704 interrupted = true;
705 }
706 } finally {
707 decWaiters();
708 }
709
710 if (isDone()) {
711 return true;
712 }
713
714
715 waitTime = timeoutNanos - (System.nanoTime() - startTime);
716 }
717 return isDone();
718 } finally {
719 if (interrupted) {
720 Thread.currentThread().interrupt();
721 }
722 }
723 }
724 }
725
726
727
728
729
730
731
732
733
734
735
736 @SuppressWarnings("unchecked")
737 void notifyProgressiveListeners(final long progress, final long total) {
738 final Object listeners = progressiveListeners();
739 if (listeners == null) {
740 return;
741 }
742
743 final ProgressiveFuture<V> self = (ProgressiveFuture<V>) this;
744
745 EventExecutor executor = executor();
746 if (executor.inEventLoop()) {
747 if (listeners instanceof GenericProgressiveFutureListener[]) {
748 notifyProgressiveListeners0(
749 self, (GenericProgressiveFutureListener<?>[]) listeners, progress, total);
750 } else {
751 notifyProgressiveListener0(
752 self, (GenericProgressiveFutureListener<ProgressiveFuture<V>>) listeners, progress, total);
753 }
754 } else {
755 if (listeners instanceof GenericProgressiveFutureListener[]) {
756 final GenericProgressiveFutureListener<?>[] array =
757 (GenericProgressiveFutureListener<?>[]) listeners;
758 safeExecute(executor, new Runnable() {
759 @Override
760 public void run() {
761 notifyProgressiveListeners0(self, array, progress, total);
762 }
763 });
764 } else {
765 final GenericProgressiveFutureListener<ProgressiveFuture<V>> l =
766 (GenericProgressiveFutureListener<ProgressiveFuture<V>>) listeners;
767 safeExecute(executor, new Runnable() {
768 @Override
769 public void run() {
770 notifyProgressiveListener0(self, l, progress, total);
771 }
772 });
773 }
774 }
775 }
776
777
778
779
780
781 private synchronized Object progressiveListeners() {
782 final GenericFutureListener listener = this.listener;
783 final DefaultFutureListeners listeners = this.listeners;
784 if (listener == null && listeners == null) {
785
786 return null;
787 }
788
789 if (listeners != null) {
790
791 DefaultFutureListeners dfl = listeners;
792 int progressiveSize = dfl.progressiveSize();
793 switch (progressiveSize) {
794 case 0:
795 return null;
796 case 1:
797 for (GenericFutureListener<?> l: dfl.listeners()) {
798 if (l instanceof GenericProgressiveFutureListener) {
799 return l;
800 }
801 }
802 return null;
803 }
804
805 GenericFutureListener<?>[] array = dfl.listeners();
806 GenericProgressiveFutureListener<?>[] copy = new GenericProgressiveFutureListener[progressiveSize];
807 for (int i = 0, j = 0; j < progressiveSize; i ++) {
808 GenericFutureListener<?> l = array[i];
809 if (l instanceof GenericProgressiveFutureListener) {
810 copy[j ++] = (GenericProgressiveFutureListener<?>) l;
811 }
812 }
813
814 return copy;
815 } else if (listener instanceof GenericProgressiveFutureListener) {
816 return listener;
817 } else {
818
819 return null;
820 }
821 }
822
823 private static void notifyProgressiveListeners0(
824 ProgressiveFuture<?> future, GenericProgressiveFutureListener<?>[] listeners, long progress, long total) {
825 for (GenericProgressiveFutureListener<?> l: listeners) {
826 if (l == null) {
827 break;
828 }
829 notifyProgressiveListener0(future, l, progress, total);
830 }
831 }
832
833 @SuppressWarnings({ "unchecked", "rawtypes" })
834 private static void notifyProgressiveListener0(
835 ProgressiveFuture future, GenericProgressiveFutureListener l, long progress, long total) {
836 try {
837 l.operationProgressed(future, progress, total);
838 } catch (Throwable t) {
839 if (logger.isWarnEnabled()) {
840 logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationProgressed()", t);
841 }
842 }
843 }
844
845 private static boolean isCancelled0(Object result) {
846 return result instanceof CauseHolder && ((CauseHolder) result).cause instanceof CancellationException;
847 }
848
849 private static boolean isDone0(Object result) {
850 return result != null && result != UNCANCELLABLE;
851 }
852
853 private static final class CauseHolder {
854 final Throwable cause;
855 CauseHolder(Throwable cause) {
856 this.cause = cause;
857 }
858 }
859
860 private static void safeExecute(EventExecutor executor, Runnable task) {
861 try {
862 executor.execute(task);
863 } catch (Throwable t) {
864 rejectedExecutionLogger.error("Failed to submit a listener notification task. Event loop shut down?", t);
865 }
866 }
867
868 private static final class StacklessCancellationException extends CancellationException {
869
870 private static final long serialVersionUID = -2974906711413716191L;
871
872 private StacklessCancellationException() { }
873
874
875
876 @Override
877 public Throwable fillInStackTrace() {
878 return this;
879 }
880
881 static StacklessCancellationException newInstance(Class<?> clazz, String method) {
882 return ThrowableUtil.unknownStackTrace(new StacklessCancellationException(), clazz, method);
883 }
884 }
885 }