blob: 9d095a15738a6696f5f4aab17cfc5bf5e5a1f4eb [file] [log] [blame] [view]
# TaskScheduler Migration
[TOC]
## Overview
[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h)
was introduced to Chrome in Q1. The API is fully documented under [Threading and
Tasks in Chrome](threading_and_tasks.md). This page will go into more details
about how to migrate callers of existing APIs to TaskScheduler.
The SequencedWorkerPools and BrowserThreads (not UI/IO) are already being
redirected to TaskScheduler under the hood so it's now "merely" a matter of
updating the actual call sites.
Much of the migration has already been automated but the callers that remain
require manual intervention from the OWNERS.
Here's [a list](https://docs.google.com/spreadsheets/d/18x9PGMlfgWcBr4fDz2SEEtIwTpSjcBFT2Puib47ZF1w/edit)
of everything that's left. Please pick items in this list, assign them to self
and tick the boxes when done.
And some [slides](https://docs.google.com/presentation/d/191H9hBO0r5pH2JVMeYYV-yrP1175JoSlrZyK5QEeUlE/edit?usp=sharing)
with a migration example.
## BlockingPool (and other SequencedWorkerPools)
Tag migration CLs with BUG=[667892](https://crbug.com/667892).
The remaining callers of BrowserThread::GetBlockingPool() require manual
intervention because they're plumbing the SequencedWorkerPool multiple layers
into another component.
The TaskScheduler API explicitly discourages this paradigm. Instead exposing a
static API from post_task.h and encouraging that individual components grab the
TaskRunner/TaskTraits they need instead of bring injected one from their owner
and hoping for the right traits. This often allows cleaning up multiple layers
of plumbing without otherwise hurting testing as documented
[here](threading_and_tasks.md#TaskRunner-ownership-encourage-no-dependency-injection).
Replace methods that used to
```cpp
DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksInCurrentSequence());
```
and make them use
```cpp
base::ThreadRestrictions::AssertIOAllowed();
```
The TaskScheduler API intentionally doesn't provide a
TaskScheduler::RunsTasksInCurrentSequence() equivalent as ultimately everything
will run in TaskScheduler and that'd be meaningless... As such prefer asserting
the properties your task needs as documentation rather than where it runs.
You can of course still use
```cpp
DCHECK(task_runner_->RunsTasksInCurrentSequence());
```
if you have access to the TaskRunner instance (generic asserts discussed above
are meant for anonymous methods that require static checks).
Note: Contrary to overheard belief: SequencedWorkerPool::PostTask() resulted in
an unsequenced (parallel) task. The SequencedWorkerPool allowed posting to
sequences but on its own was just a plain TaskRunner (despite having sequence in
its name...). base::PostTaskWithTraits() is thus the proper replacement if not
having explicit sequencing was intended, otherwise
base::CreateSequenceTaskRunnerWithTraits() is what you're looking for.
## BrowserThreads
All BrowserThreads but UI/IO are being migrated to TaskScheduler
(i.e. FILE/FILE_USER_BLOCKING/DB/PROCESS_LAUNCHER/CACHE).
Tag migration CLs with BUG=[689520](https://crbug.com/689520).
This migration requires manual intervention because:
1. Everything on BrowserThread::FOO has to be assumed to depend on being
sequenced with everything else on BrowserThread::FOO until decided otherwise
by a developer.
2. Everything on BrowserThread::FOO has to be assumed to be thread-affine until
decided otherwise by a developer.
As a developer your goal is to get rid of all uses of BrowserThread::FOO in your
assigned files by:
1. Splitting things into their own execution sequence (i.e. post to a TaskRunner
obtained from post_task.h -- see [Threading and Tasks in
Chrome](threading_and_tasks.md) for details).
2. Removing the plumbing: if GetTaskRunnerForThread(BrowserThread::FOO) is
passed down into a component the prefered paradigm is to remove all of that
plumbing and simply have the leaf layers requiring a TaskRunner get it from
base::CreateSequencedTaskRunnerWithTraits() directly.
3. Ideally migrating from a single-threaded context to a
[much preferred](threading_and_tasks.md#Prefer-Sequences-to-Threads) sequenced context.
* Note: if your tasks use COM APIs (Component Object Model on Windows),
you'll need to use CreateCOMSTATaskRunnerWithTraits() and sequencing will
not be an option (there are DCHECKs in place that will fire if your task
uses COM without being on a COM initialized TaskRunner).
## Relevant single-thread -> sequence mappings
* base::SingleThreadTaskRunner -> base::SequencedTaskRunner
* SingleThreadTaskRunner::BelongsToCurrentThread() -> SeqeuenceTaskRunner::RunsTasksInCurrentSequence()
* base::ThreadTaskRunnerHandle -> base::SequencedTaskRunnerHandle
* base::ThreadChecker -> base::SequenceChecker
* ThreadChecker::CalledOnValidThread() -> DCHECK_CALLED_ON_VALID_SEQUENCE(...)
* base::ThreadLocalStorage::Slot -> base::SequenceLocalStorageSlot
* BrowserThread::PostTaskAndReplyWithResult() -> base::PostTaskAndReplyWithResult()
(from post_task.h or from task_runner_util.h (if you need to feed a TaskRunner))
* BrowserThread::DeleteOnThread -> base::OnTaskRunnerDeleter / base::RefCountedDeleteOnSequence
* BrowserMessageFilter::OverrideThreadForMessage() -> BrowserMessageFilter::OverrideTaskRunnerForMessage()
* CreateSingleThreadTaskRunnerWithTraits() -> CreateSequencedTaskRunnerWithTraits()
* Every CreateSingleThreadTaskRunnerWithTraits() usage should be accompanied
with a comment and ideally a bug to make it sequence when the sequence-unfriendly
dependency is addressed (again [Prefer Sequences to
Threads](threading_and_tasks.md#Prefer-Sequences-to-Threads)).
### Other relevant mappings for tests
* base::MessageLoop -> base::test::ScopedTaskEnvironment
* content::TestBrowserThread -> content::TestBrowserThreadBundle (if you still
need other BrowserThreads and ScopedTaskEnvironment if you don't)
* base::RunLoop().Run() -(maybe)> content::RunAllTasksUntilIdle()
* If test code was previously using RunLoop to execute things off the main
thread (as TestBrowserThreadBundle grouped everything under a single
MessageLoop), flushing tasks will now require asking for that explicitly.
* Or ScopedTaskEnvironment::RunUntilIdle() if you're not using
TestBrowserThreadBundle.
* If you need to control the order of execution of main thread versus
scheduler you can individually RunLoop.Run() and
TaskScheduler::FlushForTesting()
* If you need the TaskScheduler to not run anything until explicitly asked to
use ScopedTaskEnvironment::ExecutionMode::QUEUED.
## Other known migration hurdles and recommended paradigms
* Everything in a file/component needs to run on the same sequence but there
isn't a clear place to own/access the common SequencedTaskRunner =>
base::Lazy(Sequenced|SingleThread|COMSTA)TaskRunner.
* For anything else, ping [base/task_scheduler/OWNERS](https://cs.chromium.org/chromium/src/base/task_scheduler/OWNERS)
or [[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/scheduler-dev),
thanks!