mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Remove unused Bolts code from runtime (#44779)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44779 We forked a copy of Bolts when we open-sourced bridgeless, but it contains many features we don't require, since we only use Tasks to orchestrate the bridgeless startup path. The only meaningful change I made is removing the fallback on stack overflow from the immediate executor, which is not something we expect to hit during startup, and would be better surfaced as a StackOverflowException. Changelog: [Internal] Reviewed By: cortinico Differential Revision: D58087989 fbshipit-source-id: a4908723a04bf47fdc38d91bf47df928b91456f5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
a9bcc0d46c
commit
95c721646d
@@ -3835,54 +3835,20 @@ public final class com/facebook/react/runtime/hermes/HermesInstance : com/facebo
|
||||
public final class com/facebook/react/runtime/hermes/HermesInstance$Companion {
|
||||
}
|
||||
|
||||
public class com/facebook/react/runtime/internal/bolts/CancellationToken {
|
||||
public fun isCancellationRequested ()Z
|
||||
public fun register (Ljava/lang/Runnable;)Lcom/facebook/react/runtime/internal/bolts/CancellationTokenRegistration;
|
||||
public fun throwIfCancellationRequested ()V
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public class com/facebook/react/runtime/internal/bolts/CancellationTokenSource : java/io/Closeable {
|
||||
public fun <init> ()V
|
||||
public fun cancel ()V
|
||||
public fun cancelAfter (J)V
|
||||
public fun close ()V
|
||||
public fun getToken ()Lcom/facebook/react/runtime/internal/bolts/CancellationToken;
|
||||
public fun isCancellationRequested ()Z
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/runtime/internal/bolts/Continuation {
|
||||
public abstract fun then (Lcom/facebook/react/runtime/internal/bolts/Task;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public class com/facebook/react/runtime/internal/bolts/Task : com/facebook/react/interfaces/TaskInterface {
|
||||
public static final field BACKGROUND_EXECUTOR Ljava/util/concurrent/ExecutorService;
|
||||
public static final field UI_THREAD_CONDITIONAL_SYNC_EXECUTOR Ljava/util/concurrent/Executor;
|
||||
public static final field UI_THREAD_EXECUTOR Ljava/util/concurrent/Executor;
|
||||
public static fun call (Ljava/util/concurrent/Callable;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun call (Ljava/util/concurrent/Callable;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun call (Ljava/util/concurrent/Callable;Ljava/util/concurrent/Executor;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun call (Ljava/util/concurrent/Callable;Ljava/util/concurrent/Executor;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun callInBackground (Ljava/util/concurrent/Callable;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun callInBackground (Ljava/util/concurrent/Callable;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun cancelled ()Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun cast ()Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWhile (Ljava/util/concurrent/Callable;Lcom/facebook/react/runtime/internal/bolts/Continuation;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWhile (Ljava/util/concurrent/Callable;Lcom/facebook/react/runtime/internal/bolts/Continuation;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWhile (Ljava/util/concurrent/Callable;Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWhile (Ljava/util/concurrent/Callable;Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWith (Lcom/facebook/react/runtime/internal/bolts/Continuation;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWith (Lcom/facebook/react/runtime/internal/bolts/Continuation;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWith (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWith (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWithTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWithTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWithTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun continueWithTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun create ()Lcom/facebook/react/runtime/internal/bolts/TaskCompletionSource;
|
||||
public static fun delay (J)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun delay (JLcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun forError (Ljava/lang/Exception;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun forResult (Ljava/lang/Object;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun getError ()Ljava/lang/Exception;
|
||||
@@ -3893,20 +3859,12 @@ public class com/facebook/react/runtime/internal/bolts/Task : com/facebook/react
|
||||
public fun isFaulted ()Z
|
||||
public fun makeVoid ()Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccess (Lcom/facebook/react/runtime/internal/bolts/Continuation;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccess (Lcom/facebook/react/runtime/internal/bolts/Continuation;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccess (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccess (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccessTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccessTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccessTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public fun onSuccessTask (Lcom/facebook/react/runtime/internal/bolts/Continuation;Ljava/util/concurrent/Executor;Lcom/facebook/react/runtime/internal/bolts/CancellationToken;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun setUnobservedExceptionHandler (Lcom/facebook/react/runtime/internal/bolts/Task$UnobservedExceptionHandler;)V
|
||||
public fun waitForCompletion ()V
|
||||
public fun waitForCompletion (JLjava/util/concurrent/TimeUnit;)Z
|
||||
public static fun whenAll (Ljava/util/Collection;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun whenAllResult (Ljava/util/Collection;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun whenAny (Ljava/util/Collection;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
public static fun whenAnyResult (Ljava/util/Collection;)Lcom/facebook/react/runtime/internal/bolts/Task;
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/runtime/internal/bolts/Task$UnobservedExceptionHandler {
|
||||
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime;
|
||||
|
||||
import com.facebook.react.runtime.internal.bolts.CancellationTokenSource;
|
||||
import com.facebook.react.runtime.internal.bolts.Task;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* This class is a {@link Future} that holds an instance of {@link Task}. The implementation of this
|
||||
* class delegates its behavior on the held task, following the {@link Future} interface defined in
|
||||
* {@link "https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html"}
|
||||
*
|
||||
* @param <T> The type of the result of the task.
|
||||
*/
|
||||
class BoltsFutureTask<T> implements Future<T> {
|
||||
private final Task<T> mTask;
|
||||
private boolean isTaskCancelled = false;
|
||||
private final CancellationTokenSource mCancellationTokenSource;
|
||||
|
||||
private BoltsFutureTask(Task<T> task) {
|
||||
this(task, new CancellationTokenSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link BoltsFutureTask} for a task that handles cancellation. For
|
||||
* more details about bolts cancellation refer to {@link
|
||||
* "https://github.com/BoltsFramework/Bolts-Android#cancelling-tasks"}
|
||||
*
|
||||
* @param task {@link Task} to be held by BoltsFutureTask
|
||||
* @param cancellationTokenSource {@link CancellationTokenSource} object that is used by the task
|
||||
* received by parameter to handle cancellation.
|
||||
*/
|
||||
private BoltsFutureTask(Task<T> task, CancellationTokenSource cancellationTokenSource) {
|
||||
mTask = task;
|
||||
mCancellationTokenSource = cancellationTokenSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
try {
|
||||
if (!isDone()) {
|
||||
mCancellationTokenSource.cancel();
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
isTaskCancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isTaskCancelled || mTask.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return isTaskCancelled || mTask.isCancelled() || mTask.isFaulted() || mTask.isCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws ExecutionException, InterruptedException {
|
||||
mTask.waitForCompletion();
|
||||
return getResult(mTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
if (mTask.waitForCompletion(timeout, unit)) {
|
||||
return getResult(mTask);
|
||||
}
|
||||
throw new TimeoutException();
|
||||
}
|
||||
|
||||
private T getResult(Task<T> task) throws ExecutionException {
|
||||
if (task.isFaulted()) {
|
||||
throw new ExecutionException("", new Throwable());
|
||||
} else if (task.isCancelled()) {
|
||||
throw new CancellationException("");
|
||||
}
|
||||
return task.getResult();
|
||||
}
|
||||
}
|
||||
+16
-20
@@ -8,7 +8,6 @@
|
||||
package com.facebook.react.runtime;
|
||||
|
||||
import static com.facebook.infer.annotation.Assertions.assertNotNull;
|
||||
import static com.facebook.infer.annotation.Assertions.nullsafeFIXME;
|
||||
import static com.facebook.infer.annotation.ThreadConfined.UI;
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
@@ -63,7 +62,6 @@ import com.facebook.react.interfaces.fabric.ReactSurface;
|
||||
import com.facebook.react.modules.appearance.AppearanceModule;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.runtime.internal.bolts.Continuation;
|
||||
import com.facebook.react.runtime.internal.bolts.Task;
|
||||
import com.facebook.react.runtime.internal.bolts.TaskCompletionSource;
|
||||
import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder;
|
||||
@@ -117,10 +115,7 @@ public class ReactHostImpl implements ReactHost {
|
||||
Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
private final BridgelessAtomicRef<Task<ReactInstance>> mReactInstanceTaskRef =
|
||||
new BridgelessAtomicRef<>(
|
||||
Task.forResult(
|
||||
nullsafeFIXME(
|
||||
null, "forResult parameter supports null, but is not annotated as @Nullable")));
|
||||
new BridgelessAtomicRef<>(Task.forResult(null));
|
||||
|
||||
private final BridgelessAtomicRef<BridgelessReactContext> mBridgelessReactContextRef =
|
||||
new BridgelessAtomicRef<>();
|
||||
@@ -912,6 +907,7 @@ public class ReactHostImpl implements ReactHost {
|
||||
TAG, new ReactNoCrashSoftException(method + ": " + message));
|
||||
}
|
||||
|
||||
/** Schedule work on a ReactInstance that is already created. */
|
||||
private Task<Boolean> callWithExistingReactInstance(
|
||||
final String callingMethod, final VeniceThenable<ReactInstance> continuation) {
|
||||
final String method = "callWithExistingReactInstance(" + callingMethod + ")";
|
||||
@@ -922,7 +918,7 @@ public class ReactHostImpl implements ReactHost {
|
||||
task -> {
|
||||
final ReactInstance reactInstance = task.getResult();
|
||||
if (reactInstance == null) {
|
||||
raiseSoftException(method, "Execute: ReactInstance null. Dropping work.");
|
||||
raiseSoftException(method, "Execute: reactInstance is null. Dropping work.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -932,23 +928,23 @@ public class ReactHostImpl implements ReactHost {
|
||||
mBGExecutor);
|
||||
}
|
||||
|
||||
/** Create a ReactInstance if it doesn't exist already, and schedule work on it. */
|
||||
private Task<Void> callAfterGetOrCreateReactInstance(
|
||||
final String callingMethod, final VeniceThenable<ReactInstance> runnable) {
|
||||
final String method = "callAfterGetOrCreateReactInstance(" + callingMethod + ")";
|
||||
|
||||
return getOrCreateReactInstance()
|
||||
.onSuccess(
|
||||
(Continuation<ReactInstance, Void>)
|
||||
task -> {
|
||||
final ReactInstance reactInstance = task.getResult();
|
||||
if (reactInstance == null) {
|
||||
raiseSoftException(method, "Execute: ReactInstance is null");
|
||||
return null;
|
||||
}
|
||||
task -> {
|
||||
final ReactInstance reactInstance = task.getResult();
|
||||
if (reactInstance == null) {
|
||||
raiseSoftException(method, "Execute: reactInstance is null. Dropping work.");
|
||||
return null;
|
||||
}
|
||||
|
||||
runnable.then(reactInstance);
|
||||
return null;
|
||||
},
|
||||
runnable.then(reactInstance);
|
||||
return null;
|
||||
},
|
||||
mBGExecutor)
|
||||
.continueWith(
|
||||
task -> {
|
||||
@@ -1253,7 +1249,7 @@ public class ReactHostImpl implements ReactHost {
|
||||
ReactInstance unwrap(Task<ReactInstance> task, String stage);
|
||||
}
|
||||
|
||||
private ReactInstanceTaskUnwrapper createReactInstanceUnwraper(
|
||||
private ReactInstanceTaskUnwrapper createReactInstanceUnwrapper(
|
||||
String tag, String method, String reason) {
|
||||
|
||||
return (task, stage) -> {
|
||||
@@ -1321,7 +1317,7 @@ public class ReactHostImpl implements ReactHost {
|
||||
raiseSoftException(method, reason);
|
||||
|
||||
ReactInstanceTaskUnwrapper reactInstanceTaskUnwrapper =
|
||||
createReactInstanceUnwraper("Reload", method, reason);
|
||||
createReactInstanceUnwrapper("Reload", method, reason);
|
||||
|
||||
if (mReloadTask == null) {
|
||||
mReloadTask =
|
||||
@@ -1497,7 +1493,7 @@ public class ReactHostImpl implements ReactHost {
|
||||
raiseSoftException(method, reason, ex);
|
||||
|
||||
ReactInstanceTaskUnwrapper reactInstanceTaskUnwrapper =
|
||||
createReactInstanceUnwraper("Destroy", method, reason);
|
||||
createReactInstanceUnwrapper("Destroy", method, reason);
|
||||
|
||||
if (mDestroyTask == null) {
|
||||
mDestroyTask =
|
||||
|
||||
+18
-3
@@ -9,7 +9,7 @@ package com.facebook.react.runtime
|
||||
|
||||
import com.facebook.jni.HybridData
|
||||
import com.facebook.proguard.annotations.DoNotStripAny
|
||||
import com.facebook.react.runtime.internal.bolts.Task
|
||||
import com.facebook.react.bridge.UiThreadUtil
|
||||
import com.facebook.soloader.SoLoader
|
||||
import java.io.Closeable
|
||||
import java.util.concurrent.Executor
|
||||
@@ -19,8 +19,7 @@ internal class ReactHostInspectorTarget(private val reactHostImpl: ReactHostImpl
|
||||
// fbjni looks for the exact name "mHybridData":
|
||||
// https://github.com/facebookincubator/fbjni/blob/5587a7fd2b191656be9391a3832ce04c034009a5/cxx/fbjni/detail/Hybrid.h#L310
|
||||
@Suppress("NoHungarianNotation")
|
||||
private val mHybridData: HybridData =
|
||||
initHybrid(reactHostImpl, Task.UI_THREAD_CONDITIONAL_SYNC_EXECUTOR)
|
||||
private val mHybridData: HybridData = initHybrid(reactHostImpl, UIThreadConditionalSyncExecutor())
|
||||
|
||||
private external fun initHybrid(reactHostImpl: ReactHostImpl, executor: Executor): HybridData
|
||||
|
||||
@@ -39,4 +38,20 @@ internal class ReactHostInspectorTarget(private val reactHostImpl: ReactHostImpl
|
||||
SoLoader.loadLibrary("rninstance")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An [java.util.concurrent.Executor] that runs tasks on the UI thread (immediately if already on
|
||||
* that thread).
|
||||
*/
|
||||
private class UIThreadConditionalSyncExecutor : Executor {
|
||||
override fun execute(command: Runnable) {
|
||||
if (UiThreadUtil.isOnUiThread()) {
|
||||
// If we're already on the main thread, execute the command immediately
|
||||
command.run()
|
||||
} else {
|
||||
// Otherwise, post it on the main thread handler
|
||||
UiThreadUtil.runOnUiThread(command)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Aggregates multiple {@code Throwable}s that may be thrown in the process of a task's execution.
|
||||
*
|
||||
* @see Task#whenAll(java.util.Collection)
|
||||
*/
|
||||
class AggregateException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String DEFAULT_MESSAGE = "There were multiple errors.";
|
||||
|
||||
@NonNull private final List<Throwable> innerThrowables;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code AggregateException} with the current stack trace, the specified detail
|
||||
* message and with references to the inner throwables that are the cause of this exception.
|
||||
*
|
||||
* @param detailMessage The detail message for this exception.
|
||||
* @param innerThrowables The exceptions that are the cause of the current exception.
|
||||
*/
|
||||
public AggregateException(@NonNull String detailMessage, @NonNull Throwable[] innerThrowables) {
|
||||
this(detailMessage, Arrays.asList(innerThrowables));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code AggregateException} with the current stack trace, the specified detail
|
||||
* message and with references to the inner throwables that are the cause of this exception.
|
||||
*
|
||||
* @param detailMessage The detail message for this exception.
|
||||
* @param innerThrowables The exceptions that are the cause of the current exception.
|
||||
*/
|
||||
public AggregateException(
|
||||
@NonNull String detailMessage, @Nullable List<? extends Throwable> innerThrowables) {
|
||||
super(
|
||||
detailMessage,
|
||||
innerThrowables != null && innerThrowables.size() > 0 ? innerThrowables.get(0) : null);
|
||||
this.innerThrowables =
|
||||
Collections.unmodifiableList(innerThrowables != null ? innerThrowables : new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code AggregateException} with the current stack trace and with references to
|
||||
* the inner throwables that are the cause of this exception.
|
||||
*
|
||||
* @param innerThrowables The exceptions that are the cause of the current exception.
|
||||
*/
|
||||
public AggregateException(@Nullable List<? extends Throwable> innerThrowables) {
|
||||
this(DEFAULT_MESSAGE, innerThrowables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a read-only {@link List} of the {@link Throwable} instances that caused the current
|
||||
* exception.
|
||||
*/
|
||||
public @NonNull List<Throwable> getInnerThrowables() {
|
||||
return innerThrowables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(@NonNull PrintStream err) {
|
||||
super.printStackTrace(err);
|
||||
|
||||
int currentIndex = -1;
|
||||
for (Throwable throwable : innerThrowables) {
|
||||
err.append("\n");
|
||||
err.append(" Inner throwable #");
|
||||
err.append(Integer.toString(++currentIndex));
|
||||
err.append(": ");
|
||||
throwable.printStackTrace(err);
|
||||
err.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(@NonNull PrintWriter err) {
|
||||
super.printStackTrace(err);
|
||||
|
||||
int currentIndex = -1;
|
||||
for (Throwable throwable : innerThrowables) {
|
||||
err.append("\n");
|
||||
err.append(" Inner throwable #");
|
||||
err.append(Integer.toString(++currentIndex));
|
||||
err.append(": ");
|
||||
throwable.printStackTrace(err);
|
||||
err.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Please use {@link #getInnerThrowables()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public @NonNull List<Exception> getErrors() {
|
||||
List<Exception> errors = new ArrayList<Exception>();
|
||||
if (innerThrowables == null) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
for (Throwable cause : innerThrowables) {
|
||||
if (cause instanceof Exception) {
|
||||
errors.add((Exception) cause);
|
||||
} else {
|
||||
errors.add(new Exception(cause));
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Please use {@link #getInnerThrowables()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public @NonNull Throwable[] getCauses() {
|
||||
return innerThrowables.toArray(new Throwable[innerThrowables.size()]);
|
||||
}
|
||||
}
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.NonNull;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This was created because the helper methods in {@link java.util.concurrent.Executors} do not work
|
||||
* as people would normally expect.
|
||||
*
|
||||
* <p>Normally, you would think that a cached thread pool would create new threads when necessary,
|
||||
* queue them when the pool is full, and kill threads when they've been inactive for a certain
|
||||
* period of time. This is not how {@link java.util.concurrent.Executors#newCachedThreadPool()}
|
||||
* works.
|
||||
*
|
||||
* <p>Instead, {@link java.util.concurrent.Executors#newCachedThreadPool()} executes all tasks on a
|
||||
* new or cached thread immediately because corePoolSize is 0, SynchronousQueue is a queue with size
|
||||
* 0 and maxPoolSize is Integer.MAX_VALUE. This is dangerous because it can create an unchecked
|
||||
* amount of threads.
|
||||
*/
|
||||
/* package */
|
||||
final class AndroidExecutors {
|
||||
|
||||
private static final AndroidExecutors INSTANCE = new AndroidExecutors();
|
||||
|
||||
@NonNull private final Executor uiThread;
|
||||
@NonNull private final Executor uiThreadConditionalSync;
|
||||
|
||||
private AndroidExecutors() {
|
||||
uiThread = new UIThreadExecutor();
|
||||
uiThreadConditionalSync = new UIThreadConditionalSyncExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Nexus 5: Quad-Core Moto X: Dual-Core
|
||||
*
|
||||
* <p>AsyncTask: CORE_POOL_SIZE = CPU_COUNT + 1 MAX_POOL_SIZE = CPU_COUNT * 2 + 1
|
||||
*
|
||||
* <p>https://github.com/android/platform_frameworks_base/commit/719c44e03b97e850a46136ba336d729f5fbd1f47
|
||||
*/
|
||||
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
/* package */ static final int CORE_POOL_SIZE = CPU_COUNT + 1;
|
||||
/* package */ static final int MAX_POOL_SIZE = CPU_COUNT * 2 + 1;
|
||||
/* package */ static final long KEEP_ALIVE_TIME = 1L;
|
||||
|
||||
/**
|
||||
* Creates a proper Cached Thread Pool. Tasks will reuse cached threads if available or create new
|
||||
* threads until the core pool is full. tasks will then be queued. If an task cannot be queued, a
|
||||
* new thread will be created unless this would exceed max pool size, then the task will be
|
||||
* rejected. Threads will time out after 1 second.
|
||||
*
|
||||
* <p>Core thread timeout is only available on android-9+.
|
||||
*
|
||||
* @return the newly created thread pool
|
||||
*/
|
||||
public static @NonNull ExecutorService newCachedThreadPool() {
|
||||
ThreadPoolExecutor executor =
|
||||
new ThreadPoolExecutor(
|
||||
CORE_POOL_SIZE,
|
||||
MAX_POOL_SIZE,
|
||||
KEEP_ALIVE_TIME,
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a proper Cached Thread Pool. Tasks will reuse cached threads if available or create new
|
||||
* threads until the core pool is full. tasks will then be queued. If an task cannot be queued, a
|
||||
* new thread will be created unless this would exceed max pool size, then the task will be
|
||||
* rejected. Threads will time out after 1 second.
|
||||
*
|
||||
* <p>Core thread timeout is only available on android-9+.
|
||||
*
|
||||
* @param threadFactory the factory to use when creating new threads
|
||||
* @return the newly created thread pool
|
||||
*/
|
||||
public static @NonNull ExecutorService newCachedThreadPool(@NonNull ThreadFactory threadFactory) {
|
||||
ThreadPoolExecutor executor =
|
||||
new ThreadPoolExecutor(
|
||||
CORE_POOL_SIZE,
|
||||
MAX_POOL_SIZE,
|
||||
KEEP_ALIVE_TIME,
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(),
|
||||
threadFactory);
|
||||
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that schedules tasks to run asynchronously on the UI
|
||||
* thread.
|
||||
*/
|
||||
public static @NonNull Executor uiThread() {
|
||||
return INSTANCE.uiThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that runs tasks on the UI thread (immediately if
|
||||
* already on that thread).
|
||||
*/
|
||||
public static @NonNull Executor uiThreadConditionalSync() {
|
||||
return INSTANCE.uiThreadConditionalSync;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that schedules tasks to run asynchronously on the UI
|
||||
* thread.
|
||||
*/
|
||||
private static class UIThreadExecutor implements Executor {
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Override
|
||||
public void execute(@NonNull Runnable command) {
|
||||
// Otherwise, post it on the main thread handler
|
||||
mHandler.post(command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that runs tasks on the UI thread (immediately if
|
||||
* already on that thread).
|
||||
*/
|
||||
private static class UIThreadConditionalSyncExecutor implements Executor {
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Override
|
||||
public void execute(@NonNull Runnable command) {
|
||||
if (Looper.myLooper() == mHandler.getLooper()) {
|
||||
// If we're already on the main thread, execute the command immediately
|
||||
command.run();
|
||||
} else {
|
||||
// Otherwise, post it on the main thread handler
|
||||
mHandler.post(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-120
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
/** Collection of {@link Executor}s to use in conjunction with {@link Task}. */
|
||||
/* package */
|
||||
final class BoltsExecutors {
|
||||
|
||||
private static final BoltsExecutors INSTANCE = new BoltsExecutors();
|
||||
|
||||
private static boolean isAndroidRuntime() {
|
||||
String javaRuntimeName = System.getProperty("java.runtime.name");
|
||||
if (javaRuntimeName == null) {
|
||||
return false;
|
||||
}
|
||||
return javaRuntimeName.toLowerCase(Locale.US).contains("android");
|
||||
}
|
||||
|
||||
private final @NonNull ExecutorService background;
|
||||
private final @NonNull ScheduledExecutorService scheduled;
|
||||
private final @NonNull Executor immediate;
|
||||
|
||||
private BoltsExecutors() {
|
||||
background =
|
||||
!isAndroidRuntime()
|
||||
? java.util.concurrent.Executors.newCachedThreadPool()
|
||||
: AndroidExecutors.newCachedThreadPool();
|
||||
scheduled = Executors.newSingleThreadScheduledExecutor();
|
||||
immediate = new ImmediateExecutor();
|
||||
}
|
||||
|
||||
/** An {@link java.util.concurrent.Executor} that executes tasks in parallel. */
|
||||
public static @NonNull ExecutorService background() {
|
||||
return INSTANCE.background;
|
||||
}
|
||||
|
||||
/* package */ static @NonNull ScheduledExecutorService scheduled() {
|
||||
return INSTANCE.scheduled;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that executes tasks in the current thread unless the
|
||||
* stack runs too deep, at which point it will delegate to {@link BoltsExecutors#background} in
|
||||
* order to trim the stack.
|
||||
*/
|
||||
/* package */ static @NonNull Executor immediate() {
|
||||
return INSTANCE.immediate;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that runs a runnable inline (rather than scheduling it
|
||||
* on a thread pool) as long as the recursion depth is less than MAX_DEPTH. If the executor has
|
||||
* recursed too deeply, it will instead delegate to the {@link Task#BACKGROUND_EXECUTOR} in order
|
||||
* to trim the stack.
|
||||
*/
|
||||
private static class ImmediateExecutor implements Executor {
|
||||
private static final int MAX_DEPTH = 15;
|
||||
private ThreadLocal<Integer> executionDepth = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Increments the depth.
|
||||
*
|
||||
* @return the new depth value.
|
||||
*/
|
||||
private int incrementDepth() {
|
||||
Integer oldDepth = executionDepth.get();
|
||||
if (oldDepth == null) {
|
||||
oldDepth = 0;
|
||||
}
|
||||
int newDepth = oldDepth + 1;
|
||||
executionDepth.set(newDepth);
|
||||
return newDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the depth.
|
||||
*
|
||||
* @return the new depth value.
|
||||
*/
|
||||
private int decrementDepth() {
|
||||
Integer oldDepth = executionDepth.get();
|
||||
if (oldDepth == null) {
|
||||
oldDepth = 0;
|
||||
}
|
||||
int newDepth = oldDepth - 1;
|
||||
if (newDepth == 0) {
|
||||
executionDepth.remove();
|
||||
} else {
|
||||
executionDepth.set(newDepth);
|
||||
}
|
||||
return newDepth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NonNull Runnable command) {
|
||||
int depth = incrementDepth();
|
||||
try {
|
||||
if (depth <= MAX_DEPTH) {
|
||||
command.run();
|
||||
} else {
|
||||
BoltsExecutors.background().execute(command);
|
||||
}
|
||||
} finally {
|
||||
decrementDepth();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
/**
|
||||
* Propagates notification that operations should be canceled.
|
||||
*
|
||||
* <p>Create an instance of {@code CancellationTokenSource} and pass the token returned from {@code
|
||||
* CancellationTokenSource#getToken()} to the asynchronous operation(s). Call {@code
|
||||
* CancellationTokenSource#cancel()} to cancel the operations.
|
||||
*
|
||||
* <p>A {@code CancellationToken} can only be cancelled once - it should not be passed to future
|
||||
* operations once cancelled.
|
||||
*
|
||||
* @see CancellationTokenSource
|
||||
* @see CancellationTokenSource#getToken()
|
||||
* @see CancellationTokenSource#cancel()
|
||||
* @see CancellationToken#register(Runnable)
|
||||
*/
|
||||
public class CancellationToken {
|
||||
|
||||
private final CancellationTokenSource tokenSource;
|
||||
|
||||
/* package */ CancellationToken(@NonNull CancellationTokenSource tokenSource) {
|
||||
this.tokenSource = tokenSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the cancellation was requested from the source, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isCancellationRequested() {
|
||||
return tokenSource.isCancellationRequested();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a runnable that will be called when this CancellationToken is canceled. If this token
|
||||
* is already in the canceled state, the runnable will be run immediately and synchronously.
|
||||
*
|
||||
* @param action the runnable to be run when the token is cancelled.
|
||||
* @return a {@link CancellationTokenRegistration} instance that can be used to unregister the
|
||||
* action.
|
||||
*/
|
||||
public @NonNull CancellationTokenRegistration register(@NonNull Runnable action) {
|
||||
return tokenSource.register(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws CancellationException if this token has had cancellation requested. May be used to stop
|
||||
* execution of a thread or runnable.
|
||||
*/
|
||||
public void throwIfCancellationRequested() throws CancellationException {
|
||||
tokenSource.throwIfCancellationRequested();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.US,
|
||||
"%s@%s[cancellationRequested=%s]",
|
||||
getClass().getName(),
|
||||
Integer.toHexString(hashCode()),
|
||||
Boolean.toString(tokenSource.isCancellationRequested()));
|
||||
}
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* Represents a callback delegate that has been registered with a {@link CancellationToken}.
|
||||
*
|
||||
* @see CancellationToken#register(Runnable)
|
||||
*/
|
||||
class CancellationTokenRegistration implements Closeable {
|
||||
|
||||
private final Object lock = new Object();
|
||||
private @Nullable CancellationTokenSource tokenSource;
|
||||
private @Nullable Runnable action;
|
||||
private boolean closed;
|
||||
|
||||
/* package */ CancellationTokenRegistration(
|
||||
@NonNull CancellationTokenSource tokenSource, @NonNull Runnable action) {
|
||||
this.tokenSource = tokenSource;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/** Unregisters the callback runnable from the cancellation token. */
|
||||
@Override
|
||||
public void close() {
|
||||
synchronized (lock) {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
closed = true;
|
||||
tokenSource.unregister(this);
|
||||
tokenSource = null;
|
||||
action = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void runAction() {
|
||||
synchronized (lock) {
|
||||
throwIfClosed();
|
||||
action.run();
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
private void throwIfClosed() {
|
||||
if (closed) {
|
||||
throw new IllegalStateException("Object already closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
-218
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import java.io.Closeable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Signals to a {@link CancellationToken} that it should be canceled. To create a {@code
|
||||
* CancellationToken} first create a {@code CancellationTokenSource} then call {@link #getToken()}
|
||||
* to retrieve the token for the source.
|
||||
*
|
||||
* @see CancellationToken
|
||||
* @see CancellationTokenSource#getToken()
|
||||
*/
|
||||
public class CancellationTokenSource implements Closeable {
|
||||
|
||||
private final Object lock = new Object();
|
||||
private final @NonNull List<CancellationTokenRegistration> registrations = new ArrayList<>();
|
||||
private final @NonNull ScheduledExecutorService executor = BoltsExecutors.scheduled();
|
||||
@Nullable private ScheduledFuture<?> scheduledCancellation;
|
||||
private boolean cancellationRequested;
|
||||
private boolean closed;
|
||||
|
||||
/** Create a new {@code CancellationTokenSource}. */
|
||||
public CancellationTokenSource() {}
|
||||
|
||||
/**
|
||||
* @return {@code true} if cancellation has been requested for this {@code
|
||||
* CancellationTokenSource}.
|
||||
*/
|
||||
public boolean isCancellationRequested() {
|
||||
synchronized (lock) {
|
||||
throwIfClosed();
|
||||
return cancellationRequested;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the token that can be passed to asynchronous method to control cancellation.
|
||||
*/
|
||||
public @NonNull CancellationToken getToken() {
|
||||
synchronized (lock) {
|
||||
throwIfClosed();
|
||||
return new CancellationToken(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** Cancels the token if it has not already been cancelled. */
|
||||
public void cancel() {
|
||||
List<CancellationTokenRegistration> registrations;
|
||||
synchronized (lock) {
|
||||
throwIfClosed();
|
||||
if (cancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelScheduledCancellation();
|
||||
|
||||
cancellationRequested = true;
|
||||
registrations = new ArrayList<>(this.registrations);
|
||||
}
|
||||
notifyListeners(registrations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a cancel operation on this {@code CancellationTokenSource} after the specified number
|
||||
* of milliseconds.
|
||||
*
|
||||
* @param delay The number of milliseconds to wait before completing the returned task. If delay
|
||||
* is {@code 0} the cancel is executed immediately. If delay is {@code -1} any scheduled
|
||||
* cancellation is stopped.
|
||||
*/
|
||||
public void cancelAfter(final long delay) {
|
||||
cancelAfter(delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void cancelAfter(long delay, @NonNull TimeUnit timeUnit) {
|
||||
if (delay < -1) {
|
||||
throw new IllegalArgumentException("Delay must be >= -1");
|
||||
}
|
||||
|
||||
if (delay == 0) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
if (cancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelScheduledCancellation();
|
||||
|
||||
if (delay != -1) {
|
||||
scheduledCancellation =
|
||||
executor.schedule(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (lock) {
|
||||
scheduledCancellation = null;
|
||||
}
|
||||
cancel();
|
||||
}
|
||||
},
|
||||
delay,
|
||||
timeUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
synchronized (lock) {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelScheduledCancellation();
|
||||
|
||||
List<CancellationTokenRegistration> registrations = new ArrayList<>(this.registrations);
|
||||
for (CancellationTokenRegistration registration : registrations) {
|
||||
registration.close();
|
||||
}
|
||||
this.registrations.clear();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ @NonNull
|
||||
CancellationTokenRegistration register(@NonNull Runnable action) {
|
||||
CancellationTokenRegistration ctr;
|
||||
synchronized (lock) {
|
||||
throwIfClosed();
|
||||
|
||||
ctr = new CancellationTokenRegistration(this, action);
|
||||
if (cancellationRequested) {
|
||||
ctr.runAction();
|
||||
} else {
|
||||
registrations.add(ctr);
|
||||
}
|
||||
}
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws CancellationException if this token has had cancellation requested. May be used to stop
|
||||
* execution of a thread or runnable.
|
||||
*/
|
||||
/* package */ void throwIfCancellationRequested() throws CancellationException {
|
||||
synchronized (lock) {
|
||||
throwIfClosed();
|
||||
if (cancellationRequested) {
|
||||
throw new CancellationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void unregister(@NonNull CancellationTokenRegistration registration) {
|
||||
synchronized (lock) {
|
||||
throwIfClosed();
|
||||
registrations.remove(registration);
|
||||
}
|
||||
}
|
||||
|
||||
// This method makes no attempt to perform any synchronization or state checks itself and once
|
||||
// invoked will notify all runnables unconditionally. As such if you require the notification
|
||||
// event
|
||||
// to be synchronized with state changes you should provide external synchronization.
|
||||
// If this is invoked without external synchronization there is a probability the token becomes
|
||||
// cancelled concurrently.
|
||||
private void notifyListeners(@NonNull List<CancellationTokenRegistration> registrations) {
|
||||
for (CancellationTokenRegistration registration : registrations) {
|
||||
registration.runAction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.US,
|
||||
"%s@%s[cancellationRequested=%s]",
|
||||
getClass().getName(),
|
||||
Integer.toHexString(hashCode()),
|
||||
Boolean.toString(isCancellationRequested()));
|
||||
}
|
||||
|
||||
// This method makes no attempt to perform any synchronization itself - you should ensure
|
||||
// accesses to this method are synchronized if you want to ensure correct behaviour in the
|
||||
// face of a concurrent invocation of the close method.
|
||||
private void throwIfClosed() {
|
||||
if (closed) {
|
||||
throw new IllegalStateException("Object already closed");
|
||||
}
|
||||
}
|
||||
|
||||
// Performs no synchronization.
|
||||
private void cancelScheduledCancellation() {
|
||||
if (scheduledCancellation != null) {
|
||||
scheduledCancellation.cancel(true);
|
||||
scheduledCancellation = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Provides a class that can be used for capturing variables in an anonymous class implementation.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
class Capture<T> {
|
||||
private @Nullable T value;
|
||||
|
||||
public Capture() {}
|
||||
|
||||
public Capture(@Nullable T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public @Nullable T get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void set(@Nullable T value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.runtime.internal.bolts;
|
||||
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* This was created because the helper methods in {@link java.util.concurrent.Executors} do not work
|
||||
* as people would normally expect.
|
||||
*
|
||||
* <p>Normally, you would think that a cached thread pool would create new threads when necessary,
|
||||
* queue them when the pool is full, and kill threads when they've been inactive for a certain
|
||||
* period of time. This is not how {@link java.util.concurrent.Executors#newCachedThreadPool()}
|
||||
* works.
|
||||
*
|
||||
* <p>Instead, {@link java.util.concurrent.Executors#newCachedThreadPool()} executes all tasks on a
|
||||
* new or cached thread immediately because corePoolSize is 0, SynchronousQueue is a queue with size
|
||||
* 0 and maxPoolSize is Integer.MAX_VALUE. This is dangerous because it can create an unchecked
|
||||
* amount of threads.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
/* package */
|
||||
final class Executors {
|
||||
public static final Executor UI_THREAD = new UIThreadExecutor();
|
||||
|
||||
public static final Executor IMMEDIATE = new ImmediateExecutor();
|
||||
|
||||
private static class UIThreadExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
// Otherwise, post it on the main thread handler
|
||||
UiThreadUtil.runOnUiThread(command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that schedules tasks to run asynchronously on the UI
|
||||
* thread.
|
||||
*/
|
||||
private static class ImmediateExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
command.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-492
@@ -10,18 +10,11 @@ package com.facebook.react.runtime.internal.bolts;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.interfaces.TaskInterface;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Represents the result of an asynchronous operation.
|
||||
@@ -29,22 +22,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @param <TResult> The type of the result of the task.
|
||||
*/
|
||||
public class Task<TResult> implements TaskInterface<TResult> {
|
||||
/** An {@link java.util.concurrent.Executor} that executes tasks in parallel. */
|
||||
public static final ExecutorService BACKGROUND_EXECUTOR = BoltsExecutors.background();
|
||||
|
||||
/**
|
||||
* An {@link java.util.concurrent.Executor} that executes tasks in the current thread unless the
|
||||
* stack runs too deep, at which point it will delegate to {@link Task#BACKGROUND_EXECUTOR} in
|
||||
* order to trim the stack.
|
||||
*/
|
||||
private static final Executor IMMEDIATE_EXECUTOR = BoltsExecutors.immediate();
|
||||
private static final Executor IMMEDIATE_EXECUTOR = Executors.IMMEDIATE;
|
||||
|
||||
/** An {@link java.util.concurrent.Executor} that executes tasks on the UI thread. */
|
||||
public static final Executor UI_THREAD_EXECUTOR = AndroidExecutors.uiThread();
|
||||
|
||||
/** An {@link java.util.concurrent.Executor} that executes tasks on the UI thread. */
|
||||
public static final Executor UI_THREAD_CONDITIONAL_SYNC_EXECUTOR =
|
||||
AndroidExecutors.uiThreadConditionalSync();
|
||||
public static final Executor UI_THREAD_EXECUTOR = Executors.UI_THREAD;
|
||||
|
||||
/**
|
||||
* Interface for handlers invoked when a failed {@code Task} is about to be finalized, but the
|
||||
@@ -225,74 +211,6 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
return (Task<TResult>) TASK_CANCELLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task that completes after a time delay.
|
||||
*
|
||||
* @param delay The number of milliseconds to wait before completing the returned task. Zero and
|
||||
* negative values are treated as requests for immediate execution.
|
||||
*/
|
||||
public static Task<Void> delay(long delay) {
|
||||
return delay(delay, BoltsExecutors.scheduled(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task that completes after a time delay.
|
||||
*
|
||||
* @param delay The number of milliseconds to wait before completing the returned task. Zero and
|
||||
* negative values are treated as requests for immediate execution.
|
||||
* @param cancellationToken The optional cancellation token that will be checked prior to
|
||||
* completing the returned task.
|
||||
*/
|
||||
public static Task<Void> delay(long delay, CancellationToken cancellationToken) {
|
||||
return delay(delay, BoltsExecutors.scheduled(), cancellationToken);
|
||||
}
|
||||
|
||||
/* package */ static Task<Void> delay(
|
||||
long delay, ScheduledExecutorService executor, final CancellationToken cancellationToken) {
|
||||
if (cancellationToken != null && cancellationToken.isCancellationRequested()) {
|
||||
return Task.cancelled();
|
||||
}
|
||||
|
||||
if (delay <= 0) {
|
||||
return Task.forResult(null);
|
||||
}
|
||||
|
||||
final TaskCompletionSource<Void> tcs = new TaskCompletionSource<>();
|
||||
final ScheduledFuture<?> scheduled =
|
||||
executor.schedule(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
tcs.trySetResult(null);
|
||||
}
|
||||
},
|
||||
delay,
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
if (cancellationToken != null) {
|
||||
cancellationToken.register(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scheduled.cancel(true);
|
||||
tcs.trySetCancelled();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return tcs.getTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a fluent cast of a Task's result possible, avoiding an extra continuation just to cast
|
||||
* the type of the result.
|
||||
*/
|
||||
public <TOut> Task<TOut> cast() {
|
||||
@SuppressWarnings("unchecked")
|
||||
Task<TOut> task = (Task<TOut>) this;
|
||||
return task;
|
||||
}
|
||||
|
||||
/** Turns a Task<T> into a Task<Void>, dropping any result. */
|
||||
public Task<Void> makeVoid() {
|
||||
return this.continueWithTask(
|
||||
@@ -310,46 +228,14 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the callable on a background thread, returning a Task to represent the operation.
|
||||
*
|
||||
* <p>If you want to cancel the resulting Task throw a {@link
|
||||
* java.util.concurrent.CancellationException} from the callable.
|
||||
*/
|
||||
public static <TResult> Task<TResult> callInBackground(Callable<TResult> callable) {
|
||||
return call(callable, BACKGROUND_EXECUTOR, null);
|
||||
}
|
||||
|
||||
/** Invokes the callable on a background thread, returning a Task to represent the operation. */
|
||||
public static <TResult> Task<TResult> callInBackground(
|
||||
Callable<TResult> callable, CancellationToken ct) {
|
||||
return call(callable, BACKGROUND_EXECUTOR, ct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the callable using the given executor, returning a Task to represent the operation.
|
||||
*
|
||||
* <p>If you want to cancel the resulting Task throw a {@link
|
||||
* java.util.concurrent.CancellationException} from the callable.
|
||||
*/
|
||||
public static <TResult> Task<TResult> call(final Callable<TResult> callable, Executor executor) {
|
||||
return call(callable, executor, null);
|
||||
}
|
||||
|
||||
/** Invokes the callable using the given executor, returning a Task to represent the operation. */
|
||||
public static <TResult> Task<TResult> call(
|
||||
final Callable<TResult> callable, Executor executor, final CancellationToken ct) {
|
||||
public static <TResult> Task<TResult> call(final Callable<TResult> callable, Executor executor) {
|
||||
final TaskCompletionSource<TResult> tcs = new TaskCompletionSource<>();
|
||||
try {
|
||||
executor.execute(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (ct != null && ct.isCancellationRequested()) {
|
||||
tcs.setCancelled();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
tcs.setResult(callable.call());
|
||||
} catch (CancellationException e) {
|
||||
@@ -373,266 +259,7 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
* java.util.concurrent.CancellationException} from the callable.
|
||||
*/
|
||||
public static <TResult> Task<TResult> call(final Callable<TResult> callable) {
|
||||
return call(callable, IMMEDIATE_EXECUTOR, null);
|
||||
}
|
||||
|
||||
/** Invokes the callable on the current thread, producing a Task. */
|
||||
public static <TResult> Task<TResult> call(
|
||||
final Callable<TResult> callable, CancellationToken ct) {
|
||||
return call(callable, IMMEDIATE_EXECUTOR, ct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task that will complete when any of the supplied tasks have completed.
|
||||
*
|
||||
* <p>The returned task will complete when any of the supplied tasks has completed. The returned
|
||||
* task will always end in the completed state with its result set to the first task to complete.
|
||||
* This is true even if the first task to complete ended in the canceled or faulted state.
|
||||
*
|
||||
* @param tasks The tasks to wait on for completion.
|
||||
* @return A task that represents the completion of one of the supplied tasks. The return task's
|
||||
* result is the task that completed.
|
||||
*/
|
||||
public static <TResult> Task<Task<TResult>> whenAnyResult(
|
||||
Collection<? extends Task<TResult>> tasks) {
|
||||
if (tasks.size() == 0) {
|
||||
return Task.forResult(null);
|
||||
}
|
||||
|
||||
final TaskCompletionSource<Task<TResult>> firstCompleted = new TaskCompletionSource<>();
|
||||
final AtomicBoolean isAnyTaskComplete = new AtomicBoolean(false);
|
||||
|
||||
for (Task<TResult> task : tasks) {
|
||||
task.continueWith(
|
||||
new Continuation<TResult, Void>() {
|
||||
@Override
|
||||
public Void then(Task<TResult> task) {
|
||||
if (isAnyTaskComplete.compareAndSet(false, true)) {
|
||||
firstCompleted.setResult(task);
|
||||
} else {
|
||||
Throwable ensureObserved = task.getError();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return firstCompleted.getTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task that will complete when any of the supplied tasks have completed.
|
||||
*
|
||||
* <p>The returned task will complete when any of the supplied tasks has completed. The returned
|
||||
* task will always end in the completed state with its result set to the first task to complete.
|
||||
* This is true even if the first task to complete ended in the canceled or faulted state.
|
||||
*
|
||||
* @param tasks The tasks to wait on for completion.
|
||||
* @return A task that represents the completion of one of the supplied tasks. The return task's
|
||||
* Result is the task that completed.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Task<Task<?>> whenAny(Collection<? extends Task<?>> tasks) {
|
||||
if (tasks.size() == 0) {
|
||||
return Task.forResult(null);
|
||||
}
|
||||
|
||||
final TaskCompletionSource<Task<?>> firstCompleted = new TaskCompletionSource<>();
|
||||
final AtomicBoolean isAnyTaskComplete = new AtomicBoolean(false);
|
||||
|
||||
for (Task<?> task : tasks) {
|
||||
((Task<Object>) task)
|
||||
.continueWith(
|
||||
new Continuation<Object, Void>() {
|
||||
@Override
|
||||
public Void then(Task<Object> task) {
|
||||
if (isAnyTaskComplete.compareAndSet(false, true)) {
|
||||
firstCompleted.setResult(task);
|
||||
} else {
|
||||
Throwable ensureObserved = task.getError();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return firstCompleted.getTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task that completes when all of the provided tasks are complete.
|
||||
*
|
||||
* <p>If any of the supplied tasks completes in a faulted state, the returned task will also
|
||||
* complete in a faulted state, where its exception will resolve to that {@link
|
||||
* java.lang.Exception} if a single task fails or an {@link AggregateException} of all the {@link
|
||||
* java.lang.Exception}s if multiple tasks fail.
|
||||
*
|
||||
* <p>If none of the supplied tasks faulted but at least one of them was cancelled, the returned
|
||||
* task will end as cancelled.
|
||||
*
|
||||
* <p>If none of the tasks faulted and none of the tasks were cancelled, the resulting task will
|
||||
* end completed. The result of the returned task will be set to a list containing all of the
|
||||
* results of the supplied tasks in the same order as they were provided (e.g. if the input tasks
|
||||
* collection contained t1, t2, t3, the output task's result will return an {@code
|
||||
* List<TResult>} where {@code list.get(0) == t1.getResult(), list.get(1) == t2.getResult(),
|
||||
* and list.get(2) == t3.getResult()}).
|
||||
*
|
||||
* <p>If the supplied collection contains no tasks, the returned task will immediately transition
|
||||
* to a completed state before it's returned to the caller. The returned {@code
|
||||
* List<TResult>} will contain 0 elements.
|
||||
*
|
||||
* @param tasks The tasks that the return value will wait for before completing.
|
||||
* @return A Task that will resolve to {@code List<TResult>} when all the tasks are
|
||||
* resolved.
|
||||
*/
|
||||
public static <TResult> Task<List<TResult>> whenAllResult(
|
||||
final Collection<? extends Task<TResult>> tasks) {
|
||||
return whenAll(tasks)
|
||||
.onSuccess(
|
||||
new Continuation<Void, List<TResult>>() {
|
||||
@Override
|
||||
public List<TResult> then(Task<Void> task) throws Exception {
|
||||
if (tasks.size() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<TResult> results = new ArrayList<>();
|
||||
for (Task<TResult> individualTask : tasks) {
|
||||
results.add(individualTask.getResult());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task that completes when all of the provided tasks are complete.
|
||||
*
|
||||
* <p>If any of the supplied tasks completes in a faulted state, the returned task will also
|
||||
* complete in a faulted state, where its exception will resolve to that {@link
|
||||
* java.lang.Exception} if a single task fails or an {@link AggregateException} of all the {@link
|
||||
* java.lang.Exception}s if multiple tasks fail.
|
||||
*
|
||||
* <p>If none of the supplied tasks faulted but at least one of them was cancelled, the returned
|
||||
* task will end as cancelled.
|
||||
*
|
||||
* <p>If none of the tasks faulted and none of the tasks were canceled, the resulting task will
|
||||
* end in the completed state.
|
||||
*
|
||||
* <p>If the supplied collection contains no tasks, the returned task will immediately transition
|
||||
* to a completed state before it's returned to the caller.
|
||||
*
|
||||
* @param tasks The tasks that the return value will wait for before completing.
|
||||
* @return A Task that will resolve to {@code Void} when all the tasks are resolved.
|
||||
*/
|
||||
public static Task<Void> whenAll(Collection<? extends Task<?>> tasks) {
|
||||
if (tasks.size() == 0) {
|
||||
return Task.forResult(null);
|
||||
}
|
||||
|
||||
final TaskCompletionSource<Void> allFinished = new TaskCompletionSource<>();
|
||||
final ArrayList<Exception> causes = new ArrayList<>();
|
||||
final Object errorLock = new Object();
|
||||
final AtomicInteger count = new AtomicInteger(tasks.size());
|
||||
final AtomicBoolean isCancelled = new AtomicBoolean(false);
|
||||
|
||||
for (Task<?> task : tasks) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Task<Object> t = (Task<Object>) task;
|
||||
t.continueWith(
|
||||
new Continuation<Object, Void>() {
|
||||
@Override
|
||||
public Void then(Task<Object> task) {
|
||||
if (task.isFaulted()) {
|
||||
synchronized (errorLock) {
|
||||
causes.add(task.getError());
|
||||
}
|
||||
}
|
||||
|
||||
if (task.isCancelled()) {
|
||||
isCancelled.set(true);
|
||||
}
|
||||
|
||||
if (count.decrementAndGet() == 0) {
|
||||
if (causes.size() != 0) {
|
||||
if (causes.size() == 1) {
|
||||
allFinished.setError(causes.get(0));
|
||||
} else {
|
||||
Exception error =
|
||||
new AggregateException(
|
||||
String.format("There were %d exceptions.", causes.size()), causes);
|
||||
allFinished.setError(error);
|
||||
}
|
||||
} else if (isCancelled.get()) {
|
||||
allFinished.setCancelled();
|
||||
} else {
|
||||
allFinished.setResult(null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return allFinished.getTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Continues a task with the equivalent of a Task-based while loop, where the body of the loop is
|
||||
* a task continuation.
|
||||
*/
|
||||
public Task<Void> continueWhile(
|
||||
Callable<Boolean> predicate, Continuation<Void, Task<Void>> continuation) {
|
||||
return continueWhile(predicate, continuation, IMMEDIATE_EXECUTOR, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continues a task with the equivalent of a Task-based while loop, where the body of the loop is
|
||||
* a task continuation.
|
||||
*/
|
||||
public Task<Void> continueWhile(
|
||||
Callable<Boolean> predicate,
|
||||
Continuation<Void, Task<Void>> continuation,
|
||||
CancellationToken ct) {
|
||||
return continueWhile(predicate, continuation, IMMEDIATE_EXECUTOR, ct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continues a task with the equivalent of a Task-based while loop, where the body of the loop is
|
||||
* a task continuation.
|
||||
*/
|
||||
public Task<Void> continueWhile(
|
||||
final Callable<Boolean> predicate,
|
||||
final Continuation<Void, Task<Void>> continuation,
|
||||
final Executor executor) {
|
||||
return continueWhile(predicate, continuation, executor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continues a task with the equivalent of a Task-based while loop, where the body of the loop is
|
||||
* a task continuation.
|
||||
*/
|
||||
public Task<Void> continueWhile(
|
||||
final Callable<Boolean> predicate,
|
||||
final Continuation<Void, Task<Void>> continuation,
|
||||
final Executor executor,
|
||||
final CancellationToken ct) {
|
||||
final Capture<Continuation<Void, Task<Void>>> predicateContinuation = new Capture<>();
|
||||
predicateContinuation.set(
|
||||
new Continuation<Void, Task<Void>>() {
|
||||
@Override
|
||||
public Task<Void> then(Task<Void> task) throws Exception {
|
||||
if (ct != null && ct.isCancellationRequested()) {
|
||||
return Task.cancelled();
|
||||
}
|
||||
|
||||
if (predicate.call()) {
|
||||
return Task.<Void>forResult(null)
|
||||
.onSuccessTask(continuation, executor)
|
||||
.onSuccessTask(predicateContinuation.get(), executor);
|
||||
}
|
||||
return Task.forResult(null);
|
||||
}
|
||||
});
|
||||
return makeVoid().continueWithTask(predicateContinuation.get(), executor);
|
||||
return call(callable, IMMEDIATE_EXECUTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -642,18 +269,6 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(
|
||||
final Continuation<TResult, TContinuationResult> continuation, final Executor executor) {
|
||||
return continueWith(continuation, executor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a continuation that will be scheduled using the executor, returning a new task that
|
||||
* completes after the continuation has finished running. This allows the continuation to be
|
||||
* scheduled on different thread.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(
|
||||
final Continuation<TResult, TContinuationResult> continuation,
|
||||
final Executor executor,
|
||||
final CancellationToken ct) {
|
||||
boolean completed;
|
||||
final TaskCompletionSource<TContinuationResult> tcs = new TaskCompletionSource<>();
|
||||
synchronized (lock) {
|
||||
@@ -663,14 +278,14 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
new Continuation<TResult, Void>() {
|
||||
@Override
|
||||
public Void then(Task<TResult> task) {
|
||||
completeImmediately(tcs, continuation, task, executor, ct);
|
||||
completeImmediately(tcs, continuation, task, executor);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (completed) {
|
||||
completeImmediately(tcs, continuation, this, executor, ct);
|
||||
completeImmediately(tcs, continuation, this, executor);
|
||||
}
|
||||
return tcs.getTask();
|
||||
}
|
||||
@@ -681,16 +296,7 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(
|
||||
Continuation<TResult, TContinuationResult> continuation) {
|
||||
return continueWith(continuation, IMMEDIATE_EXECUTOR, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a synchronous continuation to this task, returning a new task that completes after the
|
||||
* continuation has finished running.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(
|
||||
Continuation<TResult, TContinuationResult> continuation, CancellationToken ct) {
|
||||
return continueWith(continuation, IMMEDIATE_EXECUTOR, ct);
|
||||
return continueWith(continuation, IMMEDIATE_EXECUTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -700,17 +306,6 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(
|
||||
final Continuation<TResult, Task<TContinuationResult>> continuation,
|
||||
final Executor executor) {
|
||||
return continueWithTask(continuation, executor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Task-based continuation to this task that will be scheduled using the executor,
|
||||
* returning a new task that completes after the task returned by the continuation has completed.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(
|
||||
final Continuation<TResult, Task<TContinuationResult>> continuation,
|
||||
final Executor executor,
|
||||
final CancellationToken ct) {
|
||||
boolean completed;
|
||||
final TaskCompletionSource<TContinuationResult> tcs = new TaskCompletionSource<>();
|
||||
synchronized (lock) {
|
||||
@@ -720,14 +315,14 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
new Continuation<TResult, Void>() {
|
||||
@Override
|
||||
public Void then(Task<TResult> task) {
|
||||
completeAfterTask(tcs, continuation, task, executor, ct);
|
||||
completeAfterTask(tcs, continuation, task, executor);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (completed) {
|
||||
completeAfterTask(tcs, continuation, this, executor, ct);
|
||||
completeAfterTask(tcs, continuation, this, executor);
|
||||
}
|
||||
return tcs.getTask();
|
||||
}
|
||||
@@ -738,16 +333,7 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(
|
||||
Continuation<TResult, Task<TContinuationResult>> continuation) {
|
||||
return continueWithTask(continuation, IMMEDIATE_EXECUTOR, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asynchronous continuation to this task, returning a new task that completes after the
|
||||
* task returned by the continuation has completed.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(
|
||||
Continuation<TResult, Task<TContinuationResult>> continuation, CancellationToken ct) {
|
||||
return continueWithTask(continuation, IMMEDIATE_EXECUTOR, ct);
|
||||
return continueWithTask(continuation, IMMEDIATE_EXECUTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -756,25 +342,10 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccess(
|
||||
final Continuation<TResult, TContinuationResult> continuation, Executor executor) {
|
||||
return onSuccess(continuation, executor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a continuation when a task completes successfully, forwarding along {@link
|
||||
* java.lang.Exception} or cancellation.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccess(
|
||||
final Continuation<TResult, TContinuationResult> continuation,
|
||||
Executor executor,
|
||||
final CancellationToken ct) {
|
||||
return continueWithTask(
|
||||
new Continuation<TResult, Task<TContinuationResult>>() {
|
||||
@Override
|
||||
public Task<TContinuationResult> then(Task<TResult> task) {
|
||||
if (ct != null && ct.isCancellationRequested()) {
|
||||
return Task.cancelled();
|
||||
}
|
||||
|
||||
if (task.isFaulted()) {
|
||||
return Task.forError(task.getError());
|
||||
} else if (task.isCancelled()) {
|
||||
@@ -793,16 +364,7 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccess(
|
||||
final Continuation<TResult, TContinuationResult> continuation) {
|
||||
return onSuccess(continuation, IMMEDIATE_EXECUTOR, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a continuation when a task completes successfully, forwarding along {@link
|
||||
* java.lang.Exception}s or cancellation.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccess(
|
||||
final Continuation<TResult, TContinuationResult> continuation, CancellationToken ct) {
|
||||
return onSuccess(continuation, IMMEDIATE_EXECUTOR, ct);
|
||||
return onSuccess(continuation, IMMEDIATE_EXECUTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -811,25 +373,10 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccessTask(
|
||||
final Continuation<TResult, Task<TContinuationResult>> continuation, Executor executor) {
|
||||
return onSuccessTask(continuation, executor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a continuation when a task completes successfully, forwarding along {@link
|
||||
* java.lang.Exception}s or cancellation.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccessTask(
|
||||
final Continuation<TResult, Task<TContinuationResult>> continuation,
|
||||
Executor executor,
|
||||
final CancellationToken ct) {
|
||||
return continueWithTask(
|
||||
new Continuation<TResult, Task<TContinuationResult>>() {
|
||||
@Override
|
||||
public Task<TContinuationResult> then(Task<TResult> task) {
|
||||
if (ct != null && ct.isCancellationRequested()) {
|
||||
return Task.cancelled();
|
||||
}
|
||||
|
||||
if (task.isFaulted()) {
|
||||
return Task.forError(task.getError());
|
||||
} else if (task.isCancelled()) {
|
||||
@@ -851,15 +398,6 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
return onSuccessTask(continuation, IMMEDIATE_EXECUTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a continuation when a task completes successfully, forwarding along {@link
|
||||
* java.lang.Exception}s or cancellation.
|
||||
*/
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccessTask(
|
||||
final Continuation<TResult, Task<TContinuationResult>> continuation, CancellationToken ct) {
|
||||
return onSuccessTask(continuation, IMMEDIATE_EXECUTOR, ct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the non-async (i.e. the continuation doesn't return a Task) continuation case, passing
|
||||
* the results of the given Task through to the given continuation and using the results of that
|
||||
@@ -875,18 +413,12 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
final TaskCompletionSource<TContinuationResult> tcs,
|
||||
final Continuation<TResult, TContinuationResult> continuation,
|
||||
final Task<TResult> task,
|
||||
Executor executor,
|
||||
final CancellationToken ct) {
|
||||
Executor executor) {
|
||||
try {
|
||||
executor.execute(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (ct != null && ct.isCancellationRequested()) {
|
||||
tcs.setCancelled();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
TContinuationResult result = continuation.then(task);
|
||||
tcs.setResult(result);
|
||||
@@ -918,18 +450,12 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
final TaskCompletionSource<TContinuationResult> tcs,
|
||||
final Continuation<TResult, Task<TContinuationResult>> continuation,
|
||||
final Task<TResult> task,
|
||||
final Executor executor,
|
||||
final CancellationToken ct) {
|
||||
final Executor executor) {
|
||||
try {
|
||||
executor.execute(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (ct != null && ct.isCancellationRequested()) {
|
||||
tcs.setCancelled();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Task<TContinuationResult> result = continuation.then(task);
|
||||
if (result == null) {
|
||||
@@ -939,11 +465,6 @@ public class Task<TResult> implements TaskInterface<TResult> {
|
||||
new Continuation<TContinuationResult, Void>() {
|
||||
@Override
|
||||
public Void then(Task<TContinuationResult> task) {
|
||||
if (ct != null && ct.isCancellationRequested()) {
|
||||
tcs.setCancelled();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (task.isCancelled()) {
|
||||
tcs.setCancelled();
|
||||
} else if (task.isFaulted()) {
|
||||
|
||||
Reference in New Issue
Block a user