001/*
002 * Copyright (C) 2018 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.Preconditions.checkNotNull;
018import static com.google.common.base.Preconditions.checkState;
019import static com.google.common.util.concurrent.ExecutionSequencer.RunningState.NOT_RUN;
020import static com.google.common.util.concurrent.ExecutionSequencer.RunningState.STARTED;
021import static com.google.common.util.concurrent.ExecutionSequencer.RunningState.WILL_NOT_RUN;
022import static com.google.common.util.concurrent.Futures.immediateCancelledFuture;
023import static com.google.common.util.concurrent.Futures.immediateFuture;
024import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
025import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
026import static java.util.Objects.requireNonNull;
027
028import com.google.common.annotations.GwtIncompatible;
029import com.google.common.annotations.J2ktIncompatible;
030import com.google.errorprone.annotations.concurrent.LazyInit;
031import java.util.concurrent.Callable;
032import java.util.concurrent.Executor;
033import java.util.concurrent.Future;
034import java.util.concurrent.RejectedExecutionException;
035import java.util.concurrent.atomic.AtomicReference;
036import org.jspecify.annotations.Nullable;
037
038/**
039 * Serializes execution of tasks, somewhat like an "asynchronous {@code synchronized} block." Each
040 * {@linkplain #submit enqueued} callable will not be submitted to its associated executor until the
041 * previous callable has returned -- and, if the previous callable was an {@link AsyncCallable}, not
042 * until the {@code Future} it returned is {@linkplain Future#isDone done} (successful, failed, or
043 * cancelled).
044 *
045 * <p>This class serializes execution of <i>submitted</i> tasks but not any <i>listeners</i> of
046 * those tasks.
047 *
048 * <p>Submitted tasks have a happens-before order as defined in the Java Language Specification.
049 * Tasks execute with the same happens-before order that the function calls to {@link #submit} and
050 * {@link #submitAsync} that submitted those tasks had.
051 *
052 * <p>This class has limited support for cancellation and other "early completions":
053 *
054 * <ul>
055 *   <li>While calls to {@code submit} and {@code submitAsync} return a {@code Future} that can be
056 *       cancelled, cancellation never propagates to a task that has started to run -- neither to
057 *       the callable itself nor to any {@code Future} returned by an {@code AsyncCallable}.
058 *       (However, cancellation can prevent an <i>unstarted</i> task from running.) Therefore, the
059 *       next task will wait for any running callable (or pending {@code Future} returned by an
060 *       {@code AsyncCallable}) to complete, without interrupting it (and without calling {@code
061 *       cancel} on the {@code Future}). So beware: <i>Even if you cancel every preceding {@code
062 *       Future} returned by this class, the next task may still have to wait.</i>.
063 *   <li>Once an {@code AsyncCallable} returns a {@code Future}, this class considers that task to
064 *       be "done" as soon as <i>that</i> {@code Future} completes in any way. Notably, a {@code
065 *       Future} is "completed" even if it is cancelled while its underlying work continues on a
066 *       thread, an RPC, etc. The {@code Future} is also "completed" if it fails "early" -- for
067 *       example, if the deadline expires on a {@code Future} returned from {@link
068 *       Futures#withTimeout} while the {@code Future} it wraps continues its underlying work. So
069 *       beware: <i>Your {@code AsyncCallable} should not complete its {@code Future} until it is
070 *       safe for the next task to start.</i>
071 * </ul>
072 *
073 * <p>This class is similar to {@link MoreExecutors#newSequentialExecutor}. This class is different
074 * in a few ways:
075 *
076 * <ul>
077 *   <li>Each task may be associated with a different executor.
078 *   <li>Tasks may be of type {@code AsyncCallable}.
079 *   <li>Running tasks <i>cannot</i> be interrupted. (Note that {@code newSequentialExecutor} does
080 *       not return {@code Future} objects, so it doesn't support interruption directly, either.
081 *       However, utilities that <i>use</i> that executor have the ability to interrupt tasks
082 *       running on it. This class, by contrast, does not expose an {@code Executor} API.)
083 * </ul>
084 *
085 * <p>If you don't need the features of this class, you may prefer {@code newSequentialExecutor} for
086 * its simplicity and ability to accommodate interruption.
087 *
088 * @since 26.0
089 */
090@J2ktIncompatible
091@GwtIncompatible
092public final class ExecutionSequencer {
093
094  private ExecutionSequencer() {}
095
096  /** Creates a new instance. */
097  public static ExecutionSequencer create() {
098    return new ExecutionSequencer();
099  }
100
101  /** This reference acts as a pointer tracking the head of a linked list of ListenableFutures. */
102  private final AtomicReference<ListenableFuture<@Nullable Void>> ref =
103      new AtomicReference<>(immediateVoidFuture());
104
105  @LazyInit private ThreadConfinedTaskQueue latestTaskQueue = new ThreadConfinedTaskQueue();
106
107  /**
108   * This object is unsafely published, but avoids problematic races by relying exclusively on the
109   * identity equality of its Thread field so that the task field is only accessed by a single
110   * thread.
111   */
112  private static final class ThreadConfinedTaskQueue {
113    /**
114     * This field is only used for identity comparisons with the current thread. Field assignments
115     * are atomic, but do not provide happens-before ordering; however:
116     *
117     * <ul>
118     *   <li>If this field's value == currentThread, we know that it's up to date, because write
119     *       operations in a thread always happen-before subsequent read operations in the same
120     *       thread
121     *   <li>If this field's value == null because of unsafe publication, we know that it isn't the
122     *       object associated with our thread, because if it was the publication wouldn't have been
123     *       unsafe and we'd have seen our thread as the value. This state is also why a new
124     *       ThreadConfinedTaskQueue object must be created for each inline execution, because
125     *       observing a null thread does not mean the object is safe to reuse.
126     *   <li>If this field's value is some other thread object, we know that it's not our thread.
127     *   <li>If this field's value == null because it originally belonged to another thread and that
128     *       thread cleared it, we still know that it's not associated with our thread
129     *   <li>If this field's value == null because it was associated with our thread and was
130     *       cleared, we know that we're not executing inline any more
131     * </ul>
132     *
133     * All the states where thread != currentThread are identical for our purposes, and so even
134     * though it's racy, we don't care which of those values we get, so no need to synchronize.
135     */
136    @LazyInit @Nullable Thread thread;
137
138    /** Only used by the thread associated with this object */
139    @Nullable TrustedListenableFutureTask<?> nextTask;
140
141    /** Only used by the thread associated with this object */
142    @Nullable Executor nextExecutor;
143  }
144
145  /**
146   * Enqueues a task to run when the previous task (if any) completes.
147   *
148   * <p>Cancellation does not propagate from the output future to a callable that has begun to
149   * execute, but if the output future is cancelled before {@link Callable#call()} is invoked,
150   * {@link Callable#call()} will not be invoked.
151   */
152  public <T extends @Nullable Object> ListenableFuture<T> submit(
153      Callable<T> callable, Executor executor) {
154    checkNotNull(callable);
155    checkNotNull(executor);
156    return submitAsync(
157        new AsyncCallable<T>() {
158          @Override
159          public ListenableFuture<T> call() throws Exception {
160            return immediateFuture(callable.call());
161          }
162
163          @Override
164          public String toString() {
165            return callable.toString();
166          }
167        },
168        executor);
169  }
170
171  /**
172   * Enqueues a task to run when the previous task (if any) completes.
173   *
174   * <p>Cancellation does not propagate from the output future to the future returned from {@code
175   * callable} or a callable that has begun to execute, but if the output future is cancelled before
176   * {@link AsyncCallable#call()} is invoked, {@link AsyncCallable#call()} will not be invoked.
177   */
178  public <T extends @Nullable Object> ListenableFuture<T> submitAsync(
179      AsyncCallable<T> callable, Executor executor) {
180    checkNotNull(callable);
181    checkNotNull(executor);
182    TaskNonReentrantExecutor taskExecutor = new TaskNonReentrantExecutor(executor, this);
183    AsyncCallable<T> task =
184        new AsyncCallable<T>() {
185          @Override
186          public ListenableFuture<T> call() throws Exception {
187            if (!taskExecutor.trySetStarted()) {
188              return immediateCancelledFuture();
189            }
190            return callable.call();
191          }
192
193          @Override
194          public String toString() {
195            return callable.toString();
196          }
197        };
198    /*
199     * Four futures are at play here:
200     * taskFuture is the future tracking the result of the callable.
201     * newFuture is a future that completes after this and all prior tasks are done.
202     * oldFuture is the previous task's newFuture.
203     * outputFuture is the future we return to the caller, a nonCancellationPropagating taskFuture.
204     *
205     * newFuture is guaranteed to only complete once all tasks previously submitted to this instance
206     * have completed - namely after oldFuture is done, and taskFuture has either completed or been
207     * cancelled before the callable started execution.
208     */
209    SettableFuture<@Nullable Void> newFuture = SettableFuture.create();
210
211    ListenableFuture<@Nullable Void> oldFuture = ref.getAndSet(newFuture);
212
213    // Invoke our task once the previous future completes.
214    TrustedListenableFutureTask<T> taskFuture = TrustedListenableFutureTask.create(task);
215    oldFuture.addListener(taskFuture, taskExecutor);
216
217    ListenableFuture<T> outputFuture = Futures.nonCancellationPropagating(taskFuture);
218
219    // newFuture's lifetime is determined by taskFuture, which can't complete before oldFuture
220    // unless taskFuture is cancelled, in which case it falls back to oldFuture. This ensures that
221    // if the future we return is cancelled, we don't begin execution of the next task until after
222    // oldFuture completes.
223    Runnable listener =
224        () -> {
225          if (taskFuture.isDone()) {
226            // Since the value of oldFuture can only ever be immediateVoidFuture() or setFuture of a
227            // future that eventually came from immediateVoidFuture(), this doesn't leak throwables
228            // or completion values.
229            newFuture.setFutureInternal(oldFuture);
230          } else if (outputFuture.isCancelled() && taskExecutor.trySetCancelled()) {
231            // If this CAS succeeds, we know that the provided callable will never be invoked,
232            // so when oldFuture completes it is safe to allow the next submitted task to
233            // proceed. Doing this immediately here lets the next task run without waiting for
234            // the cancelled task's executor to run the noop AsyncCallable.
235            //
236            // ---
237            //
238            // If the CAS fails, the provided callable already started running (or it is about
239            // to). Our contract promises:
240            //
241            // 1. not to execute a new callable until the old one has returned
242            //
243            // If we were to cancel taskFuture, that would let the next task start while the old
244            // one is still running.
245            //
246            // Now, maybe we could tweak our implementation to not start the next task until the
247            // callable actually completes. (We could detect completion in our wrapper
248            // `AsyncCallable task`.) However, our contract also promises:
249            //
250            // 2. not to cancel any Future the user returned from an AsyncCallable
251            //
252            // We promise this because, once we cancel that Future, we would no longer be able to
253            // tell when any underlying work it is doing is done. Thus, we might start a new task
254            // while that underlying work is still running.
255            //
256            // So that is why we cancel only in the case of CAS success.
257            taskFuture.cancel(false);
258          }
259        };
260    // Adding the listener to both futures guarantees that newFuture will always be set. Adding to
261    // taskFuture guarantees completion if the callable is invoked, and adding to outputFuture
262    // propagates cancellation if the callable has not yet been invoked.
263    outputFuture.addListener(listener, directExecutor());
264    taskFuture.addListener(listener, directExecutor());
265
266    return outputFuture;
267  }
268
269  enum RunningState {
270    NOT_RUN,
271    WILL_NOT_RUN,
272    STARTED,
273  }
274
275  /**
276   * This class helps avoid a StackOverflowError when large numbers of tasks are submitted with
277   * {@link MoreExecutors#directExecutor}. Normally, when the first future completes, all the other
278   * tasks would be called recursively. Here, we detect that the delegate executor is executing
279   * inline, and maintain a queue to dispatch tasks iteratively. There is one instance of this class
280   * per call to submit() or submitAsync(), and each instance supports only one call to execute().
281   *
282   * <p>This class would certainly be simpler and easier to reason about if it were built with
283   * ThreadLocal; however, ThreadLocal is not well optimized for the case where the ThreadLocal is
284   * non-static, and is initialized/removed frequently - this causes churn in the Thread specific
285   * hashmaps. Using a static ThreadLocal to avoid that overhead would mean that different
286   * ExecutionSequencer objects interfere with each other, which would be undesirable, in addition
287   * to increasing the memory footprint of every thread that interacted with it. In order to release
288   * entries in thread-specific maps when the ThreadLocal object itself is no longer referenced,
289   * ThreadLocal is usually implemented with a WeakReference, which can have negative performance
290   * properties; for example, calling WeakReference.get() on Android will block during an
291   * otherwise-concurrent GC cycle.
292   */
293  private static final class TaskNonReentrantExecutor extends AtomicReference<RunningState>
294      implements Executor, Runnable {
295
296    /**
297     * Used to update and read the latestTaskQueue field. Set to null once the runnable has been run
298     * or queued.
299     */
300    @Nullable ExecutionSequencer sequencer;
301
302    /**
303     * Executor the task was set to run on. Set to null when the task has been queued, run, or
304     * cancelled.
305     */
306    @Nullable Executor delegate;
307
308    /**
309     * Set before calling delegate.execute(); set to null once run, so that it can be GCed; this
310     * object may live on after, if submitAsync returns an incomplete future.
311     */
312    @Nullable TrustedListenableFutureTask<?> task;
313
314    /** Thread that called execute(). Set in execute, cleared when delegate.execute() returns. */
315    @LazyInit @Nullable Thread submitting;
316
317    private TaskNonReentrantExecutor(Executor delegate, ExecutionSequencer sequencer) {
318      super(NOT_RUN);
319      this.delegate = delegate;
320      this.sequencer = sequencer;
321    }
322
323    /*
324     * We compare two Thread instances with ==: For concurrency correctness, we need to know whether
325     * they are actually the same thread, even if they are instances of some user subclass that
326     * overrides Thread.equals.
327     */
328    @SuppressWarnings("ReferenceEquality")
329    @Override
330    public void execute(Runnable task) {
331      // If this operation was successfully cancelled already, calling the runnable will be a noop.
332      // This also avoids a race where if outputFuture is cancelled, it will call taskFuture.cancel,
333      // which will call newFuture.setFuture(oldFuture), to allow the next task in the queue to run
334      // without waiting for the user's executor to run our submitted Runnable. However, this can
335      // interact poorly with the reentrancy-avoiding behavior of this executor - when the operation
336      // before the cancelled future completes, it will synchronously complete both the newFuture
337      // from the cancelled operation and its own. This can cause one runnable to queue two tasks,
338      // breaking the invariant this method relies on to iteratively run the next task after the
339      // previous one completes.
340      if (get() == RunningState.WILL_NOT_RUN) {
341        delegate = null;
342        sequencer = null;
343        return;
344      }
345      submitting = Thread.currentThread();
346      TrustedListenableFutureTask<?> trustedFutureTask = (TrustedListenableFutureTask<?>) task;
347
348      try {
349        /*
350         * requireNonNull is safe because we don't null out `sequencer` except:
351         *
352         * - above, where we return (in which case we never get here)
353         *
354         * - in `run`, which can't run until this Runnable is submitted to an executor, which
355         *   doesn't happen until below. (And this Executor -- yes, the object is both a Runnable
356         *   and an Executor -- is used for only a single `execute` call.)
357         */
358        ThreadConfinedTaskQueue submittingTaskQueue = requireNonNull(sequencer).latestTaskQueue;
359        if (submittingTaskQueue.thread == submitting) {
360          sequencer = null;
361          // Submit from inside a reentrant submit. We don't know if this one will be reentrant (and
362          // can't know without submitting something to the executor) so queue to run iteratively.
363          // Task must be null, since each execution on this executor can only produce one more
364          // execution.
365          checkState(submittingTaskQueue.nextTask == null);
366          submittingTaskQueue.nextTask = trustedFutureTask;
367          // requireNonNull(delegate) is safe for reasons similar to requireNonNull(sequencer).
368          submittingTaskQueue.nextExecutor = requireNonNull(delegate);
369          delegate = null;
370        } else {
371          // requireNonNull(delegate) is safe for reasons similar to requireNonNull(sequencer).
372          Executor localDelegate = requireNonNull(delegate);
373          delegate = null;
374          this.task = trustedFutureTask;
375          try {
376            localDelegate.execute(this);
377          } catch (RejectedExecutionException e) {
378            /*
379             * `trySetCancelled` is irrelevant when we know the task won't run and when it is
380             * harmless for our `setExceptionInternal` call here to race with a user call to
381             * `cancel`. But we do it anyway in case we want to use the `RunningState` for another
382             * purpose someday.
383             */
384            boolean unused = trySetCancelled();
385            trustedFutureTask.setExceptionInternal(e);
386            /*
387             * We don't need to clear `this.task` because no one will have a
388             * reference to `this` after we return.
389             */
390          }
391        }
392      } finally {
393        // Important to null this out here - if we did *not* execute inline, we might still
394        // run() on the same thread that called execute() - such as in a thread pool, and think
395        // that it was happening inline. As a side benefit, avoids holding on to the Thread object
396        // longer than necessary.
397        submitting = null;
398      }
399    }
400
401    @SuppressWarnings({
402      "ShortCircuitBoolean",
403      /*
404       * We compare two Thread instances with ==: For concurrency correctness, we need to know
405       * whether they are actually the same thread, even if they are instances of some user subclass
406       * that overrides Thread.equals.
407       */
408      "ReferenceEquality",
409    })
410    @Override
411    public void run() {
412      Thread currentThread = Thread.currentThread();
413      if (currentThread != submitting) {
414        /*
415         * requireNonNull is safe because we set `task` before submitting this Runnable to an
416         * Executor, and we don't null it out until here.
417         */
418        Runnable localTask = requireNonNull(task);
419        task = null;
420        localTask.run();
421        return;
422      }
423      // Executor called reentrantly! Make sure that further calls don't overflow stack. Further
424      // reentrant calls will see that their current thread is the same as the one set in
425      // latestTaskQueue, and queue rather than calling execute() directly.
426      ThreadConfinedTaskQueue executingTaskQueue = new ThreadConfinedTaskQueue();
427      executingTaskQueue.thread = currentThread;
428      /*
429       * requireNonNull is safe because we don't null out `sequencer` except:
430       *
431       * - after the requireNonNull call below. (And this object has its Runnable.run override
432       *   called only once, just as it has its Executor.execute override called only once.)
433       *
434       * - if we return immediately from `execute` (in which case we never get here)
435       *
436       * - in the "reentrant submit" case of `execute` (in which case we must have started running a
437       *   user task -- which means that we already got past this code (or else we exited early
438       *   above))
439       */
440      // Unconditionally set; there is no risk of throwing away a queued task from another thread,
441      // because in order for the current task to run on this executor the previous task must have
442      // already started execution. Because each task on a TaskNonReentrantExecutor can only produce
443      // one execute() call to another instance from the same ExecutionSequencer, we know by
444      // induction that the task that launched this one must not have added any other runnables to
445      // that thread's queue, and thus we cannot be replacing a TaskAndThread object that would
446      // otherwise have another task queued on to it. Note the exception to this, cancellation, is
447      // specially handled in execute() - execute() calls triggered by cancellation are no-ops, and
448      // thus don't count.
449      requireNonNull(sequencer).latestTaskQueue = executingTaskQueue;
450      sequencer = null;
451      try {
452        // requireNonNull is safe, as discussed above.
453        Runnable localTask = requireNonNull(task);
454        task = null;
455        localTask.run();
456        // Now check if our task attempted to reentrantly execute the next task.
457        TrustedListenableFutureTask<?> queuedTask;
458        Executor queuedExecutor;
459        /*
460         * We used to use a non-short-circuit operator here as a nano-optimization, but it caused
461         * trouble for some transpiled compilation.
462         */
463        while ((queuedTask = executingTaskQueue.nextTask) != null
464            && (queuedExecutor = executingTaskQueue.nextExecutor) != null) {
465          executingTaskQueue.nextTask = null;
466          executingTaskQueue.nextExecutor = null;
467          try {
468            queuedExecutor.execute(queuedTask);
469          } catch (RejectedExecutionException e) {
470            queuedTask.setExceptionInternal(e);
471          }
472        }
473      } finally {
474        // Null out the thread field, so that we don't leak a reference to Thread, and so that
475        // future `thread == currentThread()` calls from this thread don't incorrectly queue instead
476        // of executing. Don't null out the latestTaskQueue field, because the work done here
477        // may have scheduled more operations on another thread, and if those operations then
478        // trigger reentrant calls that thread will have updated the latestTaskQueue field, and
479        // we'd be interfering with their operation.
480        executingTaskQueue.thread = null;
481      }
482    }
483
484    private boolean trySetStarted() {
485      return compareAndSet(NOT_RUN, STARTED);
486    }
487
488    private boolean trySetCancelled() {
489      return compareAndSet(NOT_RUN, WILL_NOT_RUN);
490    }
491  }
492}