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.Beta;
022import com.google.common.annotations.GwtCompatible;
023import com.google.common.annotations.GwtIncompatible;
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;
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)
048public final class Uninterruptibles {
049
050  // Implementation Note: As of 3-7-11, the logic for each blocking/timeout
051  // methods is identical, save for method being invoked.
052
053  /** Invokes {@code latch.}{@link CountDownLatch#await() await()} uninterruptibly. */
054  @GwtIncompatible // concurrency
055  public static void awaitUninterruptibly(CountDownLatch latch) {
056    boolean interrupted = false;
057    try {
058      while (true) {
059        try {
060          latch.await();
061          return;
062        } catch (InterruptedException e) {
063          interrupted = true;
064        }
065      }
066    } finally {
067      if (interrupted) {
068        Thread.currentThread().interrupt();
069      }
070    }
071  }
072
073  /**
074   * Invokes {@code latch.}{@link CountDownLatch#await(long, TimeUnit) await(timeout, unit)}
075   * uninterruptibly.
076   *
077   * @since 28.0
078   */
079  @CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict.
080  @GwtIncompatible // concurrency
081  @Beta
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  @Beta
123  public static boolean awaitUninterruptibly(Condition condition, Duration timeout) {
124    return awaitUninterruptibly(condition, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
125  }
126
127  /**
128   * Invokes {@code condition.}{@link Condition#await(long, TimeUnit) await(timeout, unit)}
129   * uninterruptibly.
130   *
131   * @since 23.6
132   */
133  @GwtIncompatible // concurrency
134  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
135  public static boolean awaitUninterruptibly(Condition condition, long timeout, TimeUnit unit) {
136    boolean interrupted = false;
137    try {
138      long remainingNanos = unit.toNanos(timeout);
139      long end = System.nanoTime() + remainingNanos;
140
141      while (true) {
142        try {
143          return condition.await(remainingNanos, NANOSECONDS);
144        } catch (InterruptedException e) {
145          interrupted = true;
146          remainingNanos = end - System.nanoTime();
147        }
148      }
149    } finally {
150      if (interrupted) {
151        Thread.currentThread().interrupt();
152      }
153    }
154  }
155
156  /** Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly. */
157  @GwtIncompatible // concurrency
158  public static void joinUninterruptibly(Thread toJoin) {
159    boolean interrupted = false;
160    try {
161      while (true) {
162        try {
163          toJoin.join();
164          return;
165        } catch (InterruptedException e) {
166          interrupted = true;
167        }
168      }
169    } finally {
170      if (interrupted) {
171        Thread.currentThread().interrupt();
172      }
173    }
174  }
175
176  /**
177   * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)}
178   * uninterruptibly.
179   *
180   * @since 28.0
181   */
182  @GwtIncompatible // concurrency
183  @Beta
184  public static void joinUninterruptibly(Thread toJoin, Duration timeout) {
185    joinUninterruptibly(toJoin, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
186  }
187
188  /**
189   * Invokes {@code unit.}{@link TimeUnit#timedJoin(Thread, long) timedJoin(toJoin, timeout)}
190   * uninterruptibly.
191   */
192  @GwtIncompatible // concurrency
193  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
194  public static void joinUninterruptibly(Thread toJoin, long timeout, TimeUnit unit) {
195    Preconditions.checkNotNull(toJoin);
196    boolean interrupted = false;
197    try {
198      long remainingNanos = unit.toNanos(timeout);
199      long end = System.nanoTime() + remainingNanos;
200      while (true) {
201        try {
202          // TimeUnit.timedJoin() treats negative timeouts just like zero.
203          NANOSECONDS.timedJoin(toJoin, remainingNanos);
204          return;
205        } catch (InterruptedException e) {
206          interrupted = true;
207          remainingNanos = end - System.nanoTime();
208        }
209      }
210    } finally {
211      if (interrupted) {
212        Thread.currentThread().interrupt();
213      }
214    }
215  }
216
217  /**
218   * Invokes {@code future.}{@link Future#get() get()} uninterruptibly.
219   *
220   * <p>Similar methods:
221   *
222   * <ul>
223   *   <li>To retrieve a result from a {@code Future} that is already done, use {@link
224   *       Futures#getDone Futures.getDone}.
225   *   <li>To treat {@link InterruptedException} uniformly with other exceptions, use {@link
226   *       Futures#getChecked(Future, Class) Futures.getChecked}.
227   *   <li>To get uninterruptibility and remove checked exceptions, use {@link
228   *       Futures#getUnchecked}.
229   * </ul>
230   *
231   * @throws ExecutionException if the computation threw an exception
232   * @throws CancellationException if the computation was cancelled
233   */
234  @CanIgnoreReturnValue
235  public static <V> V getUninterruptibly(Future<V> future) 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  @Beta
274  public static <V> V getUninterruptibly(Future<V> future, Duration timeout)
275      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  public static <V> V getUninterruptibly(Future<V> future, long timeout, TimeUnit unit)
301      throws ExecutionException, TimeoutException {
302    boolean interrupted = false;
303    try {
304      long remainingNanos = unit.toNanos(timeout);
305      long end = System.nanoTime() + remainingNanos;
306
307      while (true) {
308        try {
309          // Future treats negative timeouts just like zero.
310          return future.get(remainingNanos, NANOSECONDS);
311        } catch (InterruptedException e) {
312          interrupted = true;
313          remainingNanos = end - System.nanoTime();
314        }
315      }
316    } finally {
317      if (interrupted) {
318        Thread.currentThread().interrupt();
319      }
320    }
321  }
322
323  /** Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly. */
324  @GwtIncompatible // concurrency
325  public static <E> E takeUninterruptibly(BlockingQueue<E> queue) {
326    boolean interrupted = false;
327    try {
328      while (true) {
329        try {
330          return queue.take();
331        } catch (InterruptedException e) {
332          interrupted = true;
333        }
334      }
335    } finally {
336      if (interrupted) {
337        Thread.currentThread().interrupt();
338      }
339    }
340  }
341
342  /**
343   * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)} uninterruptibly.
344   *
345   * @throws ClassCastException if the class of the specified element prevents it from being added
346   *     to the given queue
347   * @throws IllegalArgumentException if some property of the specified element prevents it from
348   *     being added to the given queue
349   */
350  @GwtIncompatible // concurrency
351  public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) {
352    boolean interrupted = false;
353    try {
354      while (true) {
355        try {
356          queue.put(element);
357          return;
358        } catch (InterruptedException e) {
359          interrupted = true;
360        }
361      }
362    } finally {
363      if (interrupted) {
364        Thread.currentThread().interrupt();
365      }
366    }
367  }
368
369  // TODO(user): Support Sleeper somehow (wrapper or interface method)?
370  /**
371   * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)} uninterruptibly.
372   *
373   * @since 28.0
374   */
375  @GwtIncompatible // concurrency
376  @Beta
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  @Beta
415  public static boolean tryAcquireUninterruptibly(Semaphore semaphore, Duration timeout) {
416    return tryAcquireUninterruptibly(semaphore, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
417  }
418
419  /**
420   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(1,
421   * timeout, unit)} uninterruptibly.
422   *
423   * @since 18.0
424   */
425  @GwtIncompatible // concurrency
426  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
427  public static boolean tryAcquireUninterruptibly(
428      Semaphore semaphore, long timeout, TimeUnit unit) {
429    return tryAcquireUninterruptibly(semaphore, 1, timeout, unit);
430  }
431
432  /**
433   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits,
434   * timeout, unit)} uninterruptibly.
435   *
436   * @since 28.0
437   */
438  @GwtIncompatible // concurrency
439  @Beta
440  public static boolean tryAcquireUninterruptibly(
441      Semaphore semaphore, int permits, Duration timeout) {
442    return tryAcquireUninterruptibly(
443        semaphore, permits, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
444  }
445
446  /**
447   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit) tryAcquire(permits,
448   * timeout, unit)} uninterruptibly.
449   *
450   * @since 18.0
451   */
452  @GwtIncompatible // concurrency
453  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
454  public static boolean tryAcquireUninterruptibly(
455      Semaphore semaphore, int permits, long timeout, TimeUnit unit) {
456    boolean interrupted = false;
457    try {
458      long remainingNanos = unit.toNanos(timeout);
459      long end = System.nanoTime() + remainingNanos;
460
461      while (true) {
462        try {
463          // Semaphore treats negative timeouts just like zero.
464          return semaphore.tryAcquire(permits, remainingNanos, NANOSECONDS);
465        } catch (InterruptedException e) {
466          interrupted = true;
467          remainingNanos = end - System.nanoTime();
468        }
469      }
470    } finally {
471      if (interrupted) {
472        Thread.currentThread().interrupt();
473      }
474    }
475  }
476
477  /**
478   * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)}
479   * uninterruptibly.
480   *
481   * @since 30.0
482   */
483  @GwtIncompatible // concurrency
484  @Beta
485  public static boolean tryLockUninterruptibly(Lock lock, Duration timeout) {
486    return tryLockUninterruptibly(lock, toNanosSaturated(timeout), TimeUnit.NANOSECONDS);
487  }
488
489  /**
490   * Invokes {@code lock.}{@link Lock#tryLock(long, TimeUnit) tryLock(timeout, unit)}
491   * uninterruptibly.
492   *
493   * @since 30.0
494   */
495  @GwtIncompatible // concurrency
496  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
497  public static boolean tryLockUninterruptibly(Lock lock, long timeout, TimeUnit unit) {
498    boolean interrupted = false;
499    try {
500      long remainingNanos = unit.toNanos(timeout);
501      long end = System.nanoTime() + remainingNanos;
502
503      while (true) {
504        try {
505          return lock.tryLock(remainingNanos, NANOSECONDS);
506        } catch (InterruptedException e) {
507          interrupted = true;
508          remainingNanos = end - System.nanoTime();
509        }
510      }
511    } finally {
512      if (interrupted) {
513        Thread.currentThread().interrupt();
514      }
515    }
516  }
517
518  /**
519   * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit)
520   * awaitTermination(long, TimeUnit)} uninterruptibly with no timeout.
521   *
522   * @since 30.0
523   */
524  @Beta
525  @GwtIncompatible // concurrency
526  public static void awaitTerminationUninterruptibly(ExecutorService executor) {
527    // TODO(cpovirk): We could optimize this to avoid calling nanoTime() at all.
528    verify(awaitTerminationUninterruptibly(executor, Long.MAX_VALUE, NANOSECONDS));
529  }
530
531  /**
532   * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit)
533   * awaitTermination(long, TimeUnit)} uninterruptibly.
534   *
535   * @since 30.0
536   */
537  @Beta
538  @GwtIncompatible // concurrency
539  public static boolean awaitTerminationUninterruptibly(
540      ExecutorService executor, Duration timeout) {
541    return awaitTerminationUninterruptibly(executor, toNanosSaturated(timeout), NANOSECONDS);
542  }
543
544  /**
545   * Invokes {@code executor.}{@link ExecutorService#awaitTermination(long, TimeUnit)
546   * awaitTermination(long, TimeUnit)} uninterruptibly.
547   *
548   * @since 30.0
549   */
550  @Beta
551  @GwtIncompatible // concurrency
552  @SuppressWarnings("GoodTime")
553  public static boolean awaitTerminationUninterruptibly(
554      ExecutorService executor, long timeout, TimeUnit unit) {
555    boolean interrupted = false;
556    try {
557      long remainingNanos = unit.toNanos(timeout);
558      long end = System.nanoTime() + remainingNanos;
559
560      while (true) {
561        try {
562          return executor.awaitTermination(remainingNanos, NANOSECONDS);
563        } catch (InterruptedException e) {
564          interrupted = true;
565          remainingNanos = end - System.nanoTime();
566        }
567      }
568    } finally {
569      if (interrupted) {
570        Thread.currentThread().interrupt();
571      }
572    }
573  }
574
575  // TODO(user): Add support for waitUninterruptibly.
576
577  private Uninterruptibles() {}
578}