OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |