001/*
002 * Copyright (C) 2011 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.util.concurrent;
016
017import static com.google.common.base.Verify.verify;
018import static com.google.common.util.concurrent.Internal.toNanosSaturated;
019import static java.util.concurrent.TimeUnit.NANOSECONDS;
020
021import com.google.common.annotations.GwtCompatible;
022import com.google.common.annotations.GwtIncompatible;
023import com.google.common.annotations.J2ktIncompatible;
024import com.google.common.base.Preconditions;
025import com.google.errorprone.annotations.CanIgnoreReturnValue;
026import java.time.Duration;
027import java.util.concurrent.BlockingQueue;
028import java.util.concurrent.CancellationException;
029import java.util.concurrent.CountDownLatch;
030import java.util.concurrent.ExecutionException;
031import java.util.concurrent.ExecutorService;
032import java.util.concurrent.Future;
033import java.util.concurrent.Semaphore;
034import java.util.concurrent.TimeUnit;
035import java.util.concurrent.TimeoutException;
036import java.util.concurrent.locks.Condition;
037import java.util.concurrent.locks.Lock;
038import org.checkerframework.checker.nullness.qual.Nullable;
039
040/**
041 * Utilities for treating interruptible operations as uninterruptible. In all cases, if a thread is
042 * interrupted during such a call, the call continues to block until the result is available or the
043 * timeout elapses, and only then re-interrupts the thread.
044 *
045 * @author Anthony Zana
046 * @since 10.0
047 */
048@GwtCompatible(emulated = true)
049@ElementTypesAreNonnullByDefault
050public final class Uninterruptibles {
051
052  // Implementation Note: As of 3-7-11, the logic for each blocking/timeout
053  // methods is identical, save for method being invoked.
054
055  /** Invokes {@code latch.}{@link CountDownLatch#await() await()} uninterruptibly. */
056  @J2ktIncompatible
057  @GwtIncompatible // concurrency
058  public static void awaitUninterruptibly(CountDownLatch latch) {
059    boolean interrupted = false;
060    try {
061      while (true) {
062        try {
063          latch.await();
064          return;
065        } catch (InterruptedException e) {
066          interrupted = true;
067        }
068      }
069    } finally {
070      if (interrupted) {
071        Thread.currentThread().interrupt();
072      }
073    }
074  }
075
076  /**
077   * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)}
078   * uninterruptibly.
079   *
080   * @since 33.4.0 (but since 28.0 in the JRE flavor)
081   */
082  @J2ktIncompatible
083  @GwtIncompatible // concurrency
084  @SuppressWarnings("Java7ApiChecker")
085  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
086  public static boolean awaitUninterruptibly(CountDownLatch latch, Duration timeout) {
087    return awaitUninterruptibly(latch, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
088  }
089
090  /**
091   * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)}
092   * uninterruptibly.
093   */
094  @J2ktIncompatible
095  @GwtIncompatible // concurrency
096  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
097  public static boolean awaitUninterruptibly(CountDownLatch latch, long timeout, TimeUnit unit) {
098    boolean interrupted = false;
099    try {
100      long remainingNanos = unit.toNanos(timeout);
101      long end = System.nanoTime() + remainingNanos;
102
103      while (true) {
104        try {
105          // CountDownLatch treats negative timeouts just like zero.
106          return latch.await(remainingNanos, NANOSECONDS);
107        } catch (InterruptedException e) {
108          interrupted = true;
109          remainingNanos = end - System.nanoTime();
110        }
111      }
112    } finally {
113      if (interrupted) {
114        Thread.currentThread().interrupt();
115      }
116    }
117  }
118
119  /**
120   * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)}
121   * uninterruptibly.
122   *
123   * @since 33.4.0 (but since 28.0 in the JRE flavor)
124   */
125  @J2ktIncompatible
126  @GwtIncompatible // concurrency
127  @SuppressWarnings("Java7ApiChecker")
128  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
129  public static boolean awaitUninterruptibly(Condition condition, Duration timeout) {
130    return awaitUninterruptibly(condition, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
131  }
132
133  /**
134   * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)}
135   * uninterruptibly.
136   *
137   * @since 23.6
138   */
139  @J2ktIncompatible
140  @GwtIncompatible // concurrency
141  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
142  public static boolean awaitUninterruptibly(Condition condition, long timeout, TimeUnit unit) {
143    boolean interrupted = false;
144    try {
145      long remainingNanos = unit.toNanos(timeout);
146      long end = System.nanoTime() + remainingNanos;
147
148      while (true) {
149        try {
150          return condition.await(remainingNanos, NANOSECONDS);
151        } catch (InterruptedException e) {
152          interrupted = true;
153          remainingNanos = end - System.nanoTime();
154        }
155      }
156    } finally {
157      if (interrupted) {
158        Thread.currentThread().interrupt();
159      }
160    }
161  }
162
163  /** Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly. */
164  @J2ktIncompatible
165  @GwtIncompatible // concurrency
166  public static void joinUninterruptibly(Thread toJoin) {
167    boolean interrupted = false;
168    try {
169      while (true) {
170        try {
171          toJoin.join();
172          return;
173        } catch (InterruptedException e) {
174          interrupted = true;
175        }
176      }
177    } finally {
178      if (interrupted) {
179        Thread.currentThread().interrupt();
180      }
181    }
182  }
183
184  /**
185   * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)}
186   * uninterruptibly.
187   *
188   * @since 33.4.0 (but since 28.0 in the JRE flavor)
189   */
190  @J2ktIncompatible
191  @GwtIncompatible // concurrency
192  @SuppressWarnings("Java7ApiChecker")
193  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
194  public static void joinUninterruptibly(Thread toJoin, Duration timeout) {
195    joinUninterruptibly(toJoin, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
196  }
197
198  /**
199   * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)}
200   * uninterruptibly.
201   */
202  @J2ktIncompatible
203  @GwtIncompatible // concurrency
204  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
205  public static void joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit) {
206    Preconditions.checkNotNull(toJoin);
207    boolean interrupted = false;
208    try {
209      long remainingNanos = unit.toNanos(timeout);
210      long end = System.nanoTime() + remainingNanos;
211      while (true) {
212        try {
213          // TimeUnit.timedJoin() treats negative timeouts just like zero.
214          NANOSECONDS.timedJoin(toJoin, remainingNanos);
215          return;
216        } catch (InterruptedException e) {
217          interrupted = true;
218          remainingNanos = end - System.nanoTime();
219        }
220      }
221    } finally {
222      if (interrupted) {
223        Thread.currentThread().interrupt();
224      }
225    }
226  }
227
228  /**
229   * Invokes {@code future.}{@link Future#get() get()} uninterruptibly.
230   *
231   * <p>Similar methods:
232   *
233   * <ul>
234   *   <li>To retrieve a result from a {@code Future} that is already done, use {@link
235   *       Futures#getDone Futures.getDone}.
236   *   <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link
237   *       Futures#getChecked(Future, Class) Futures.getChecked}.
238   *   <li>To get uninterruptibility and remove checked exceptions, use {@link
239   *       Futures#getUnchecked}.
240   * </ul>
241   *
242   * @throws ExecutionException if the computation threw an exception
243   * @throws CancellationException if the computation was cancelled
244   */
245  @CanIgnoreReturnValue
246  @ParametricNullness
247  public static <V extends @Nullable Object> V getUninterruptibly(Future<V> future)
248      throws ExecutionException {
249    boolean interrupted = false;
250    try {
251      while (true) {
252        try {
253          return future.get();
254        } catch (InterruptedException e) {
255          interrupted = true;
256        }
257      }
258    } finally {
259      if (interrupted) {
260        Thread.currentThread().interrupt();
261      }
262    }
263  }
264
265  /**
266   * Invokes {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} uninterruptibly.
267   *
268   * <p>Similar methods:
269   *
270   * <ul>
271   *   <li>To retrieve a result from a {@code Future} that is already done, use {@link
272   *       Futures#getDone Futures.getDone}.
273   *   <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link
274   *       Futures#getChecked(Future, Class, long, TimeUnit) Futures.getChecked}.
275   *   <li>To get uninterruptibility and remove checked exceptions, use {@link
276   *       Futures#getUnchecked}.
277   * </ul>
278   *
279   * @throws ExecutionException if the computation threw an exception
280   * @throws CancellationException if the computation was cancelled
281   * @throws TimeoutException if the wait timed out
282   * @since 33.4.0 (but since 28.0 in the JRE flavor)
283   */
284  @CanIgnoreReturnValue
285  @J2ktIncompatible
286  @GwtIncompatible // java.time.Duration
287  @ParametricNullness
288  @SuppressWarnings("Java7ApiChecker")
289  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
290  public static <V extends @Nullable Object> V getUninterruptibly(
291      Future<V> future, Duration timeout) throws ExecutionException, TimeoutException {
292    return getUninterruptibly(future, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
293  }
294
295  /**
296   * Invokes {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)} uninterruptibly.
297   *
298   * <p>Similar methods:
299   *
300   * <ul>
301   *   <li>To retrieve a result from a {@code Future} that is already done, use {@link
302   *       Futures#getDone Futures.getDone}.
303   *   <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link
304   *       Futures#getChecked(Future, Class, long, TimeUnit) Futures.getChecked}.
305   *   <li>To get uninterruptibility and remove checked exceptions, use {@link
306   *       Futures#getUnchecked}.
307   * </ul>
308   *
309   * @throws ExecutionException if the computation threw an exception
310   * @throws CancellationException if the computation was cancelled
311   * @throws TimeoutException if the wait timed out
312   */
313  @CanIgnoreReturnValue
314  @J2ktIncompatible
315  @GwtIncompatible // TODO
316  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
317  @ParametricNullness
318  public static <V extends @Nullable Object> V getUninterruptibly(
319      Future<V> future, long timeout, TimeUnit unit) throws ExecutionException, TimeoutException {
320    boolean interrupted = false;
321    try {
322      long remainingNanos = unit.toNanos(timeout);
323      long end = System.nanoTime() + remainingNanos;
324
325      while (true) {
326        try {
327          // Future treats negative timeouts just like zero.
328          return future.get(remainingNanos, NANOSECONDS);
329        } catch (InterruptedException e) {
330          interrupted = true;
331          remainingNanos = end - System.nanoTime();
332        }
333      }
334    } finally {
335      if (interrupted) {
336        Thread.currentThread().interrupt();
337      }
338    }
339  }
340
341  /** Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly. */
342  @J2ktIncompatible
343  @GwtIncompatible // concurrency
344  public static <E> E takeUninterruptibly(BlockingQueue<E> queue) {
345    boolean interrupted = false;
346    try {
347      while (true) {
348        try {
349          return queue.take();
350        } catch (InterruptedException e) {
351          interrupted = true;
352        }
353      }
354    } finally {
355      if (interrupted) {
356        Thread.currentThread().interrupt();
357      }
358    }
359  }
360
361  /**
362   * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)} uninterruptibly.
363   *
364   * @throws ClassCastException if the class of the specified element prevents it from being added
365   *     to the given queue
366   * @throws IllegalArgumentException if some property of the specified element prevents it from
367   *     being added to the given queue
368   */
369  @J2ktIncompatible
370  @GwtIncompatible // concurrency
371  public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) {
372    boolean interrupted = false;
373    try {
374      while (true) {
375        try {
376          queue.put(element);
377          return;
378        } catch (InterruptedException e) {
379          interrupted = true;
380        }
381      }
382    } finally {
383      if (interrupted) {
384        Thread.currentThread().interrupt();
385      }
386    }
387  }
388
389  // TODO(user): Support Sleeper somehow (wrapper or interface method)?
390  /**
391   * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly.
392   *
393   * @since 33.4.0 (but since 28.0 in the JRE flavor)
394   */
395  @J2ktIncompatible
396  @GwtIncompatible // concurrency
397  @SuppressWarnings("Java7ApiChecker")
398  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
399  public static void sleepUninterruptibly(Duration sleepFor) {
400    sleepUninterruptibly(toNanosSaturated(sleepFor), TimeUnit.NANOSECONDS);
401  }
402
403  // TODO(user): Support Sleeper somehow (wrapper or interface method)?
404  /** Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly. */
405  @J2ktIncompatible
406  @GwtIncompatible // concurrency
407  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
408  public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) {
409    boolean interrupted = false;
410    try {
411      long remainingNanos = unit.toNanos(sleepFor);
412      long end = System.nanoTime() + remainingNanos;
413      while (true) {
414        try {
415          // TimeUnit.sleep() treats negative timeouts just like zero.
416          NANOSECONDS.sleep(remainingNanos);
417          return;
418        } catch (InterruptedException e) {
419          interrupted = true;
420          remainingNanos = end - System.nanoTime();
421        }
422      }
423    } finally {
424      if (interrupted) {
425        Thread.currentThread().interrupt();
426      }
427    }
428  }
429
430  /**
431   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1,
432   * timeout, unit)} uninterruptibly.
433   *
434   * @since 33.4.0 (but since 28.0 in the JRE flavor)
435   */
436  @J2ktIncompatible
437  @GwtIncompatible // concurrency
438  @SuppressWarnings("Java7ApiChecker")
439  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
440  public static boolean tryAcquireUninterruptibly(Semaphore semaphore, Duration timeout) {
441    return tryAcquireUninterruptibly(semaphore, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
442  }
443
444  /**
445   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1,
446   * timeout, unit)} uninterruptibly.
447   *
448   * @since 18.0
449   */
450  @J2ktIncompatible
451  @GwtIncompatible // concurrency
452  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
453  public static boolean tryAcquireUninterruptibly(
454      Semaphore semaphore, long timeout, TimeUnit unit) {
455    return tryAcquireUninterruptibly(semaphore, 1, timeout, unit);
456  }
457
458  /**
459   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits,
460   * timeout, unit)} uninterruptibly.
461   *
462   * @since 33.4.0 (but since 28.0 in the JRE flavor)
463   */
464  @J2ktIncompatible
465  @GwtIncompatible // concurrency
466  @SuppressWarnings("Java7ApiChecker")
467  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
468  public static boolean tryAcquireUninterruptibly(
469      Semaphore semaphore, int permits, Duration timeout) {
470    return tryAcquireUninterruptibly(
471        semaphore, permits, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
472  }
473
474  /**
475   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits,
476   * timeout, unit)} uninterruptibly.
477   *
478   * @since 18.0
479   */
480  @J2ktIncompatible
481  @GwtIncompatible // concurrency
482  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
483  public static boolean tryAcquireUninterruptibly(
484      Semaphore semaphore, int permits, long timeout, TimeUnit unit) {
485    boolean interrupted = false;
486    try {
487      long remainingNanos = unit.toNanos(timeout);
488      long end = System.nanoTime() + remainingNanos;
489
490      while (true) {
491        try {
492          // Semaphore treats negative timeouts just like zero.
493          return semaphore.tryAcquire(permits, remainingNanos, NANOSECONDS);
494        } catch (InterruptedException e) {
495          interrupted = true;
496          remainingNanos = end - System.nanoTime();
497        }
498      }
499    } finally {
500      if (interrupted) {
501        Thread.currentThread().interrupt();
502      }
503    }
504  }
505
506  /**
507   * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)}
508   * uninterruptibly.
509   *
510   * @since 33.4.0 (but since 30.0 in the JRE flavor)
511   */
512  @J2ktIncompatible
513  @GwtIncompatible // concurrency
514  @SuppressWarnings("Java7ApiChecker")
515  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
516  public static boolean tryLockUninterruptibly(Lock lock, Duration timeout) {
517    return tryLockUninterruptibly(lock, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
518  }
519
520  /**
521   * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)}
522   * uninterruptibly.
523   *
524   * @since 30.0
525   */
526  @J2ktIncompatible
527  @GwtIncompatible // concurrency
528  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
529  public static boolean tryLockUninterruptibly(Lock lock, long timeout, TimeUnit unit) {
530    boolean interrupted = false;
531    try {
532      long remainingNanos = unit.toNanos(timeout);
533      long end = System.nanoTime() + remainingNanos;
534
535      while (true) {
536        try {
537          return lock.tryLock(remainingNanos, NANOSECONDS);
538        } catch (InterruptedException e) {
539          interrupted = true;
540          remainingNanos = end - System.nanoTime();
541        }
542      }
543    } finally {
544      if (interrupted) {
545        Thread.currentThread().interrupt();
546      }
547    }
548  }
549
550  /**
551   * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit)
552   * awaitTermination(long, TimeUnit)} uninterruptibly with no timeout.
553   *
554   * @since 30.0
555   */
556  @J2ktIncompatible
557  @GwtIncompatible // concurrency
558  public static void awaitTerminationUninterruptibly(ExecutorService executor) {
559    // TODO(cpovirk): We could optimize this to avoid calling nanoTime() at all.
560    verify(awaitTerminationUninterruptibly(executor, Long.MAX_VALUE, NANOSECONDS));
561  }
562
563  /**
564   * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit)
565   * awaitTermination(long, TimeUnit)} uninterruptibly.
566   *
567   * @since 33.4.0 (but since 30.0 in the JRE flavor)
568   */
569  @J2ktIncompatible
570  @GwtIncompatible // concurrency
571  @SuppressWarnings("Java7ApiChecker")
572  @IgnoreJRERequirement // Users will use this only if they're already using Duration.
573  public static boolean awaitTerminationUninterruptibly(
574      ExecutorService executor, Duration timeout) {
575    return awaitTerminationUninterruptibly(executor, toNanosSaturated(timeout), NANOSECONDS);
576  }
577
578  /**
579   * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit)
580   * awaitTermination(long, TimeUnit)} uninterruptibly.
581   *
582   * @since 30.0
583   */
584  @J2ktIncompatible
585  @GwtIncompatible // concurrency
586  @SuppressWarnings("GoodTime")
587  public static boolean awaitTerminationUninterruptibly(
588      ExecutorService executor, long timeout, TimeUnit unit) {
589    boolean interrupted = false;
590    try {
591      long remainingNanos = unit.toNanos(timeout);
592      long end = System.nanoTime() + remainingNanos;
593
594      while (true) {
595        try {
596          return executor.awaitTermination(remainingNanos, NANOSECONDS);
597        } catch (InterruptedException e) {
598          interrupted = true;
599          remainingNanos = end - System.nanoTime();
600        }
601      }
602    } finally {
603      if (interrupted) {
604        Thread.currentThread().interrupt();
605      }
606    }
607  }
608
609  // TODO(user): Add support for waitUninterruptibly.
610
611  private Uninterruptibles() {}
612}