Chromium Code Reviews| Index: base/threading/task_runner_handle.cc |
| diff --git a/base/threading/task_runner_handle.cc b/base/threading/task_runner_handle.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6d44f56bfda5aeeaa004ab7a243fd7f4f8459b96 |
| --- /dev/null |
| +++ b/base/threading/task_runner_handle.cc |
| @@ -0,0 +1,151 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "base/threading/task_runner_handle.h" |
| + |
| +#include <utility> |
| + |
| +#include "base/lazy_instance.h" |
| +#include "base/logging.h" |
| +#include "base/threading/sequenced_worker_pool.h" |
| +#include "base/threading/thread_local.h" |
| + |
| +namespace base { |
| + |
| +namespace { |
| + |
| +// TaskScopeState for the current thread stored in TLS. |
| +LazyInstance<ThreadLocalPointer<internal::TaskScopeState>>::Leaky |
| + g_task_scope_state = LAZY_INSTANCE_INITIALIZER; |
| + |
| +} // namespace |
| + |
| +scoped_refptr<TaskRunner> TaskRunnerHandle::Get() { |
| + DCHECK(HasTaskScope()); |
| + |
| + const internal::TaskScopeState* state = g_task_scope_state.Get().Get(); |
| + if (state) |
| + return state->task_runners.task_runner; |
| + |
| + // Explicitly support the SequencedWorkerPool here while it still exists |
| + // (supporting TaskRunnerHandles from it would be non-trivial and it will soon |
| + // be deprecated in favor of TaskScheduler). |
| + return SequencedWorkerPool::GetWorkerPoolForCurrentThread(); |
| +} |
| + |
| +scoped_refptr<SequencedTaskRunner> TaskRunnerHandle::GetSequenced() { |
| + DCHECK(HasSequencedTaskScope()); |
| + |
| + const internal::TaskScopeState* state = g_task_scope_state.Get().Get(); |
| + if (state) |
| + return state->task_runners.sequenced_task_runner; |
| + |
| + // Assuming there is a sequenced scope and it isn't in our TLS, the current |
| + // context is the SequencedWorkerPool: get its SequencedTaskRunner. Note: this |
| + // special case will go away when SequencedWorkerPool is deprecated in favor |
| + // of TaskScheduler. |
| + scoped_refptr<SequencedTaskRunner> sequenced_worker_pool_runner = |
| + SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread(); |
| + return sequenced_worker_pool_runner; |
| +} |
| + |
| +scoped_refptr<SingleThreadTaskRunner> TaskRunnerHandle::GetSingleThreaded() { |
| + DCHECK(HasSingleThreadTaskScope()); |
| + return g_task_scope_state.Get().Get()->task_runners.single_thread_task_runner; |
| +} |
| + |
| +bool TaskRunnerHandle::HasTaskScope() { |
| + return g_task_scope_state.Get().Get() || |
| + SequencedWorkerPool::GetWorkerPoolForCurrentThread(); |
| +} |
| + |
| +bool TaskRunnerHandle::HasSequencedTaskScope() { |
| + // TODO(gab): Replace GetWorkerPoolForCurrentThread() below with |
| + // GetSequenceTokenForCurrentThread() once returning a SequencedTaskRunner |
| + // from an unsequenced task is deprecated. |
| + const internal::TaskScopeState* state = g_task_scope_state.Get().Get(); |
| + return state ? state->type >= internal::TaskScopeState::SEQUENCED |
| + : !!SequencedWorkerPool::GetWorkerPoolForCurrentThread(); |
| +} |
| + |
| +bool TaskRunnerHandle::HasSingleThreadTaskScope() { |
| + const internal::TaskScopeState* state = g_task_scope_state.Get().Get(); |
| + return (state && state->type >= internal::TaskScopeState::SINGLE_THREADED); |
| +} |
| + |
| +TaskRunnerHandle::TaskScope::TaskScope(scoped_refptr<TaskRunner> task_runner) |
| + : state_(std::move(task_runner)) {} |
| + |
| +TaskRunnerHandle::SequencedTaskScope::SequencedTaskScope( |
| + scoped_refptr<SequencedTaskRunner> sequenced_task_runner) |
| + : state_(std::move(sequenced_task_runner)) {} |
| + |
| +TaskRunnerHandle::SingleThreadTaskScope::SingleThreadTaskScope( |
| + scoped_refptr<SingleThreadTaskRunner> single_thread_task_runner) |
| + : state_(std::move(single_thread_task_runner)) {} |
| + |
| +namespace internal { |
| + |
| +TaskScopeState::TaskScopeState(scoped_refptr<TaskRunner> task_runner) |
| + : type(PARALLEL), task_runners(std::move(task_runner)) { |
| + DCHECK(!TaskRunnerHandle::HasTaskScope()); |
| + g_task_scope_state.Get().Set(this); |
| +} |
| + |
| +TaskScopeState::TaskScopeState( |
| + scoped_refptr<SequencedTaskRunner> sequenced_task_runner) |
| + : type(SEQUENCED), task_runners(std::move(sequenced_task_runner)) { |
| + DCHECK(!TaskRunnerHandle::HasTaskScope()); |
| + g_task_scope_state.Get().Set(this); |
| +} |
| + |
| +TaskScopeState::TaskScopeState( |
| + scoped_refptr<SingleThreadTaskRunner> single_thread_task_runner) |
| + : type(SINGLE_THREADED), |
| + task_runners(std::move(single_thread_task_runner)) { |
| + DCHECK(!TaskRunnerHandle::HasTaskScope()); |
| + g_task_scope_state.Get().Set(this); |
| +} |
| + |
| +TaskScopeState::~TaskScopeState() { |
| + DCHECK(TaskRunnerHandle::HasTaskScope()); |
| + DCHECK(TaskRunnerHandle::HasSequencedTaskScope() || type < SEQUENCED); |
| + DCHECK(TaskRunnerHandle::HasSingleThreadTaskScope() || |
| + type < SINGLE_THREADED); |
| + |
| + DCHECK(TaskRunnerHandle::Get()->RunsTasksOnCurrentThread()); |
| + |
| + g_task_scope_state.Get().Set(nullptr); |
| + DCHECK(!TaskRunnerHandle::HasTaskScope()); |
| +} |
| + |
| +TaskScopeState::TaskRunnerUnion::TaskRunnerUnion( |
| + scoped_refptr<TaskRunner> task_runner_in) |
| + : task_runner(std::move(task_runner_in)) { |
| + DCHECK(task_runner->RunsTasksOnCurrentThread()); |
| +} |
| + |
| +TaskScopeState::TaskRunnerUnion::TaskRunnerUnion( |
| + scoped_refptr<SequencedTaskRunner> sequenced_task_runner_in) |
| + : sequenced_task_runner(std::move(sequenced_task_runner_in)) { |
| + DCHECK(sequenced_task_runner->RunsTasksOnCurrentThread()); |
| +} |
| + |
| +TaskScopeState::TaskRunnerUnion::TaskRunnerUnion( |
| + scoped_refptr<SingleThreadTaskRunner> single_thread_task_runner_in) |
| + : single_thread_task_runner(std::move(single_thread_task_runner_in)) { |
| + DCHECK(single_thread_task_runner->BelongsToCurrentThread()); |
| +} |
| + |
| +TaskScopeState::TaskRunnerUnion::~TaskRunnerUnion() { |
| + // Unions with complex members require explicit destruction. All types in the |
| + // union derive from base::TaskRunner, as such it is ok to always use that |
| + // type for deletion. |
| + if (task_runner) |
| + task_runner.get()->Release(); |
|
fdoray
2016/06/17 14:29:02
I'm not strongly against the union, but with a cas
gab
2016/06/20 19:55:36
Right, done (based on what I read in this I think
|
| +} |
| + |
| +} // namespace internal |
| + |
| +} // namespace base |