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