View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
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       * One or more listeners. Can be a {@link GenericFutureListener} or a {@link DefaultFutureListeners}.
54       * If {@code null}, it means either 1) no listeners were added yet or 2) all listeners were notified.
55       *
56       * Threading - synchronized(this). We must support adding listeners when there is no EventExecutor.
57       */
58      private GenericFutureListener<? extends Future<?>> listener;
59      private DefaultFutureListeners listeners;
60      /**
61       * Threading - synchronized(this). We are required to hold the monitor to use Java's underlying wait()/notifyAll().
62       */
63      private short waiters;
64  
65      /**
66       * Threading - synchronized(this). We must prevent concurrent notification and FIFO listener notification if the
67       * executor changes.
68       */
69      private boolean notifyingListeners;
70  
71      /**
72       * Creates a new instance.
73       *
74       * It is preferable to use {@link EventExecutor#newPromise()} to create a new promise
75       *
76       * @param executor
77       *        the {@link EventExecutor} which is used to notify the promise once it is complete.
78       *        It is assumed this executor will protect against {@link StackOverflowError} exceptions.
79       *        The executor may be used to avoid {@link StackOverflowError} by executing a {@link Runnable} if the stack
80       *        depth exceeds a threshold.
81       *
82       */
83      public DefaultPromise(EventExecutor executor) {
84          this.executor = checkNotNull(executor, "executor");
85      }
86  
87      /**
88       * See {@link #executor()} for expectations of the executor.
89       */
90      protected DefaultPromise() {
91          // only for subclasses
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         // Suppress a warning since the method doesn't need synchronization
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                     // Interrupted while waiting.
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             // Should not be raised at all.
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             // Should not be raised at all.
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      * {@inheritDoc}
379      *
380      * @param mayInterruptIfRunning this value has no effect in this implementation.
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      * Get the executor used to notify listeners when this promise is complete.
450      * <p>
451      * It is assumed this executor will protect against {@link StackOverflowError} exceptions.
452      * The executor may be used to avoid {@link StackOverflowError} by executing a {@link Runnable} if the stack
453      * depth exceeds a threshold.
454      * @return The executor used to notify listeners when this promise is complete.
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      * Notify a listener that a future has completed.
469      * <p>
470      * This method has a fixed depth of {@link #MAX_LISTENER_STACK_DEPTH} that will limit recursion to prevent
471      * {@link StackOverflowError} and will stop notifying listeners added after this threshold is exceeded.
472      * @param eventExecutor the executor to use to notify the listener {@code listener}.
473      * @param future the future that is complete.
474      * @param listener the listener to notify.
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      * The logic in this method should be identical to {@link #notifyListeners()} but
510      * cannot share code because the listener(s) cannot be cached for an instance of {@link DefaultPromise} since the
511      * listener(s) may be changed and is protected by a synchronized operation.
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             // Only proceed if there are listeners to notify and we are not already notifying listeners.
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                     // Nothing can throw from within this method, so setting notifyingListeners back to false does not
564                     // need to be in a finally block.
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             // Removal is rare, no need for compaction
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      * Check if there are any waiters and if so notify these.
645      * @return {@code true} if there are any listeners attached to the promise, {@code false} otherwise.
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         // Start counting time from here instead of the first line of this method,
690         // to avoid/postpone performance cost of System.nanoTime().
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                     // Check isDone() in advance, try to avoid calculating the elapsed time later.
710                     if (isDone()) {
711                         return true;
712                     }
713                     // Calculate the elapsed time here instead of in the while condition,
714                     // try to avoid performance cost of System.nanoTime() in the first loop of while.
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      * Notify all progressive listeners.
728      * <p>
729      * No attempt is made to ensure notification order if multiple calls are made to this method before
730      * the original invocation completes.
731      * <p>
732      * This will do an iteration over all listeners to get all of type {@link GenericProgressiveFutureListener}s.
733      * @param progress the new progress.
734      * @param total the total progress.
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      * Returns a {@link GenericProgressiveFutureListener}, an array of {@link GenericProgressiveFutureListener}, or
779      * {@code null}.
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             // No listeners added
786             return null;
787         }
788 
789         if (listeners != null) {
790             // Copy DefaultFutureListeners into an array of listeners.
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             // Only one listener was added and it's not a progressive listener.
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         // Override fillInStackTrace() so we not populate the backtrace via a native call and so leak the
875         // Classloader.
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 }