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