diff --git a/okhttp/src/main/java/okhttp3/internal/concurrent/Task.kt b/okhttp/src/main/java/okhttp3/internal/concurrent/Task.kt new file mode 100644 index 000000000..541011e47 --- /dev/null +++ b/okhttp/src/main/java/okhttp3/internal/concurrent/Task.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3.internal.concurrent + +/** + * A unit of work that can be executed one or more times. + * + * Cancellation + * ------------ + * + * Tasks control their cancellation. If the hosting queue is canceled, the [Task.tryCancel] function + * returns true if the task should skip the next-scheduled execution. Note that canceling a task is + * not permanent; it is okay to schedule a task after it has been canceled. + * + * Recurrence + * ---------- + * + * Tasks control their recurrence schedule. The [runOnce] function returns -1L to signify that the + * task should not be executed again. Otherwise it returns a delay until the next execution. + * + * A task has at most one next execution. If the same task instance is scheduled multiple times, the + * earliest one wins. This applies to both executions scheduled with [TaskRunner.Queue.schedule] and + * those implied by the returned execution delay. + * + * Task Queues + * ----------- + * + * Tasks are bound to the [TaskQueue] they are scheduled in. Each queue is sequential and the tasks + * within it never execute concurrently. It is an error to use a task in multiple queues. + */ +abstract class Task( + val name: String, + val daemon: Boolean = true +) { + /** Returns the delay in nanoseconds until the next execution, or -1L to not reschedule. */ + abstract fun runOnce(): Long + + /** Return true to skip the scheduled execution. */ + open fun tryCancel(): Boolean = false +} diff --git a/okhttp/src/main/java/okhttp3/internal/concurrent/TaskQueue.kt b/okhttp/src/main/java/okhttp3/internal/concurrent/TaskQueue.kt new file mode 100644 index 000000000..554232c50 --- /dev/null +++ b/okhttp/src/main/java/okhttp3/internal/concurrent/TaskQueue.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3.internal.concurrent + +/** + * A set of tasks that are executed in sequential order. + * + * Work within queues is not concurrent. This is equivalent to each queue having a dedicated thread + * for its work; in practice a set of queues may share a set of threads to save resources. + */ +interface TaskQueue { + /** + * An application-level object like a connection pool or HTTP call that this queue works on behalf + * of. This is intended to be useful for testing and debugging only. + */ + val owner: Any + + /** Returns a snapshot of tasks currently scheduled for execution. */ + val scheduledTasks: List + + /** + * Schedules [task] for execution in [delayNanos]. A task may only have one future execution + * scheduled. If the task is already in the queue, the earliest execution time is used. + * + * The target execution time is implemented on a best-effort basis. If another task in this queue + * is running when that time is reached, that task is allowed to complete before this task is + * started. Similarly the task will be delayed if the host lacks compute resources. + */ + fun schedule(task: Task, delayNanos: Long = 0L) + + /** + * Schedules immediate execution of [Task.tryCancel] on all currently-enqueued tasks. These calls + * will not be made until any currently-executing task has completed. Tasks that return true will + * be removed from the execution schedule. + */ + fun cancelAll() +} diff --git a/okhttp/src/main/java/okhttp3/internal/concurrent/TaskRunner.kt b/okhttp/src/main/java/okhttp3/internal/concurrent/TaskRunner.kt new file mode 100644 index 000000000..f003f15b3 --- /dev/null +++ b/okhttp/src/main/java/okhttp3/internal/concurrent/TaskRunner.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3.internal.concurrent + +/** + * A set of worker threads that are shared among a set of task queues. + * + * The task runner is responsible for managing non-daemon threads. It keeps the process alive while + * user-visible (ie. non-daemon) tasks are scheduled, and allows the process to exit when only + * housekeeping (ie. daemon) tasks are scheduled. + * + * The task runner is also responsible for releasing held threads when the library is unloaded. + * This is for the benefit of container environments that implement code unloading. + * + * Most applications should share a process-wide [TaskRunner] and use queues for per-client work. + */ +interface TaskRunner { + fun newQueue(owner: Any): TaskQueue + + /** + * Returns a snapshot of queues that currently have tasks scheduled. The task runner does not + * necessarily track queues that have no tasks scheduled. + */ + fun activeQueues(): List +}