Chromium Code Reviews| 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 721e1daf76dc56d86959378db34ed561194fe84b..b39c95ab6ae3ea6dad4a66a819a8d7431677ed44 100644 |
| --- a/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc |
| +++ b/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc |
| @@ -11,6 +11,7 @@ |
| #include "base/bind.h" |
| #include "base/callback.h" |
| +#include "base/debug/stack_trace.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/stringprintf.h" |
| @@ -284,6 +285,11 @@ 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_); |
| } |
| @@ -325,10 +331,29 @@ SchedulerSingleThreadTaskRunnerManager:: |
| #if DCHECK_IS_ON() |
| size_t workers_unregistered_during_join = |
| subtle::NoBarrier_Load(&workers_unregistered_during_join_); |
| - DCHECK_EQ(workers_unregistered_during_join, workers_.size()) |
| - << "There cannot be outstanding SingleThreadTaskRunners upon destruction " |
| - "of SchedulerSingleThreadTaskRunnerManager or the Task Scheduler"; |
| -#endif |
| + // Log an ERROR instead of DCHECK'ing as it's often useful to have both the |
| + // stack trace of this call and the crash stack trace of the upcoming |
| + // out-of-order ~SchedulerSingleThreadTaskRunner() call to know what to flip. |
| + DLOG_IF(ERROR, workers_unregistered_during_join != workers_.size()) |
| + << "Expect incoming crash in ~SchedulerSingleThreadTaskRunner()!!! There " |
| + "cannot be outstanding SingleThreadTaskRunners upon destruction " |
| + "of SchedulerSingleThreadTaskRunnerManager in tests " |
| + << workers_.size() - workers_unregistered_during_join << " outstanding). " |
| + << "Hint 1: If you're hitting this it's most likely because your test " |
| + "fixture is destroying its TaskScheduler too early (e.g. via " |
| + "base::test::~ScopedTaskEnvironment() or " |
| + "content::~TestBrowserThreadBundle()). Refer to the following stack " |
| + "trace to know what caused this destruction as well as to the " |
| + "upcoming crash in ~SchedulerSingleThreadTaskRunner() to know what " |
| + "should have happened before. " |
| + "Hint 2: base::test::ScopedTaskEnvironment et al. should typically " |
| + "be the first member in a test fixture to ensure it's initialized " |
| + "first and destroyed last.\n" |
|
Avi (use Gerrit)
2017/05/04 23:10:44
Awesome error!
|
| +#if !defined(OS_NACL) // We don't build base/debug/stack_trace.cc for NaCl. |
| + << base::debug::StackTrace().ToString() |
| +#endif // !defined(OS_NACL) |
| + ; |
| +#endif // DCHECK_IS_ON() |
| } |
| void SchedulerSingleThreadTaskRunnerManager::Start() { |