xref: /aosp_15_r20/external/libchrome/base/task_scheduler/task_scheduler_impl_unittest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/task_scheduler/task_scheduler_impl.h"
6 
7 #include <stddef.h>
8 
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/callback.h"
16 #include "base/cfi_buildflags.h"
17 #include "base/debug/stack_trace.h"
18 #include "base/macros.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/metrics/field_trial.h"
21 #include "base/metrics/field_trial_params.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "base/task_scheduler/environment_config.h"
24 #include "base/task_scheduler/scheduler_worker_observer.h"
25 #include "base/task_scheduler/scheduler_worker_pool_params.h"
26 #include "base/task_scheduler/task_traits.h"
27 #include "base/task_scheduler/test_task_factory.h"
28 #include "base/task_scheduler/test_utils.h"
29 #include "base/test/gtest_util.h"
30 #include "base/test/test_timeouts.h"
31 #include "base/threading/platform_thread.h"
32 #include "base/threading/sequence_local_storage_slot.h"
33 #include "base/threading/simple_thread.h"
34 #include "base/threading/thread.h"
35 #include "base/threading/thread_restrictions.h"
36 #include "base/time/time.h"
37 #include "build/build_config.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 
40 #if defined(OS_POSIX)
41 #include <unistd.h>
42 
43 #include "base/debug/leak_annotations.h"
44 #include "base/files/file_descriptor_watcher_posix.h"
45 #include "base/files/file_util.h"
46 #include "base/posix/eintr_wrapper.h"
47 #endif  // defined(OS_POSIX)
48 
49 #if defined(OS_WIN)
50 #include "base/win/com_init_util.h"
51 #endif  // defined(OS_WIN)
52 
53 namespace base {
54 namespace internal {
55 
56 namespace {
57 
58 struct TraitsExecutionModePair {
TraitsExecutionModePairbase::internal::__anon315c264a0111::TraitsExecutionModePair59   TraitsExecutionModePair(const TaskTraits& traits,
60                           test::ExecutionMode execution_mode)
61       : traits(traits), execution_mode(execution_mode) {}
62 
63   TaskTraits traits;
64   test::ExecutionMode execution_mode;
65 };
66 
67 #if DCHECK_IS_ON()
68 // Returns whether I/O calls are allowed on the current thread.
GetIOAllowed()69 bool GetIOAllowed() {
70   const bool previous_value = ThreadRestrictions::SetIOAllowed(true);
71   ThreadRestrictions::SetIOAllowed(previous_value);
72   return previous_value;
73 }
74 #endif
75 
76 // Verify that the current thread priority and I/O restrictions are appropriate
77 // to run a Task with |traits|.
78 // Note: ExecutionMode is verified inside TestTaskFactory.
VerifyTaskEnvironment(const TaskTraits & traits)79 void VerifyTaskEnvironment(const TaskTraits& traits) {
80   EXPECT_EQ(CanUseBackgroundPriorityForSchedulerWorker() &&
81                     traits.priority() == TaskPriority::BACKGROUND
82                 ? ThreadPriority::BACKGROUND
83                 : ThreadPriority::NORMAL,
84             PlatformThread::GetCurrentThreadPriority());
85 
86 #if DCHECK_IS_ON()
87   // The #if above is required because GetIOAllowed() always returns true when
88   // !DCHECK_IS_ON(), even when |traits| don't allow file I/O.
89   EXPECT_EQ(traits.may_block(), GetIOAllowed());
90 #endif
91 
92   // Verify that the thread the task is running on is named as expected.
93   const std::string current_thread_name(PlatformThread::GetName());
94   EXPECT_NE(std::string::npos, current_thread_name.find("TaskScheduler"));
95 
96   if (current_thread_name.find("SingleThread") != std::string::npos) {
97     // For now, single-threaded background tasks run on their own threads.
98     // TODO(fdoray): Run single-threaded background tasks on foreground workers
99     // on platforms that don't support background thread priority.
100     EXPECT_NE(
101         std::string::npos,
102         current_thread_name.find(traits.priority() == TaskPriority::BACKGROUND
103                                      ? "Background"
104                                      : "Foreground"));
105   } else {
106     EXPECT_NE(std::string::npos,
107               current_thread_name.find(
108                   CanUseBackgroundPriorityForSchedulerWorker() &&
109                           traits.priority() == TaskPriority::BACKGROUND
110                       ? "Background"
111                       : "Foreground"));
112   }
113   EXPECT_EQ(traits.may_block(),
114             current_thread_name.find("Blocking") != std::string::npos);
115 }
116 
VerifyTaskEnvironmentAndSignalEvent(const TaskTraits & traits,WaitableEvent * event)117 void VerifyTaskEnvironmentAndSignalEvent(const TaskTraits& traits,
118                                          WaitableEvent* event) {
119   DCHECK(event);
120   VerifyTaskEnvironment(traits);
121   event->Signal();
122 }
123 
VerifyTimeAndTaskEnvironmentAndSignalEvent(const TaskTraits & traits,TimeTicks expected_time,WaitableEvent * event)124 void VerifyTimeAndTaskEnvironmentAndSignalEvent(const TaskTraits& traits,
125                                                 TimeTicks expected_time,
126                                                 WaitableEvent* event) {
127   DCHECK(event);
128   EXPECT_LE(expected_time, TimeTicks::Now());
129   VerifyTaskEnvironment(traits);
130   event->Signal();
131 }
132 
CreateTaskRunnerWithTraitsAndExecutionMode(TaskScheduler * scheduler,const TaskTraits & traits,test::ExecutionMode execution_mode,SingleThreadTaskRunnerThreadMode default_single_thread_task_runner_mode=SingleThreadTaskRunnerThreadMode::SHARED)133 scoped_refptr<TaskRunner> CreateTaskRunnerWithTraitsAndExecutionMode(
134     TaskScheduler* scheduler,
135     const TaskTraits& traits,
136     test::ExecutionMode execution_mode,
137     SingleThreadTaskRunnerThreadMode default_single_thread_task_runner_mode =
138         SingleThreadTaskRunnerThreadMode::SHARED) {
139   switch (execution_mode) {
140     case test::ExecutionMode::PARALLEL:
141       return scheduler->CreateTaskRunnerWithTraits(traits);
142     case test::ExecutionMode::SEQUENCED:
143       return scheduler->CreateSequencedTaskRunnerWithTraits(traits);
144     case test::ExecutionMode::SINGLE_THREADED: {
145       return scheduler->CreateSingleThreadTaskRunnerWithTraits(
146           traits, default_single_thread_task_runner_mode);
147     }
148   }
149   ADD_FAILURE() << "Unknown ExecutionMode";
150   return nullptr;
151 }
152 
153 class ThreadPostingTasks : public SimpleThread {
154  public:
155   // Creates a thread that posts Tasks to |scheduler| with |traits| and
156   // |execution_mode|.
ThreadPostingTasks(TaskSchedulerImpl * scheduler,const TaskTraits & traits,test::ExecutionMode execution_mode)157   ThreadPostingTasks(TaskSchedulerImpl* scheduler,
158                      const TaskTraits& traits,
159                      test::ExecutionMode execution_mode)
160       : SimpleThread("ThreadPostingTasks"),
161         traits_(traits),
162         factory_(CreateTaskRunnerWithTraitsAndExecutionMode(scheduler,
163                                                             traits,
164                                                             execution_mode),
165                  execution_mode) {}
166 
WaitForAllTasksToRun()167   void WaitForAllTasksToRun() { factory_.WaitForAllTasksToRun(); }
168 
169  private:
Run()170   void Run() override {
171     EXPECT_FALSE(factory_.task_runner()->RunsTasksInCurrentSequence());
172 
173     const size_t kNumTasksPerThread = 150;
174     for (size_t i = 0; i < kNumTasksPerThread; ++i) {
175       factory_.PostTask(test::TestTaskFactory::PostNestedTask::NO,
176                         Bind(&VerifyTaskEnvironment, traits_));
177     }
178   }
179 
180   const TaskTraits traits_;
181   test::TestTaskFactory factory_;
182 
183   DISALLOW_COPY_AND_ASSIGN(ThreadPostingTasks);
184 };
185 
186 // Returns a vector with a TraitsExecutionModePair for each valid
187 // combination of {ExecutionMode, TaskPriority, MayBlock()}.
GetTraitsExecutionModePairs()188 std::vector<TraitsExecutionModePair> GetTraitsExecutionModePairs() {
189   std::vector<TraitsExecutionModePair> params;
190 
191   const test::ExecutionMode execution_modes[] = {
192       test::ExecutionMode::PARALLEL, test::ExecutionMode::SEQUENCED,
193       test::ExecutionMode::SINGLE_THREADED};
194 
195   for (test::ExecutionMode execution_mode : execution_modes) {
196     for (size_t priority_index = static_cast<size_t>(TaskPriority::LOWEST);
197          priority_index <= static_cast<size_t>(TaskPriority::HIGHEST);
198          ++priority_index) {
199       const TaskPriority priority = static_cast<TaskPriority>(priority_index);
200       params.push_back(TraitsExecutionModePair({priority}, execution_mode));
201       params.push_back(TraitsExecutionModePair({MayBlock()}, execution_mode));
202     }
203   }
204 
205   return params;
206 }
207 
208 class TaskSchedulerImplTest
209     : public testing::TestWithParam<TraitsExecutionModePair> {
210  protected:
TaskSchedulerImplTest()211   TaskSchedulerImplTest() : scheduler_("Test"), field_trial_list_(nullptr) {}
212 
EnableAllTasksUserBlocking()213   void EnableAllTasksUserBlocking() {
214     constexpr char kFieldTrialName[] = "BrowserScheduler";
215     constexpr char kFieldTrialTestGroup[] = "DummyGroup";
216     std::map<std::string, std::string> variation_params;
217     variation_params["AllTasksUserBlocking"] = "true";
218     base::AssociateFieldTrialParams(kFieldTrialName, kFieldTrialTestGroup,
219                                     variation_params);
220     base::FieldTrialList::CreateFieldTrial(kFieldTrialName,
221                                            kFieldTrialTestGroup);
222   }
223 
set_scheduler_worker_observer(SchedulerWorkerObserver * scheduler_worker_observer)224   void set_scheduler_worker_observer(
225       SchedulerWorkerObserver* scheduler_worker_observer) {
226     scheduler_worker_observer_ = scheduler_worker_observer;
227   }
228 
StartTaskScheduler()229   void StartTaskScheduler() {
230     constexpr TimeDelta kSuggestedReclaimTime = TimeDelta::FromSeconds(30);
231     constexpr int kMaxNumBackgroundThreads = 1;
232     constexpr int kMaxNumBackgroundBlockingThreads = 3;
233     constexpr int kMaxNumForegroundThreads = 4;
234     constexpr int kMaxNumForegroundBlockingThreads = 12;
235 
236     scheduler_.Start(
237         {{kMaxNumBackgroundThreads, kSuggestedReclaimTime},
238          {kMaxNumBackgroundBlockingThreads, kSuggestedReclaimTime},
239          {kMaxNumForegroundThreads, kSuggestedReclaimTime},
240          {kMaxNumForegroundBlockingThreads, kSuggestedReclaimTime}},
241         scheduler_worker_observer_);
242   }
243 
TearDown()244   void TearDown() override {
245     if (did_tear_down_)
246       return;
247 
248     scheduler_.FlushForTesting();
249     scheduler_.JoinForTesting();
250     did_tear_down_ = true;
251   }
252 
253   TaskSchedulerImpl scheduler_;
254 
255  private:
256   base::FieldTrialList field_trial_list_;
257   SchedulerWorkerObserver* scheduler_worker_observer_ = nullptr;
258   bool did_tear_down_ = false;
259 
260   DISALLOW_COPY_AND_ASSIGN(TaskSchedulerImplTest);
261 };
262 
263 }  // namespace
264 
265 // Verifies that a Task posted via PostDelayedTaskWithTraits with parameterized
266 // TaskTraits and no delay runs on a thread with the expected priority and I/O
267 // restrictions. The ExecutionMode parameter is ignored by this test.
TEST_P(TaskSchedulerImplTest,PostDelayedTaskWithTraitsNoDelay)268 TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsNoDelay) {
269   StartTaskScheduler();
270   WaitableEvent task_ran;
271   scheduler_.PostDelayedTaskWithTraits(
272       FROM_HERE, GetParam().traits,
273       BindOnce(&VerifyTaskEnvironmentAndSignalEvent, GetParam().traits,
274                Unretained(&task_ran)),
275       TimeDelta());
276   task_ran.Wait();
277 }
278 
279 // Verifies that a Task posted via PostDelayedTaskWithTraits with parameterized
280 // TaskTraits and a non-zero delay runs on a thread with the expected priority
281 // and I/O restrictions after the delay expires. The ExecutionMode parameter is
282 // ignored by this test.
TEST_P(TaskSchedulerImplTest,PostDelayedTaskWithTraitsWithDelay)283 TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsWithDelay) {
284   StartTaskScheduler();
285   WaitableEvent task_ran;
286   scheduler_.PostDelayedTaskWithTraits(
287       FROM_HERE, GetParam().traits,
288       BindOnce(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetParam().traits,
289                TimeTicks::Now() + TestTimeouts::tiny_timeout(),
290                Unretained(&task_ran)),
291       TestTimeouts::tiny_timeout());
292   task_ran.Wait();
293 }
294 
295 // Verifies that Tasks posted via a TaskRunner with parameterized TaskTraits and
296 // ExecutionMode run on a thread with the expected priority and I/O restrictions
297 // and respect the characteristics of their ExecutionMode.
TEST_P(TaskSchedulerImplTest,PostTasksViaTaskRunner)298 TEST_P(TaskSchedulerImplTest, PostTasksViaTaskRunner) {
299   StartTaskScheduler();
300   test::TestTaskFactory factory(
301       CreateTaskRunnerWithTraitsAndExecutionMode(&scheduler_, GetParam().traits,
302                                                  GetParam().execution_mode),
303       GetParam().execution_mode);
304   EXPECT_FALSE(factory.task_runner()->RunsTasksInCurrentSequence());
305 
306   const size_t kNumTasksPerTest = 150;
307   for (size_t i = 0; i < kNumTasksPerTest; ++i) {
308     factory.PostTask(test::TestTaskFactory::PostNestedTask::NO,
309                      Bind(&VerifyTaskEnvironment, GetParam().traits));
310   }
311 
312   factory.WaitForAllTasksToRun();
313 }
314 
315 // Verifies that a task posted via PostDelayedTaskWithTraits without a delay
316 // doesn't run before Start() is called.
TEST_P(TaskSchedulerImplTest,PostDelayedTaskWithTraitsNoDelayBeforeStart)317 TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsNoDelayBeforeStart) {
318   WaitableEvent task_running;
319   scheduler_.PostDelayedTaskWithTraits(
320       FROM_HERE, GetParam().traits,
321       BindOnce(&VerifyTaskEnvironmentAndSignalEvent, GetParam().traits,
322                Unretained(&task_running)),
323       TimeDelta());
324 
325   // Wait a little bit to make sure that the task doesn't run before Start().
326   // Note: This test won't catch a case where the task runs just after the check
327   // and before Start(). However, we expect the test to be flaky if the tested
328   // code allows that to happen.
329   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
330   EXPECT_FALSE(task_running.IsSignaled());
331 
332   StartTaskScheduler();
333   task_running.Wait();
334 }
335 
336 // Verifies that a task posted via PostDelayedTaskWithTraits with a delay
337 // doesn't run before Start() is called.
TEST_P(TaskSchedulerImplTest,PostDelayedTaskWithTraitsWithDelayBeforeStart)338 TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsWithDelayBeforeStart) {
339   WaitableEvent task_running;
340   scheduler_.PostDelayedTaskWithTraits(
341       FROM_HERE, GetParam().traits,
342       BindOnce(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetParam().traits,
343                TimeTicks::Now() + TestTimeouts::tiny_timeout(),
344                Unretained(&task_running)),
345       TestTimeouts::tiny_timeout());
346 
347   // Wait a little bit to make sure that the task doesn't run before Start().
348   // Note: This test won't catch a case where the task runs just after the check
349   // and before Start(). However, we expect the test to be flaky if the tested
350   // code allows that to happen.
351   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
352   EXPECT_FALSE(task_running.IsSignaled());
353 
354   StartTaskScheduler();
355   task_running.Wait();
356 }
357 
358 // Verifies that a task posted via a TaskRunner doesn't run before Start() is
359 // called.
TEST_P(TaskSchedulerImplTest,PostTaskViaTaskRunnerBeforeStart)360 TEST_P(TaskSchedulerImplTest, PostTaskViaTaskRunnerBeforeStart) {
361   WaitableEvent task_running;
362   CreateTaskRunnerWithTraitsAndExecutionMode(&scheduler_, GetParam().traits,
363                                              GetParam().execution_mode)
364       ->PostTask(FROM_HERE,
365                  BindOnce(&VerifyTaskEnvironmentAndSignalEvent,
366                           GetParam().traits, Unretained(&task_running)));
367 
368   // Wait a little bit to make sure that the task doesn't run before Start().
369   // Note: This test won't catch a case where the task runs just after the check
370   // and before Start(). However, we expect the test to be flaky if the tested
371   // code allows that to happen.
372   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
373   EXPECT_FALSE(task_running.IsSignaled());
374 
375   StartTaskScheduler();
376 
377   // This should not hang if the task runs after Start().
378   task_running.Wait();
379 }
380 
381 // Verify that all tasks posted to a TaskRunner after Start() run in a
382 // USER_BLOCKING environment when the AllTasksUserBlocking variation param of
383 // the BrowserScheduler experiment is true.
TEST_P(TaskSchedulerImplTest,AllTasksAreUserBlockingTaskRunner)384 TEST_P(TaskSchedulerImplTest, AllTasksAreUserBlockingTaskRunner) {
385   EnableAllTasksUserBlocking();
386   StartTaskScheduler();
387 
388   WaitableEvent task_running;
389   CreateTaskRunnerWithTraitsAndExecutionMode(&scheduler_, GetParam().traits,
390                                              GetParam().execution_mode)
391       ->PostTask(FROM_HERE,
392                  BindOnce(&VerifyTaskEnvironmentAndSignalEvent,
393                           TaskTraits::Override(GetParam().traits,
394                                                {TaskPriority::USER_BLOCKING}),
395                           Unretained(&task_running)));
396   task_running.Wait();
397 }
398 
399 // Verify that all tasks posted via PostDelayedTaskWithTraits() after Start()
400 // run in a USER_BLOCKING environment when the AllTasksUserBlocking variation
401 // param of the BrowserScheduler experiment is true.
TEST_P(TaskSchedulerImplTest,AllTasksAreUserBlocking)402 TEST_P(TaskSchedulerImplTest, AllTasksAreUserBlocking) {
403   EnableAllTasksUserBlocking();
404   StartTaskScheduler();
405 
406   WaitableEvent task_running;
407   // Ignore |params.execution_mode| in this test.
408   scheduler_.PostDelayedTaskWithTraits(
409       FROM_HERE, GetParam().traits,
410       BindOnce(&VerifyTaskEnvironmentAndSignalEvent,
411                TaskTraits::Override(GetParam().traits,
412                                     {TaskPriority::USER_BLOCKING}),
413                Unretained(&task_running)),
414       TimeDelta());
415   task_running.Wait();
416 }
417 
418 // Verifies that FlushAsyncForTesting() calls back correctly for all trait and
419 // execution mode pairs.
TEST_P(TaskSchedulerImplTest,FlushAsyncForTestingSimple)420 TEST_P(TaskSchedulerImplTest, FlushAsyncForTestingSimple) {
421   StartTaskScheduler();
422 
423   WaitableEvent unblock_task;
424   CreateTaskRunnerWithTraitsAndExecutionMode(
425       &scheduler_,
426       TaskTraits::Override(GetParam().traits, {WithBaseSyncPrimitives()}),
427       GetParam().execution_mode, SingleThreadTaskRunnerThreadMode::DEDICATED)
428       ->PostTask(FROM_HERE,
429                  BindOnce(&WaitableEvent::Wait, Unretained(&unblock_task)));
430 
431   WaitableEvent flush_event;
432   scheduler_.FlushAsyncForTesting(
433       BindOnce(&WaitableEvent::Signal, Unretained(&flush_event)));
434   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
435   EXPECT_FALSE(flush_event.IsSignaled());
436 
437   unblock_task.Signal();
438 
439   flush_event.Wait();
440 }
441 
442 INSTANTIATE_TEST_CASE_P(OneTraitsExecutionModePair,
443                         TaskSchedulerImplTest,
444                         ::testing::ValuesIn(GetTraitsExecutionModePairs()));
445 
446 // Spawns threads that simultaneously post Tasks to TaskRunners with various
447 // TaskTraits and ExecutionModes. Verifies that each Task runs on a thread with
448 // the expected priority and I/O restrictions and respects the characteristics
449 // of its ExecutionMode.
TEST_F(TaskSchedulerImplTest,MultipleTraitsExecutionModePairs)450 TEST_F(TaskSchedulerImplTest, MultipleTraitsExecutionModePairs) {
451   StartTaskScheduler();
452   std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks;
453   for (const auto& traits_execution_mode_pair : GetTraitsExecutionModePairs()) {
454     threads_posting_tasks.push_back(WrapUnique(
455         new ThreadPostingTasks(&scheduler_, traits_execution_mode_pair.traits,
456                                traits_execution_mode_pair.execution_mode)));
457     threads_posting_tasks.back()->Start();
458   }
459 
460   for (const auto& thread : threads_posting_tasks) {
461     thread->WaitForAllTasksToRun();
462     thread->Join();
463   }
464 }
465 
TEST_F(TaskSchedulerImplTest,GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated)466 TEST_F(TaskSchedulerImplTest,
467        GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated) {
468   StartTaskScheduler();
469 
470   // GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated() does not support
471   // TaskPriority::BACKGROUND.
472   EXPECT_DCHECK_DEATH({
473     scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
474         {TaskPriority::BACKGROUND});
475   });
476   EXPECT_DCHECK_DEATH({
477     scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
478         {MayBlock(), TaskPriority::BACKGROUND});
479   });
480 
481   EXPECT_EQ(4, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
482                    {TaskPriority::USER_VISIBLE}));
483   EXPECT_EQ(12, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
484                     {MayBlock(), TaskPriority::USER_VISIBLE}));
485   EXPECT_EQ(4, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
486                    {TaskPriority::USER_BLOCKING}));
487   EXPECT_EQ(12, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
488                     {MayBlock(), TaskPriority::USER_BLOCKING}));
489 }
490 
491 // Verify that the RunsTasksInCurrentSequence() method of a SequencedTaskRunner
492 // returns false when called from a task that isn't part of the sequence.
TEST_F(TaskSchedulerImplTest,SequencedRunsTasksInCurrentSequence)493 TEST_F(TaskSchedulerImplTest, SequencedRunsTasksInCurrentSequence) {
494   StartTaskScheduler();
495   auto single_thread_task_runner =
496       scheduler_.CreateSingleThreadTaskRunnerWithTraits(
497           TaskTraits(), SingleThreadTaskRunnerThreadMode::SHARED);
498   auto sequenced_task_runner =
499       scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits());
500 
501   WaitableEvent task_ran;
502   single_thread_task_runner->PostTask(
503       FROM_HERE,
504       BindOnce(
505           [](scoped_refptr<TaskRunner> sequenced_task_runner,
506              WaitableEvent* task_ran) {
507             EXPECT_FALSE(sequenced_task_runner->RunsTasksInCurrentSequence());
508             task_ran->Signal();
509           },
510           sequenced_task_runner, Unretained(&task_ran)));
511   task_ran.Wait();
512 }
513 
514 // Verify that the RunsTasksInCurrentSequence() method of a
515 // SingleThreadTaskRunner returns false when called from a task that isn't part
516 // of the sequence.
TEST_F(TaskSchedulerImplTest,SingleThreadRunsTasksInCurrentSequence)517 TEST_F(TaskSchedulerImplTest, SingleThreadRunsTasksInCurrentSequence) {
518   StartTaskScheduler();
519   auto sequenced_task_runner =
520       scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits());
521   auto single_thread_task_runner =
522       scheduler_.CreateSingleThreadTaskRunnerWithTraits(
523           TaskTraits(), SingleThreadTaskRunnerThreadMode::SHARED);
524 
525   WaitableEvent task_ran;
526   sequenced_task_runner->PostTask(
527       FROM_HERE,
528       BindOnce(
529           [](scoped_refptr<TaskRunner> single_thread_task_runner,
530              WaitableEvent* task_ran) {
531             EXPECT_FALSE(
532                 single_thread_task_runner->RunsTasksInCurrentSequence());
533             task_ran->Signal();
534           },
535           single_thread_task_runner, Unretained(&task_ran)));
536   task_ran.Wait();
537 }
538 
539 #if defined(OS_WIN)
TEST_F(TaskSchedulerImplTest,COMSTATaskRunnersRunWithCOMSTA)540 TEST_F(TaskSchedulerImplTest, COMSTATaskRunnersRunWithCOMSTA) {
541   StartTaskScheduler();
542   auto com_sta_task_runner = scheduler_.CreateCOMSTATaskRunnerWithTraits(
543       TaskTraits(), SingleThreadTaskRunnerThreadMode::SHARED);
544 
545   WaitableEvent task_ran;
546   com_sta_task_runner->PostTask(
547       FROM_HERE, Bind(
548                      [](WaitableEvent* task_ran) {
549                        win::AssertComApartmentType(win::ComApartmentType::STA);
550                        task_ran->Signal();
551                      },
552                      Unretained(&task_ran)));
553   task_ran.Wait();
554 }
555 #endif  // defined(OS_WIN)
556 
TEST_F(TaskSchedulerImplTest,DelayedTasksNotRunAfterShutdown)557 TEST_F(TaskSchedulerImplTest, DelayedTasksNotRunAfterShutdown) {
558   StartTaskScheduler();
559   // As with delayed tasks in general, this is racy. If the task does happen to
560   // run after Shutdown within the timeout, it will fail this test.
561   //
562   // The timeout should be set sufficiently long enough to ensure that the
563   // delayed task did not run. 2x is generally good enough.
564   //
565   // A non-racy way to do this would be to post two sequenced tasks:
566   // 1) Regular Post Task: A WaitableEvent.Wait
567   // 2) Delayed Task: ADD_FAILURE()
568   // and signalling the WaitableEvent after Shutdown() on a different thread
569   // since Shutdown() will block. However, the cost of managing this extra
570   // thread was deemed to be too great for the unlikely race.
571   scheduler_.PostDelayedTaskWithTraits(FROM_HERE, TaskTraits(),
572                                        BindOnce([]() { ADD_FAILURE(); }),
573                                        TestTimeouts::tiny_timeout());
574   scheduler_.Shutdown();
575   PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 2);
576 }
577 
578 #if defined(OS_POSIX)
579 
TEST_F(TaskSchedulerImplTest,FileDescriptorWatcherNoOpsAfterShutdown)580 TEST_F(TaskSchedulerImplTest, FileDescriptorWatcherNoOpsAfterShutdown) {
581   StartTaskScheduler();
582 
583   int pipes[2];
584   ASSERT_EQ(0, pipe(pipes));
585 
586   scoped_refptr<TaskRunner> blocking_task_runner =
587       scheduler_.CreateSequencedTaskRunnerWithTraits(
588           {TaskShutdownBehavior::BLOCK_SHUTDOWN});
589   blocking_task_runner->PostTask(
590       FROM_HERE,
591       BindOnce(
592           [](int read_fd) {
593             std::unique_ptr<FileDescriptorWatcher::Controller> controller =
594                 FileDescriptorWatcher::WatchReadable(
595                     read_fd, BindRepeating([]() { NOTREACHED(); }));
596 
597             // This test is for components that intentionally leak their
598             // watchers at shutdown. We can't clean |controller| up because its
599             // destructor will assert that it's being called from the correct
600             // sequence. After the task scheduler is shutdown, it is not
601             // possible to run tasks on this sequence.
602             //
603             // Note: Do not inline the controller.release() call into the
604             //       ANNOTATE_LEAKING_OBJECT_PTR as the annotation is removed
605             //       by the preprocessor in non-LEAK_SANITIZER builds,
606             //       effectively breaking this test.
607             ANNOTATE_LEAKING_OBJECT_PTR(controller.get());
608             controller.release();
609           },
610           pipes[0]));
611 
612   scheduler_.Shutdown();
613 
614   constexpr char kByte = '!';
615   ASSERT_TRUE(WriteFileDescriptor(pipes[1], &kByte, sizeof(kByte)));
616 
617   // Give a chance for the file watcher to fire before closing the handles.
618   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
619 
620   EXPECT_EQ(0, IGNORE_EINTR(close(pipes[0])));
621   EXPECT_EQ(0, IGNORE_EINTR(close(pipes[1])));
622 }
623 #endif  // defined(OS_POSIX)
624 
625 // Verify that tasks posted on the same sequence access the same values on
626 // SequenceLocalStorage, and tasks on different sequences see different values.
TEST_F(TaskSchedulerImplTest,SequenceLocalStorage)627 TEST_F(TaskSchedulerImplTest, SequenceLocalStorage) {
628   StartTaskScheduler();
629 
630   SequenceLocalStorageSlot<int> slot;
631   auto sequenced_task_runner1 =
632       scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits());
633   auto sequenced_task_runner2 =
634       scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits());
635 
636   sequenced_task_runner1->PostTask(
637       FROM_HERE,
638       BindOnce([](SequenceLocalStorageSlot<int>* slot) { slot->Set(11); },
639                &slot));
640 
641   sequenced_task_runner1->PostTask(FROM_HERE,
642                                    BindOnce(
643                                        [](SequenceLocalStorageSlot<int>* slot) {
644                                          EXPECT_EQ(slot->Get(), 11);
645                                        },
646                                        &slot));
647 
648   sequenced_task_runner2->PostTask(FROM_HERE,
649                                    BindOnce(
650                                        [](SequenceLocalStorageSlot<int>* slot) {
651                                          EXPECT_NE(slot->Get(), 11);
652                                        },
653                                        &slot));
654 
655   scheduler_.FlushForTesting();
656 }
657 
TEST_F(TaskSchedulerImplTest,FlushAsyncNoTasks)658 TEST_F(TaskSchedulerImplTest, FlushAsyncNoTasks) {
659   StartTaskScheduler();
660   bool called_back = false;
661   scheduler_.FlushAsyncForTesting(
662       BindOnce([](bool* called_back) { *called_back = true; },
663                Unretained(&called_back)));
664   EXPECT_TRUE(called_back);
665 }
666 
667 namespace {
668 
669 // Verifies that |query| is found on the current stack. Ignores failures if this
670 // configuration doesn't have symbols.
VerifyHasStringOnStack(const std::string & query)671 void VerifyHasStringOnStack(const std::string& query) {
672   const std::string stack = debug::StackTrace().ToString();
673   SCOPED_TRACE(stack);
674   const bool found_on_stack = stack.find(query) != std::string::npos;
675   const bool stack_has_symbols =
676       stack.find("SchedulerWorker") != std::string::npos;
677   EXPECT_TRUE(found_on_stack || !stack_has_symbols) << query;
678 }
679 
680 }  // namespace
681 
682 #if defined(OS_POSIX)
683 // Many POSIX bots flakily crash on |debug::StackTrace().ToString()|,
684 // https://crbug.com/840429.
685 #define MAYBE_IdentifiableStacks DISABLED_IdentifiableStacks
686 #elif defined(OS_WIN) && \
687     (defined(ADDRESS_SANITIZER) || BUILDFLAG(CFI_CAST_CHECK))
688 // Hangs on WinASan and WinCFI (grabbing StackTrace() too slow?),
689 // https://crbug.com/845010#c7.
690 #define MAYBE_IdentifiableStacks DISABLED_IdentifiableStacks
691 #else
692 #define MAYBE_IdentifiableStacks IdentifiableStacks
693 #endif
694 
695 // Integration test that verifies that workers have a frame on their stacks
696 // which easily identifies the type of worker (useful to diagnose issues from
697 // logs without memory dumps).
TEST_F(TaskSchedulerImplTest,MAYBE_IdentifiableStacks)698 TEST_F(TaskSchedulerImplTest, MAYBE_IdentifiableStacks) {
699   StartTaskScheduler();
700 
701   scheduler_.CreateSequencedTaskRunnerWithTraits({})->PostTask(
702       FROM_HERE, BindOnce(&VerifyHasStringOnStack, "RunPooledWorker"));
703   scheduler_.CreateSequencedTaskRunnerWithTraits({TaskPriority::BACKGROUND})
704       ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
705                                      "RunBackgroundPooledWorker"));
706 
707   scheduler_
708       .CreateSingleThreadTaskRunnerWithTraits(
709           {}, SingleThreadTaskRunnerThreadMode::SHARED)
710       ->PostTask(FROM_HERE,
711                  BindOnce(&VerifyHasStringOnStack, "RunSharedWorker"));
712   scheduler_
713       .CreateSingleThreadTaskRunnerWithTraits(
714           {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED)
715       ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
716                                      "RunBackgroundSharedWorker"));
717 
718   scheduler_
719       .CreateSingleThreadTaskRunnerWithTraits(
720           {}, SingleThreadTaskRunnerThreadMode::DEDICATED)
721       ->PostTask(FROM_HERE,
722                  BindOnce(&VerifyHasStringOnStack, "RunDedicatedWorker"));
723   scheduler_
724       .CreateSingleThreadTaskRunnerWithTraits(
725           {TaskPriority::BACKGROUND},
726           SingleThreadTaskRunnerThreadMode::DEDICATED)
727       ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
728                                      "RunBackgroundDedicatedWorker"));
729 
730 #if defined(OS_WIN)
731   scheduler_
732       .CreateCOMSTATaskRunnerWithTraits(
733           {}, SingleThreadTaskRunnerThreadMode::SHARED)
734       ->PostTask(FROM_HERE,
735                  BindOnce(&VerifyHasStringOnStack, "RunSharedCOMWorker"));
736   scheduler_
737       .CreateCOMSTATaskRunnerWithTraits(
738           {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED)
739       ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
740                                      "RunBackgroundSharedCOMWorker"));
741 
742   scheduler_
743       .CreateCOMSTATaskRunnerWithTraits(
744           {}, SingleThreadTaskRunnerThreadMode::DEDICATED)
745       ->PostTask(FROM_HERE,
746                  BindOnce(&VerifyHasStringOnStack, "RunDedicatedCOMWorker"));
747   scheduler_
748       .CreateCOMSTATaskRunnerWithTraits(
749           {TaskPriority::BACKGROUND},
750           SingleThreadTaskRunnerThreadMode::DEDICATED)
751       ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
752                                      "RunBackgroundDedicatedCOMWorker"));
753 #endif  // defined(OS_WIN)
754 
755   scheduler_.FlushForTesting();
756 }
757 
TEST_F(TaskSchedulerImplTest,SchedulerWorkerObserver)758 TEST_F(TaskSchedulerImplTest, SchedulerWorkerObserver) {
759   testing::StrictMock<test::MockSchedulerWorkerObserver> observer;
760   set_scheduler_worker_observer(&observer);
761 
762   // A worker should be created for each pool. After that, 8 threads should be
763   // created for single-threaded work (16 on Windows).
764   const int kExpectedNumPoolWorkers =
765       CanUseBackgroundPriorityForSchedulerWorker() ? 4 : 2;
766 #if defined(OS_WIN)
767   const int kExpectedNumSingleThreadedWorkers = 16;
768 #else
769   const int kExpectedNumSingleThreadedWorkers = 8;
770 #endif
771   const int kExpectedNumWorkers =
772       kExpectedNumPoolWorkers + kExpectedNumSingleThreadedWorkers;
773 
774   EXPECT_CALL(observer, OnSchedulerWorkerMainEntry())
775       .Times(kExpectedNumWorkers);
776 
777   StartTaskScheduler();
778 
779   std::vector<scoped_refptr<SingleThreadTaskRunner>> task_runners;
780 
781   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
782       {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED));
783   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
784       {TaskPriority::BACKGROUND, MayBlock()},
785       SingleThreadTaskRunnerThreadMode::SHARED));
786   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
787       {TaskPriority::USER_BLOCKING}, SingleThreadTaskRunnerThreadMode::SHARED));
788   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
789       {TaskPriority::USER_BLOCKING, MayBlock()},
790       SingleThreadTaskRunnerThreadMode::SHARED));
791 
792   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
793       {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::DEDICATED));
794   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
795       {TaskPriority::BACKGROUND, MayBlock()},
796       SingleThreadTaskRunnerThreadMode::DEDICATED));
797   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
798       {TaskPriority::USER_BLOCKING},
799       SingleThreadTaskRunnerThreadMode::DEDICATED));
800   task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits(
801       {TaskPriority::USER_BLOCKING, MayBlock()},
802       SingleThreadTaskRunnerThreadMode::DEDICATED));
803 
804 #if defined(OS_WIN)
805   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
806       {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED));
807   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
808       {TaskPriority::BACKGROUND, MayBlock()},
809       SingleThreadTaskRunnerThreadMode::SHARED));
810   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
811       {TaskPriority::USER_BLOCKING}, SingleThreadTaskRunnerThreadMode::SHARED));
812   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
813       {TaskPriority::USER_BLOCKING, MayBlock()},
814       SingleThreadTaskRunnerThreadMode::SHARED));
815 
816   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
817       {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::DEDICATED));
818   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
819       {TaskPriority::BACKGROUND, MayBlock()},
820       SingleThreadTaskRunnerThreadMode::DEDICATED));
821   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
822       {TaskPriority::USER_BLOCKING},
823       SingleThreadTaskRunnerThreadMode::DEDICATED));
824   task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits(
825       {TaskPriority::USER_BLOCKING, MayBlock()},
826       SingleThreadTaskRunnerThreadMode::DEDICATED));
827 #endif
828 
829   for (auto& task_runner : task_runners)
830     task_runner->PostTask(FROM_HERE, DoNothing());
831 
832   EXPECT_CALL(observer, OnSchedulerWorkerMainExit()).Times(kExpectedNumWorkers);
833 
834   // Allow single-threaded workers to be released.
835   task_runners.clear();
836 
837   TearDown();
838 }
839 
840 }  // namespace internal
841 }  // namespace base
842