Synchronously waits until this Deferred is called back. @param interruptible Whether or not to let InterruptedException interrupt us. If false then this method will never throw InterruptedException, it will handle it and keep waiting. In this case though, the interrupted st
(final boolean interruptible, final long timeout)
| 1110 | * @throws TimeoutException if there's a timeout. |
| 1111 | */ |
| 1112 | @SuppressWarnings("unchecked") |
| 1113 | private T doJoin(final boolean interruptible, final long timeout) |
| 1114 | throws InterruptedException, Exception { |
| 1115 | if (state == DONE) { // Nothing to join, we're already DONE. |
| 1116 | if (result instanceof Exception) { |
| 1117 | throw (Exception) result; |
| 1118 | } |
| 1119 | return (T) result; |
| 1120 | } |
| 1121 | |
| 1122 | final Signal signal_cb = new Signal(); |
| 1123 | |
| 1124 | // Dealing with InterruptedException properly is a PITA. I highly |
| 1125 | // recommend reading http://goo.gl/aeOOXT to understand how this works. |
| 1126 | boolean interrupted = false; |
| 1127 | try { |
| 1128 | while (true) { |
| 1129 | try { |
| 1130 | boolean timedout = false; |
| 1131 | synchronized (signal_cb) { |
| 1132 | addBoth((Callback<T, T>) ((Object) signal_cb)); |
| 1133 | if (timeout == 0) { // No timeout, we can use a simple loop. |
| 1134 | // If we get called back immediately, we won't enter the loop. |
| 1135 | while (signal_cb.result == signal_cb) { |
| 1136 | signal_cb.wait(); |
| 1137 | } |
| 1138 | } else if (timeout < 0) { |
| 1139 | throw new IllegalArgumentException("negative timeout: " + timeout); |
| 1140 | } else { // We have a timeout, the loop is a bit more complicated. |
| 1141 | long timeleft = timeout * 1000000L; // Convert to nanoseconds. |
| 1142 | if (timeout > 31556926000L) { // One year in milliseconds. |
| 1143 | // Most likely a programming bug. |
| 1144 | LOG.warn("Timeout (" + timeout + ") is long than 1 year." |
| 1145 | + " this=" + this); |
| 1146 | if (timeleft <= 0) { // Very unlikely. |
| 1147 | throw new IllegalArgumentException("timeout overflow after" |
| 1148 | + " conversion to nanoseconds: " + timeout); |
| 1149 | } |
| 1150 | } |
| 1151 | // If we get called back immediately, we won't enter the loop. |
| 1152 | while (signal_cb.result == signal_cb) { |
| 1153 | // We can't distinguish between a timeout and a spurious wakeup. |
| 1154 | // So we have to time how long we slept to figure out whether we |
| 1155 | // timed out or how long we need to sleep again. There's no |
| 1156 | // better way to do this, that's how it's implemented in the JDK |
| 1157 | // in `AbstractQueuedSynchronizer.ConditionObject.awaitNanos()'. |
| 1158 | long duration = System.nanoTime(); |
| 1159 | final long millis = timeleft / 1000000L; |
| 1160 | final int nanos = (int) (timeleft % 1000000); |
| 1161 | // This API is annoying because it won't let us specify just |
| 1162 | // nanoseconds. The second argument must be less than 1000000. |
| 1163 | signal_cb.wait(millis, nanos); |
| 1164 | duration = System.nanoTime() - duration; |
| 1165 | timeleft -= duration; |
| 1166 | // If we have 0ns or less left, the timeout has expired |
| 1167 | // already. If we have less than 100ns left, there's no |
| 1168 | // point in looping again, as just going through the loop |
| 1169 | // above easily takes 100ns on a modern x86-64 CPU, after |
no test coverage detected