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