Index: base/task_scheduler/scheduler_single_thread_task_runner_manager.cc |
diff --git a/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc b/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc |
index d96b8cef643dfa211d58df4a44214faa3980276b..3f45500e8a6edd714084586a32d6b404e5b33de5 100644 |
--- a/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc |
+++ b/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc |
@@ -246,8 +246,12 @@ class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner |
SchedulerSingleThreadTaskRunner( |
SchedulerSingleThreadTaskRunnerManager* const outer, |
const TaskTraits& traits, |
- SchedulerWorker* worker) |
- : outer_(outer), traits_(traits), worker_(worker) { |
+ SchedulerWorker* worker, |
+ SingleThreadTaskRunnerThreadMode thread_mode) |
+ : outer_(outer), |
+ traits_(traits), |
+ worker_(worker), |
+ thread_mode_(thread_mode) { |
DCHECK(outer_); |
DCHECK(worker_); |
} |
@@ -285,12 +289,16 @@ class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner |
private: |
~SchedulerSingleThreadTaskRunner() override { |
- // Note: This will crash if SchedulerSingleThreadTaskRunnerManager is |
- // incorrectly destroyed first in tests (in production the TaskScheduler and |
- // all of its state are intentionally leaked after |
- // TaskScheduler::Shutdown(). See ~SchedulerSingleThreadTaskRunnerManager() |
- // for more details. |
- outer_->UnregisterSchedulerWorker(worker_); |
+ // Only unregister if this is a DEDICATED SingleThreadTaskRunner. SHARED |
+ // task runner SchedulerWorkers are managed separately as they are reused. |
+ if (thread_mode_ == SingleThreadTaskRunnerThreadMode::DEDICATED) { |
+ // Note: This will crash if SchedulerSingleThreadTaskRunnerManager is |
+ // incorrectly destroyed first in tests (in production the TaskScheduler |
+ // and all of its state are intentionally leaked after |
+ // TaskScheduler::Shutdown(). See |
+ // ~SchedulerSingleThreadTaskRunnerManager() for more details. |
+ outer_->UnregisterSchedulerWorker(worker_); |
+ } |
} |
void PostTaskNow(std::unique_ptr<Task> task) { |
@@ -314,6 +322,7 @@ class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner |
SchedulerSingleThreadTaskRunnerManager* const outer_; |
const TaskTraits traits_; |
SchedulerWorker* const worker_; |
+ const SingleThreadTaskRunnerThreadMode thread_mode_; |
DISALLOW_COPY_AND_ASSIGN(SchedulerSingleThreadTaskRunner); |
}; |
@@ -321,9 +330,25 @@ class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner |
SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunnerManager( |
TaskTracker* task_tracker, |
DelayedTaskManager* delayed_task_manager) |
- : task_tracker_(task_tracker), delayed_task_manager_(delayed_task_manager) { |
+ : task_tracker_(task_tracker), |
+ delayed_task_manager_(delayed_task_manager), |
+ shared_scheduler_workers_ {} |
+#if defined(OS_WIN) |
+ , |
+ shared_com_scheduler_workers_ {} |
gab
2017/05/25 18:47:00
Use member initialization for these two as mention
robliao
2017/05/30 20:01:06
Done.
|
+#endif // defined(OS_WIN) |
+{ |
DCHECK(task_tracker_); |
DCHECK(delayed_task_manager_); |
+ static_assert( |
+ arraysize(shared_scheduler_workers_) == ENVIRONMENT_COUNT, |
fdoray
2017/05/25 17:02:59
The static_assert is redundant if this is defined
gab
2017/05/25 18:47:00
Agreed and with the initialization moving to membe
robliao
2017/05/30 20:01:06
Done. Keeping the one below though since that cert
|
+ "The size of |shared_scheduler_workers_| must match ENVIRONMENT_COUNT"); |
+#if defined(OS_WIN) |
+ static_assert(arraysize(shared_com_scheduler_workers_) == |
+ arraysize(shared_scheduler_workers_), |
+ "The size of |shared_com_scheduler_workers_| must match " |
+ "|shared_scheduler_workers_|"); |
+#endif // defined(OS_WIN) |
} |
SchedulerSingleThreadTaskRunnerManager:: |
@@ -375,24 +400,72 @@ void SchedulerSingleThreadTaskRunnerManager::Start() { |
scoped_refptr<SingleThreadTaskRunner> |
SchedulerSingleThreadTaskRunnerManager::CreateSingleThreadTaskRunnerWithTraits( |
const std::string& name, |
- ThreadPriority priority_hint, |
- const TaskTraits& traits) { |
- return CreateSingleThreadTaskRunnerWithDelegate<SchedulerWorkerDelegate>( |
- name, priority_hint, traits); |
+ const TaskTraits& traits, |
+ SingleThreadTaskRunnerThreadMode thread_mode) { |
+ return CreateTaskRunnerWithTraitsImpl<SchedulerWorkerDelegate>(name, traits, |
+ thread_mode); |
} |
#if defined(OS_WIN) |
scoped_refptr<SingleThreadTaskRunner> |
SchedulerSingleThreadTaskRunnerManager::CreateCOMSTATaskRunnerWithTraits( |
const std::string& name, |
- ThreadPriority priority_hint, |
- const TaskTraits& traits) { |
- return CreateSingleThreadTaskRunnerWithDelegate<SchedulerWorkerCOMDelegate>( |
- name, priority_hint, traits); |
+ const TaskTraits& traits, |
+ SingleThreadTaskRunnerThreadMode thread_mode) { |
+ return CreateTaskRunnerWithTraitsImpl<SchedulerWorkerCOMDelegate>( |
+ name, traits, thread_mode); |
} |
#endif // defined(OS_WIN) |
+template <typename DelegateType> |
+scoped_refptr< |
+ SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner> |
+SchedulerSingleThreadTaskRunnerManager::CreateTaskRunnerWithTraitsImpl( |
+ const std::string& name, |
+ const TaskTraits& traits, |
+ SingleThreadTaskRunnerThreadMode thread_mode) { |
+ DCHECK(thread_mode != SingleThreadTaskRunnerThreadMode::SHARED || |
+ !traits.with_base_sync_primitives()) |
+ << "Using WithBaseSyncPrimitives() on a shared SingleThreadTaskRunner " |
+ "may cause deadlocks. Either reevaluate your usage pattern or use " |
gab
2017/05/25 18:47:00
"... your usage patterns (e.g. use SequencedTaskRu
robliao
2017/05/30 20:01:06
added the e.g. The singular usage is appropriate h
|
+ "SingleThreadTaskRunnerThreadMode::DEDICATED."; |
+ // To simplify the code, |dedicated_worker| is a local only variable that |
+ // allows the code to treat both the DEDICATED and SHARED cases similarly for |
+ // SingleThreadTaskRunnerThreadMode. In DEDICATED, the scoped_refptr is backed |
+ // by a local variable and in SHARED, the scoped_refptr is backed by a member |
+ // variable. |
+ SchedulerWorker* dedicated_worker = nullptr; |
+ SchedulerWorker*& worker = |
+ thread_mode == SingleThreadTaskRunnerThreadMode::DEDICATED |
+ ? dedicated_worker |
+ : GetSharedSchedulerWorkerForTraits<DelegateType>(traits); |
+ bool new_worker = false; |
+ bool started; |
+ { |
+ AutoSchedulerLock auto_lock(lock_); |
+ if (!worker) { |
+ const auto& environment_params = |
+ kEnvironmentParams[GetEnvironmentIndexForTraits(traits)]; |
+ std::string processed_name = |
+ thread_mode == SingleThreadTaskRunnerThreadMode::DEDICATED |
+ ? name + environment_params.name_suffix |
+ : "Shared" + name + environment_params.name_suffix; |
+ worker = CreateAndRegisterSchedulerWorker<DelegateType>( |
+ processed_name, environment_params.priority_hint); |
+ new_worker = true; |
+ } |
+ started = started_; |
+ } |
+ |
+ if (new_worker && started) |
+ worker->Start(); |
+ |
+ return new SchedulerSingleThreadTaskRunner(this, traits, worker, thread_mode); |
fdoray
2017/05/25 17:02:59
MakeRefCounted<SchedulerSingleThreadTaskRunner>
robliao
2017/05/30 20:01:06
Done.
|
+} |
+ |
void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() { |
+ ReleaseSharedSchedulerWorkers(); |
+ |
decltype(workers_) local_workers; |
{ |
AutoSchedulerLock auto_lock(lock_); |
@@ -410,16 +483,6 @@ void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() { |
} |
} |
-template <typename DelegateType> |
-scoped_refptr<SingleThreadTaskRunner> SchedulerSingleThreadTaskRunnerManager:: |
- CreateSingleThreadTaskRunnerWithDelegate(const std::string& name, |
- ThreadPriority priority_hint, |
- const TaskTraits& traits) { |
- return new SchedulerSingleThreadTaskRunner( |
- this, traits, |
- CreateAndRegisterSchedulerWorker<DelegateType>(name, priority_hint)); |
-} |
- |
template <> |
std::unique_ptr<SchedulerWorkerDelegate> |
SchedulerSingleThreadTaskRunnerManager::CreateSchedulerWorkerDelegate< |
@@ -444,24 +507,29 @@ SchedulerWorker* |
SchedulerSingleThreadTaskRunnerManager::CreateAndRegisterSchedulerWorker( |
const std::string& name, |
ThreadPriority priority_hint) { |
- SchedulerWorker* worker; |
- bool start_worker; |
- |
- { |
- AutoSchedulerLock auto_lock(lock_); |
- int id = next_worker_id_++; |
- workers_.emplace_back(make_scoped_refptr(new SchedulerWorker( |
- priority_hint, CreateSchedulerWorkerDelegate<DelegateType>(name, id), |
- task_tracker_))); |
- worker = workers_.back().get(); |
- start_worker = started_; |
- } |
+ lock_.AssertAcquired(); |
+ int id = next_worker_id_++; |
+ workers_.emplace_back(make_scoped_refptr(new SchedulerWorker( |
+ priority_hint, CreateSchedulerWorkerDelegate<DelegateType>(name, id), |
+ task_tracker_))); |
+ return workers_.back().get(); |
+} |
- if (start_worker) |
- worker->Start(); |
+template <> |
+SchedulerWorker*& |
+SchedulerSingleThreadTaskRunnerManager::GetSharedSchedulerWorkerForTraits< |
+ SchedulerWorkerDelegate>(const TaskTraits& traits) { |
+ return shared_scheduler_workers_[GetEnvironmentIndexForTraits(traits)]; |
+} |
- return worker; |
+#if defined(OS_WIN) |
+template <> |
+SchedulerWorker*& |
+SchedulerSingleThreadTaskRunnerManager::GetSharedSchedulerWorkerForTraits< |
+ SchedulerWorkerCOMDelegate>(const TaskTraits& traits) { |
+ return shared_com_scheduler_workers_[GetEnvironmentIndexForTraits(traits)]; |
} |
+#endif // defined(OS_WIN) |
void SchedulerSingleThreadTaskRunnerManager::UnregisterSchedulerWorker( |
SchedulerWorker* worker) { |
@@ -492,5 +560,30 @@ void SchedulerSingleThreadTaskRunnerManager::UnregisterSchedulerWorker( |
worker_to_destroy->Cleanup(); |
} |
+void SchedulerSingleThreadTaskRunnerManager::ReleaseSharedSchedulerWorkers() { |
+ decltype(shared_scheduler_workers_) local_shared_scheduler_workers; |
+#if defined(OS_WIN) |
+ decltype(shared_com_scheduler_workers_) local_shared_com_scheduler_workers; |
+#endif |
+ { |
+ AutoSchedulerLock auto_lock(lock_); |
+ for (size_t i = 0; i < arraysize(shared_scheduler_workers_); ++i) { |
+ local_shared_scheduler_workers[i] = shared_scheduler_workers_[i]; |
+#if defined(OS_WIN) |
+ local_shared_com_scheduler_workers[i] = shared_com_scheduler_workers_[i]; |
gab
2017/05/25 18:47:00
Why do we need a local list? Doesn't seem like any
robliao
2017/05/30 20:01:06
The local list is needed to avoid unregistration w
|
+#endif |
+ } |
+ } |
+ |
+ for (size_t i = 0; i < arraysize(local_shared_scheduler_workers); ++i) { |
+ if (local_shared_scheduler_workers[i]) |
+ UnregisterSchedulerWorker(local_shared_scheduler_workers[i]); |
+#if defined(OS_WIN) |
+ if (local_shared_com_scheduler_workers[i]) |
+ UnregisterSchedulerWorker(local_shared_com_scheduler_workers[i]); |
+#endif |
+ } |
+} |
+ |
} // namespace internal |
} // namespace base |