Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: base/task_scheduler/scheduler_single_thread_task_runner_manager.cc

Issue 2902753003: Implement Shared SingleThreadTaskRunners in the Task Scheduler (Closed)
Patch Set: Change Dependent Change Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/task_scheduler/scheduler_single_thread_task_runner_manager.h" 5 #include "base/task_scheduler/scheduler_single_thread_task_runner_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <memory> 8 #include <memory>
9 #include <string> 9 #include <string>
10 #include <utility> 10 #include <utility>
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 } // namespace 239 } // namespace
240 240
241 class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner 241 class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner
242 : public SingleThreadTaskRunner { 242 : public SingleThreadTaskRunner {
243 public: 243 public:
244 // Constructs a SchedulerSingleThreadTaskRunner that indirectly controls the 244 // Constructs a SchedulerSingleThreadTaskRunner that indirectly controls the
245 // lifetime of a dedicated |worker| for |traits|. 245 // lifetime of a dedicated |worker| for |traits|.
246 SchedulerSingleThreadTaskRunner( 246 SchedulerSingleThreadTaskRunner(
247 SchedulerSingleThreadTaskRunnerManager* const outer, 247 SchedulerSingleThreadTaskRunnerManager* const outer,
248 const TaskTraits& traits, 248 const TaskTraits& traits,
249 SchedulerWorker* worker) 249 SchedulerWorker* worker,
250 : outer_(outer), traits_(traits), worker_(worker) { 250 SingleThreadTaskRunnerThreadMode thread_mode)
251 : outer_(outer),
252 traits_(traits),
253 worker_(worker),
254 thread_mode_(thread_mode) {
251 DCHECK(outer_); 255 DCHECK(outer_);
252 DCHECK(worker_); 256 DCHECK(worker_);
253 } 257 }
254 258
255 // SingleThreadTaskRunner: 259 // SingleThreadTaskRunner:
256 bool PostDelayedTask(const tracked_objects::Location& from_here, 260 bool PostDelayedTask(const tracked_objects::Location& from_here,
257 OnceClosure closure, 261 OnceClosure closure,
258 TimeDelta delay) override { 262 TimeDelta delay) override {
259 auto task = MakeUnique<Task>(from_here, std::move(closure), traits_, delay); 263 auto task = MakeUnique<Task>(from_here, std::move(closure), traits_, delay);
260 task->single_thread_task_runner_ref = this; 264 task->single_thread_task_runner_ref = this;
(...skipping 17 matching lines...) Expand all
278 // Tasks are never nested within the task scheduler. 282 // Tasks are never nested within the task scheduler.
279 return PostDelayedTask(from_here, std::move(closure), delay); 283 return PostDelayedTask(from_here, std::move(closure), delay);
280 } 284 }
281 285
282 bool RunsTasksInCurrentSequence() const override { 286 bool RunsTasksInCurrentSequence() const override {
283 return GetDelegate()->RunsTasksInCurrentSequence(); 287 return GetDelegate()->RunsTasksInCurrentSequence();
284 } 288 }
285 289
286 private: 290 private:
287 ~SchedulerSingleThreadTaskRunner() override { 291 ~SchedulerSingleThreadTaskRunner() override {
288 // Note: This will crash if SchedulerSingleThreadTaskRunnerManager is 292 // Only unregister if this is a DEDICATED SingleThreadTaskRunner. SHARED
289 // incorrectly destroyed first in tests (in production the TaskScheduler and 293 // task runner SchedulerWorkers are managed separately as they are reused.
290 // all of its state are intentionally leaked after 294 if (thread_mode_ == SingleThreadTaskRunnerThreadMode::DEDICATED) {
291 // TaskScheduler::Shutdown(). See ~SchedulerSingleThreadTaskRunnerManager() 295 // Note: This will crash if SchedulerSingleThreadTaskRunnerManager is
292 // for more details. 296 // incorrectly destroyed first in tests (in production the TaskScheduler
293 outer_->UnregisterSchedulerWorker(worker_); 297 // and all of its state are intentionally leaked after
298 // TaskScheduler::Shutdown(). See
299 // ~SchedulerSingleThreadTaskRunnerManager() for more details.
300 outer_->UnregisterSchedulerWorker(worker_);
301 }
294 } 302 }
295 303
296 void PostTaskNow(std::unique_ptr<Task> task) { 304 void PostTaskNow(std::unique_ptr<Task> task) {
297 scoped_refptr<Sequence> sequence = GetDelegate()->sequence(); 305 scoped_refptr<Sequence> sequence = GetDelegate()->sequence();
298 // If |sequence| is null, then the thread is effectively gone (either 306 // If |sequence| is null, then the thread is effectively gone (either
299 // shutdown or joined). 307 // shutdown or joined).
300 if (!sequence) 308 if (!sequence)
301 return; 309 return;
302 310
303 const bool sequence_was_empty = sequence->PushTask(std::move(task)); 311 const bool sequence_was_empty = sequence->PushTask(std::move(task));
304 if (sequence_was_empty) { 312 if (sequence_was_empty) {
305 GetDelegate()->ReEnqueueSequence(std::move(sequence)); 313 GetDelegate()->ReEnqueueSequence(std::move(sequence));
306 worker_->WakeUp(); 314 worker_->WakeUp();
307 } 315 }
308 } 316 }
309 317
310 SchedulerWorkerDelegate* GetDelegate() const { 318 SchedulerWorkerDelegate* GetDelegate() const {
311 return static_cast<SchedulerWorkerDelegate*>(worker_->delegate()); 319 return static_cast<SchedulerWorkerDelegate*>(worker_->delegate());
312 } 320 }
313 321
314 SchedulerSingleThreadTaskRunnerManager* const outer_; 322 SchedulerSingleThreadTaskRunnerManager* const outer_;
315 const TaskTraits traits_; 323 const TaskTraits traits_;
316 SchedulerWorker* const worker_; 324 SchedulerWorker* const worker_;
325 const SingleThreadTaskRunnerThreadMode thread_mode_;
317 326
318 DISALLOW_COPY_AND_ASSIGN(SchedulerSingleThreadTaskRunner); 327 DISALLOW_COPY_AND_ASSIGN(SchedulerSingleThreadTaskRunner);
319 }; 328 };
320 329
321 SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunnerManager( 330 SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunnerManager(
322 TaskTracker* task_tracker, 331 TaskTracker* task_tracker,
323 DelayedTaskManager* delayed_task_manager) 332 DelayedTaskManager* delayed_task_manager)
324 : task_tracker_(task_tracker), delayed_task_manager_(delayed_task_manager) { 333 : task_tracker_(task_tracker),
334 delayed_task_manager_(delayed_task_manager),
335 shared_scheduler_workers_ {}
336 #if defined(OS_WIN)
337 ,
338 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.
339 #endif // defined(OS_WIN)
340 {
325 DCHECK(task_tracker_); 341 DCHECK(task_tracker_);
326 DCHECK(delayed_task_manager_); 342 DCHECK(delayed_task_manager_);
343 static_assert(
344 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
345 "The size of |shared_scheduler_workers_| must match ENVIRONMENT_COUNT");
346 #if defined(OS_WIN)
347 static_assert(arraysize(shared_com_scheduler_workers_) ==
348 arraysize(shared_scheduler_workers_),
349 "The size of |shared_com_scheduler_workers_| must match "
350 "|shared_scheduler_workers_|");
351 #endif // defined(OS_WIN)
327 } 352 }
328 353
329 SchedulerSingleThreadTaskRunnerManager:: 354 SchedulerSingleThreadTaskRunnerManager::
330 ~SchedulerSingleThreadTaskRunnerManager() { 355 ~SchedulerSingleThreadTaskRunnerManager() {
331 #if DCHECK_IS_ON() 356 #if DCHECK_IS_ON()
332 size_t workers_unregistered_during_join = 357 size_t workers_unregistered_during_join =
333 subtle::NoBarrier_Load(&workers_unregistered_during_join_); 358 subtle::NoBarrier_Load(&workers_unregistered_during_join_);
334 // Log an ERROR instead of DCHECK'ing as it's often useful to have both the 359 // Log an ERROR instead of DCHECK'ing as it's often useful to have both the
335 // stack trace of this call and the crash stack trace of the upcoming 360 // stack trace of this call and the crash stack trace of the upcoming
336 // out-of-order ~SchedulerSingleThreadTaskRunner() call to know what to flip. 361 // out-of-order ~SchedulerSingleThreadTaskRunner() call to know what to flip.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 // workers are started as they are created. 393 // workers are started as they are created.
369 for (scoped_refptr<SchedulerWorker> worker : workers_to_start) { 394 for (scoped_refptr<SchedulerWorker> worker : workers_to_start) {
370 worker->Start(); 395 worker->Start();
371 worker->WakeUp(); 396 worker->WakeUp();
372 } 397 }
373 } 398 }
374 399
375 scoped_refptr<SingleThreadTaskRunner> 400 scoped_refptr<SingleThreadTaskRunner>
376 SchedulerSingleThreadTaskRunnerManager::CreateSingleThreadTaskRunnerWithTraits( 401 SchedulerSingleThreadTaskRunnerManager::CreateSingleThreadTaskRunnerWithTraits(
377 const std::string& name, 402 const std::string& name,
378 ThreadPriority priority_hint, 403 const TaskTraits& traits,
379 const TaskTraits& traits) { 404 SingleThreadTaskRunnerThreadMode thread_mode) {
380 return CreateSingleThreadTaskRunnerWithDelegate<SchedulerWorkerDelegate>( 405 return CreateTaskRunnerWithTraitsImpl<SchedulerWorkerDelegate>(name, traits,
381 name, priority_hint, traits); 406 thread_mode);
382 } 407 }
383 408
384 #if defined(OS_WIN) 409 #if defined(OS_WIN)
385 scoped_refptr<SingleThreadTaskRunner> 410 scoped_refptr<SingleThreadTaskRunner>
386 SchedulerSingleThreadTaskRunnerManager::CreateCOMSTATaskRunnerWithTraits( 411 SchedulerSingleThreadTaskRunnerManager::CreateCOMSTATaskRunnerWithTraits(
387 const std::string& name, 412 const std::string& name,
388 ThreadPriority priority_hint, 413 const TaskTraits& traits,
389 const TaskTraits& traits) { 414 SingleThreadTaskRunnerThreadMode thread_mode) {
390 return CreateSingleThreadTaskRunnerWithDelegate<SchedulerWorkerCOMDelegate>( 415 return CreateTaskRunnerWithTraitsImpl<SchedulerWorkerCOMDelegate>(
391 name, priority_hint, traits); 416 name, traits, thread_mode);
392 } 417 }
393 #endif // defined(OS_WIN) 418 #endif // defined(OS_WIN)
394 419
420 template <typename DelegateType>
421 scoped_refptr<
422 SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner>
423 SchedulerSingleThreadTaskRunnerManager::CreateTaskRunnerWithTraitsImpl(
424 const std::string& name,
425 const TaskTraits& traits,
426 SingleThreadTaskRunnerThreadMode thread_mode) {
427 DCHECK(thread_mode != SingleThreadTaskRunnerThreadMode::SHARED ||
428 !traits.with_base_sync_primitives())
429 << "Using WithBaseSyncPrimitives() on a shared SingleThreadTaskRunner "
430 "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
431 "SingleThreadTaskRunnerThreadMode::DEDICATED.";
432 // To simplify the code, |dedicated_worker| is a local only variable that
433 // allows the code to treat both the DEDICATED and SHARED cases similarly for
434 // SingleThreadTaskRunnerThreadMode. In DEDICATED, the scoped_refptr is backed
435 // by a local variable and in SHARED, the scoped_refptr is backed by a member
436 // variable.
437 SchedulerWorker* dedicated_worker = nullptr;
438 SchedulerWorker*& worker =
439 thread_mode == SingleThreadTaskRunnerThreadMode::DEDICATED
440 ? dedicated_worker
441 : GetSharedSchedulerWorkerForTraits<DelegateType>(traits);
442 bool new_worker = false;
443 bool started;
444 {
445 AutoSchedulerLock auto_lock(lock_);
446 if (!worker) {
447 const auto& environment_params =
448 kEnvironmentParams[GetEnvironmentIndexForTraits(traits)];
449 std::string processed_name =
450 thread_mode == SingleThreadTaskRunnerThreadMode::DEDICATED
451 ? name + environment_params.name_suffix
452 : "Shared" + name + environment_params.name_suffix;
453 worker = CreateAndRegisterSchedulerWorker<DelegateType>(
454 processed_name, environment_params.priority_hint);
455 new_worker = true;
456 }
457 started = started_;
458 }
459
460 if (new_worker && started)
461 worker->Start();
462
463 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.
464 }
465
395 void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() { 466 void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() {
467 ReleaseSharedSchedulerWorkers();
468
396 decltype(workers_) local_workers; 469 decltype(workers_) local_workers;
397 { 470 {
398 AutoSchedulerLock auto_lock(lock_); 471 AutoSchedulerLock auto_lock(lock_);
399 local_workers = std::move(workers_); 472 local_workers = std::move(workers_);
400 } 473 }
401 474
402 for (const auto& worker : local_workers) 475 for (const auto& worker : local_workers)
403 worker->JoinForTesting(); 476 worker->JoinForTesting();
404 477
405 { 478 {
406 AutoSchedulerLock auto_lock(lock_); 479 AutoSchedulerLock auto_lock(lock_);
407 DCHECK(workers_.empty()) 480 DCHECK(workers_.empty())
408 << "New worker(s) unexpectedly registered during join."; 481 << "New worker(s) unexpectedly registered during join.";
409 workers_ = std::move(local_workers); 482 workers_ = std::move(local_workers);
410 } 483 }
411 } 484 }
412 485
413 template <typename DelegateType>
414 scoped_refptr<SingleThreadTaskRunner> SchedulerSingleThreadTaskRunnerManager::
415 CreateSingleThreadTaskRunnerWithDelegate(const std::string& name,
416 ThreadPriority priority_hint,
417 const TaskTraits& traits) {
418 return new SchedulerSingleThreadTaskRunner(
419 this, traits,
420 CreateAndRegisterSchedulerWorker<DelegateType>(name, priority_hint));
421 }
422
423 template <> 486 template <>
424 std::unique_ptr<SchedulerWorkerDelegate> 487 std::unique_ptr<SchedulerWorkerDelegate>
425 SchedulerSingleThreadTaskRunnerManager::CreateSchedulerWorkerDelegate< 488 SchedulerSingleThreadTaskRunnerManager::CreateSchedulerWorkerDelegate<
426 SchedulerWorkerDelegate>(const std::string& name, int id) { 489 SchedulerWorkerDelegate>(const std::string& name, int id) {
427 return MakeUnique<SchedulerWorkerDelegate>( 490 return MakeUnique<SchedulerWorkerDelegate>(
428 StringPrintf("TaskSchedulerSingleThread%s%d", name.c_str(), id)); 491 StringPrintf("TaskSchedulerSingleThread%s%d", name.c_str(), id));
429 } 492 }
430 493
431 #if defined(OS_WIN) 494 #if defined(OS_WIN)
432 template <> 495 template <>
433 std::unique_ptr<SchedulerWorkerDelegate> 496 std::unique_ptr<SchedulerWorkerDelegate>
434 SchedulerSingleThreadTaskRunnerManager::CreateSchedulerWorkerDelegate< 497 SchedulerSingleThreadTaskRunnerManager::CreateSchedulerWorkerDelegate<
435 SchedulerWorkerCOMDelegate>(const std::string& name, int id) { 498 SchedulerWorkerCOMDelegate>(const std::string& name, int id) {
436 return MakeUnique<SchedulerWorkerCOMDelegate>( 499 return MakeUnique<SchedulerWorkerCOMDelegate>(
437 StringPrintf("TaskSchedulerSingleThreadCOMSTA%s%d", name.c_str(), id), 500 StringPrintf("TaskSchedulerSingleThreadCOMSTA%s%d", name.c_str(), id),
438 task_tracker_); 501 task_tracker_);
439 } 502 }
440 #endif // defined(OS_WIN) 503 #endif // defined(OS_WIN)
441 504
442 template <typename DelegateType> 505 template <typename DelegateType>
443 SchedulerWorker* 506 SchedulerWorker*
444 SchedulerSingleThreadTaskRunnerManager::CreateAndRegisterSchedulerWorker( 507 SchedulerSingleThreadTaskRunnerManager::CreateAndRegisterSchedulerWorker(
445 const std::string& name, 508 const std::string& name,
446 ThreadPriority priority_hint) { 509 ThreadPriority priority_hint) {
447 SchedulerWorker* worker; 510 lock_.AssertAcquired();
448 bool start_worker; 511 int id = next_worker_id_++;
512 workers_.emplace_back(make_scoped_refptr(new SchedulerWorker(
513 priority_hint, CreateSchedulerWorkerDelegate<DelegateType>(name, id),
514 task_tracker_)));
515 return workers_.back().get();
516 }
449 517
450 { 518 template <>
451 AutoSchedulerLock auto_lock(lock_); 519 SchedulerWorker*&
452 int id = next_worker_id_++; 520 SchedulerSingleThreadTaskRunnerManager::GetSharedSchedulerWorkerForTraits<
453 workers_.emplace_back(make_scoped_refptr(new SchedulerWorker( 521 SchedulerWorkerDelegate>(const TaskTraits& traits) {
454 priority_hint, CreateSchedulerWorkerDelegate<DelegateType>(name, id), 522 return shared_scheduler_workers_[GetEnvironmentIndexForTraits(traits)];
455 task_tracker_))); 523 }
456 worker = workers_.back().get();
457 start_worker = started_;
458 }
459 524
460 if (start_worker) 525 #if defined(OS_WIN)
461 worker->Start(); 526 template <>
462 527 SchedulerWorker*&
463 return worker; 528 SchedulerSingleThreadTaskRunnerManager::GetSharedSchedulerWorkerForTraits<
529 SchedulerWorkerCOMDelegate>(const TaskTraits& traits) {
530 return shared_com_scheduler_workers_[GetEnvironmentIndexForTraits(traits)];
464 } 531 }
532 #endif // defined(OS_WIN)
465 533
466 void SchedulerSingleThreadTaskRunnerManager::UnregisterSchedulerWorker( 534 void SchedulerSingleThreadTaskRunnerManager::UnregisterSchedulerWorker(
467 SchedulerWorker* worker) { 535 SchedulerWorker* worker) {
468 // Cleanup uses a SchedulerLock, so call Cleanup() after releasing 536 // Cleanup uses a SchedulerLock, so call Cleanup() after releasing
469 // |lock_|. 537 // |lock_|.
470 scoped_refptr<SchedulerWorker> worker_to_destroy; 538 scoped_refptr<SchedulerWorker> worker_to_destroy;
471 { 539 {
472 AutoSchedulerLock auto_lock(lock_); 540 AutoSchedulerLock auto_lock(lock_);
473 541
474 // We might be joining, so record that a worker was unregistered for 542 // We might be joining, so record that a worker was unregistered for
(...skipping 10 matching lines...) Expand all
485 [worker](const scoped_refptr<SchedulerWorker>& candidate) { 553 [worker](const scoped_refptr<SchedulerWorker>& candidate) {
486 return candidate.get() == worker; 554 return candidate.get() == worker;
487 }); 555 });
488 DCHECK(worker_iter != workers_.end()); 556 DCHECK(worker_iter != workers_.end());
489 worker_to_destroy = std::move(*worker_iter); 557 worker_to_destroy = std::move(*worker_iter);
490 workers_.erase(worker_iter); 558 workers_.erase(worker_iter);
491 } 559 }
492 worker_to_destroy->Cleanup(); 560 worker_to_destroy->Cleanup();
493 } 561 }
494 562
563 void SchedulerSingleThreadTaskRunnerManager::ReleaseSharedSchedulerWorkers() {
564 decltype(shared_scheduler_workers_) local_shared_scheduler_workers;
565 #if defined(OS_WIN)
566 decltype(shared_com_scheduler_workers_) local_shared_com_scheduler_workers;
567 #endif
568 {
569 AutoSchedulerLock auto_lock(lock_);
570 for (size_t i = 0; i < arraysize(shared_scheduler_workers_); ++i) {
571 local_shared_scheduler_workers[i] = shared_scheduler_workers_[i];
572 #if defined(OS_WIN)
573 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
574 #endif
575 }
576 }
577
578 for (size_t i = 0; i < arraysize(local_shared_scheduler_workers); ++i) {
579 if (local_shared_scheduler_workers[i])
580 UnregisterSchedulerWorker(local_shared_scheduler_workers[i]);
581 #if defined(OS_WIN)
582 if (local_shared_com_scheduler_workers[i])
583 UnregisterSchedulerWorker(local_shared_com_scheduler_workers[i]);
584 #endif
585 }
586 }
587
495 } // namespace internal 588 } // namespace internal
496 } // namespace base 589 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698