Registers a callback and an "errback". If the deferred result is already available, the callback or the errback (depending on the nature of the result) is executed immediately from this thread. @param cb The callback to register. @param eb Th errback to register. @return this with an "up
(final Callback<R, T> cb,
final Callback<R2, E> eb)
| 635 | * you hit it, you probably did something wrong. |
| 636 | */ |
| 637 | @SuppressWarnings("unchecked") |
| 638 | public <R, R2, E> Deferred<R> addCallbacks(final Callback<R, T> cb, |
| 639 | final Callback<R2, E> eb) { |
| 640 | if (cb == null) { |
| 641 | throw new NullPointerException("null callback"); |
| 642 | } else if (eb == null) { |
| 643 | throw new NullPointerException("null errback"); |
| 644 | } |
| 645 | // We need to synchronize on `this' first before the CAS, to prevent |
| 646 | // runCallbacks from switching our state from RUNNING to DONE right |
| 647 | // before we add another callback. |
| 648 | synchronized (this) { |
| 649 | // If we're DONE, switch to RUNNING atomically. |
| 650 | if (state == DONE) { |
| 651 | // This "check-then-act" sequence is safe as this is the only code |
| 652 | // path that transitions from DONE to RUNNING and it's synchronized. |
| 653 | state = RUNNING; |
| 654 | } else { |
| 655 | // We get here if weren't DONE (most common code path) |
| 656 | // -or- |
| 657 | // if we were DONE and another thread raced with us to change the |
| 658 | // state and we lost the race (uncommon). |
| 659 | if (callbacks == null) { |
| 660 | callbacks = new Callback[INIT_CALLBACK_CHAIN_SIZE]; |
| 661 | } |
| 662 | // Do we need to grow the array? |
| 663 | else if (last_callback == callbacks.length) { |
| 664 | final int oldlen = callbacks.length; |
| 665 | if (oldlen == MAX_CALLBACK_CHAIN_LENGTH * 2) { |
| 666 | throw new CallbackOverflowError("Too many callbacks in " + this |
| 667 | + " (size=" + (oldlen / 2) + ") when attempting to add cb=" |
| 668 | + cb + '@' + cb.hashCode() + ", eb=" + eb + '@' + eb.hashCode()); |
| 669 | } |
| 670 | final int len = Math.min(oldlen * 2, MAX_CALLBACK_CHAIN_LENGTH * 2); |
| 671 | final Callback[] newcbs = new Callback[len]; |
| 672 | System.arraycopy(callbacks, next_callback, // Outstanding callbacks. |
| 673 | newcbs, 0, // Move them to the beginning. |
| 674 | last_callback - next_callback); // Number of items. |
| 675 | last_callback -= next_callback; |
| 676 | next_callback = 0; |
| 677 | callbacks = newcbs; |
| 678 | } |
| 679 | callbacks[last_callback++] = cb; |
| 680 | callbacks[last_callback++] = eb; |
| 681 | return (Deferred<R>) ((Deferred) this); |
| 682 | } |
| 683 | } // end of synchronized block |
| 684 | |
| 685 | if (!doCall(result instanceof Exception ? eb : cb)) { |
| 686 | // While we were executing the callback, another thread could have |
| 687 | // added more callbacks. If doCall returned true, it means we're |
| 688 | // PAUSED, so we won't reach this point, because the Deferred we're |
| 689 | // waiting on will call us back later. But if we're still in state |
| 690 | // RUNNING, we'll get to here, and we must check to see if any new |
| 691 | // callbacks were added while we were executing doCall, because if |
| 692 | // there are, we must execute them immediately, because no one else |
| 693 | // is going to execute them for us otherwise. |
| 694 | boolean more; |
no test coverage detected