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