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/scheduler_worker.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/synchronization/condition_variable.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/task_scheduler/environment_config.h"
20 #include "base/task_scheduler/scheduler_lock.h"
21 #include "base/task_scheduler/scheduler_worker_observer.h"
22 #include "base/task_scheduler/sequence.h"
23 #include "base/task_scheduler/task.h"
24 #include "base/task_scheduler/task_tracker.h"
25 #include "base/task_scheduler/test_utils.h"
26 #include "base/test/test_timeouts.h"
27 #include "base/threading/platform_thread.h"
28 #include "base/threading/simple_thread.h"
29 #include "base/time/time.h"
30 #include "build/build_config.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 
34 #if defined(OS_WIN)
35 #include <objbase.h>
36 
37 #include "base/win/com_init_check_hook.h"
38 #endif
39 
40 using testing::_;
41 using testing::Mock;
42 using testing::Ne;
43 using testing::StrictMock;
44 
45 namespace base {
46 namespace internal {
47 namespace {
48 
49 const size_t kNumSequencesPerTest = 150;
50 
51 class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate {
52  public:
53   SchedulerWorkerDefaultDelegate() = default;
54 
55   // SchedulerWorker::Delegate:
OnCanScheduleSequence(scoped_refptr<Sequence> sequence)56   void OnCanScheduleSequence(scoped_refptr<Sequence> sequence) override {
57     ADD_FAILURE() << "Unexpected call to OnCanScheduleSequence().";
58   }
GetThreadLabel() const59   SchedulerWorker::ThreadLabel GetThreadLabel() const override {
60     return SchedulerWorker::ThreadLabel::DEDICATED;
61   }
OnMainEntry(const SchedulerWorker * worker)62   void OnMainEntry(const SchedulerWorker* worker) override {}
GetWork(SchedulerWorker * worker)63   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
64     return nullptr;
65   }
DidRunTask()66   void DidRunTask() override {
67     ADD_FAILURE() << "Unexpected call to DidRunTask()";
68   }
ReEnqueueSequence(scoped_refptr<Sequence> sequence)69   void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override {
70     ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()";
71   }
GetSleepTimeout()72   TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); }
73 
74  private:
75   DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate);
76 };
77 
78 // The test parameter is the number of Tasks per Sequence returned by GetWork().
79 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> {
80  protected:
TaskSchedulerWorkerTest()81   TaskSchedulerWorkerTest()
82       : num_get_work_cv_(lock_.CreateConditionVariable()) {}
83 
SetUp()84   void SetUp() override {
85     worker_ = MakeRefCounted<SchedulerWorker>(
86         ThreadPriority::NORMAL,
87         std::make_unique<TestSchedulerWorkerDelegate>(this),
88         task_tracker_.GetTrackedRef());
89     ASSERT_TRUE(worker_);
90     worker_->Start();
91     worker_set_.Signal();
92     main_entry_called_.Wait();
93   }
94 
TearDown()95   void TearDown() override {
96     // |worker_| needs to be released before ~TaskTracker() as it holds a
97     // TrackedRef to it.
98     worker_->JoinForTesting();
99     worker_ = nullptr;
100   }
101 
TasksPerSequence() const102   size_t TasksPerSequence() const { return GetParam(); }
103 
104   // Wait until GetWork() has been called |num_get_work| times.
WaitForNumGetWork(size_t num_get_work)105   void WaitForNumGetWork(size_t num_get_work) {
106     AutoSchedulerLock auto_lock(lock_);
107     while (num_get_work_ < num_get_work)
108       num_get_work_cv_->Wait();
109   }
110 
SetMaxGetWork(size_t max_get_work)111   void SetMaxGetWork(size_t max_get_work) {
112     AutoSchedulerLock auto_lock(lock_);
113     max_get_work_ = max_get_work;
114   }
115 
SetNumSequencesToCreate(size_t num_sequences_to_create)116   void SetNumSequencesToCreate(size_t num_sequences_to_create) {
117     AutoSchedulerLock auto_lock(lock_);
118     EXPECT_EQ(0U, num_sequences_to_create_);
119     num_sequences_to_create_ = num_sequences_to_create;
120   }
121 
NumRunTasks()122   size_t NumRunTasks() {
123     AutoSchedulerLock auto_lock(lock_);
124     return num_run_tasks_;
125   }
126 
CreatedSequences()127   std::vector<scoped_refptr<Sequence>> CreatedSequences() {
128     AutoSchedulerLock auto_lock(lock_);
129     return created_sequences_;
130   }
131 
EnqueuedSequences()132   std::vector<scoped_refptr<Sequence>> EnqueuedSequences() {
133     AutoSchedulerLock auto_lock(lock_);
134     return re_enqueued_sequences_;
135   }
136 
137   scoped_refptr<SchedulerWorker> worker_;
138 
139  private:
140   class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate {
141    public:
TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest * outer)142     TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer)
143         : outer_(outer) {}
144 
~TestSchedulerWorkerDelegate()145     ~TestSchedulerWorkerDelegate() override {
146       EXPECT_FALSE(IsCallToDidRunTaskExpected());
147     }
148 
149     // SchedulerWorker::Delegate:
OnMainEntry(const SchedulerWorker * worker)150     void OnMainEntry(const SchedulerWorker* worker) override {
151       outer_->worker_set_.Wait();
152       EXPECT_EQ(outer_->worker_.get(), worker);
153       EXPECT_FALSE(IsCallToDidRunTaskExpected());
154 
155       // Without synchronization, OnMainEntry() could be called twice without
156       // generating an error.
157       AutoSchedulerLock auto_lock(outer_->lock_);
158       EXPECT_FALSE(outer_->main_entry_called_.IsSignaled());
159       outer_->main_entry_called_.Signal();
160     }
161 
GetWork(SchedulerWorker * worker)162     scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
163       EXPECT_FALSE(IsCallToDidRunTaskExpected());
164       EXPECT_EQ(outer_->worker_.get(), worker);
165 
166       {
167         AutoSchedulerLock auto_lock(outer_->lock_);
168 
169         // Increment the number of times that this method has been called.
170         ++outer_->num_get_work_;
171         outer_->num_get_work_cv_->Signal();
172 
173         // Verify that this method isn't called more times than expected.
174         EXPECT_LE(outer_->num_get_work_, outer_->max_get_work_);
175 
176         // Check if a Sequence should be returned.
177         if (outer_->num_sequences_to_create_ == 0)
178           return nullptr;
179         --outer_->num_sequences_to_create_;
180       }
181 
182       // Create a Sequence with TasksPerSequence() Tasks.
183       scoped_refptr<Sequence> sequence(new Sequence);
184       for (size_t i = 0; i < outer_->TasksPerSequence(); ++i) {
185         Task task(FROM_HERE,
186                   BindOnce(&TaskSchedulerWorkerTest::RunTaskCallback,
187                            Unretained(outer_)),
188                   TaskTraits(), TimeDelta());
189         EXPECT_TRUE(outer_->task_tracker_.WillPostTask(&task));
190         sequence->PushTask(std::move(task));
191       }
192 
193       ExpectCallToDidRunTask();
194 
195       {
196         // Add the Sequence to the vector of created Sequences.
197         AutoSchedulerLock auto_lock(outer_->lock_);
198         outer_->created_sequences_.push_back(sequence);
199       }
200 
201       sequence = outer_->task_tracker_.WillScheduleSequence(std::move(sequence),
202                                                             nullptr);
203       EXPECT_TRUE(sequence);
204       return sequence;
205     }
206 
DidRunTask()207     void DidRunTask() override {
208       AutoSchedulerLock auto_lock(expect_did_run_task_lock_);
209       EXPECT_TRUE(expect_did_run_task_);
210       expect_did_run_task_ = false;
211     }
212 
213     // This override verifies that |sequence| contains the expected number of
214     // Tasks and adds it to |enqueued_sequences_|. Unlike a normal
215     // EnqueueSequence implementation, it doesn't reinsert |sequence| into a
216     // queue for further execution.
ReEnqueueSequence(scoped_refptr<Sequence> sequence)217     void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override {
218       EXPECT_FALSE(IsCallToDidRunTaskExpected());
219       EXPECT_GT(outer_->TasksPerSequence(), 1U);
220 
221       // Verify that |sequence| contains TasksPerSequence() - 1 Tasks.
222       for (size_t i = 0; i < outer_->TasksPerSequence() - 1; ++i) {
223         EXPECT_TRUE(sequence->TakeTask());
224         EXPECT_EQ(i == outer_->TasksPerSequence() - 2, sequence->Pop());
225       }
226 
227       // Add |sequence| to |re_enqueued_sequences_|.
228       AutoSchedulerLock auto_lock(outer_->lock_);
229       outer_->re_enqueued_sequences_.push_back(std::move(sequence));
230       EXPECT_LE(outer_->re_enqueued_sequences_.size(),
231                 outer_->created_sequences_.size());
232     }
233 
234    private:
235     // Expect a call to DidRunTask() before the next call to any other method of
236     // this delegate.
ExpectCallToDidRunTask()237     void ExpectCallToDidRunTask() {
238       AutoSchedulerLock auto_lock(expect_did_run_task_lock_);
239       expect_did_run_task_ = true;
240     }
241 
IsCallToDidRunTaskExpected() const242     bool IsCallToDidRunTaskExpected() const {
243       AutoSchedulerLock auto_lock(expect_did_run_task_lock_);
244       return expect_did_run_task_;
245     }
246 
247     TaskSchedulerWorkerTest* outer_;
248 
249     // Synchronizes access to |expect_did_run_task_|.
250     mutable SchedulerLock expect_did_run_task_lock_;
251 
252     // Whether the next method called on this delegate should be DidRunTask().
253     bool expect_did_run_task_ = false;
254 
255     DISALLOW_COPY_AND_ASSIGN(TestSchedulerWorkerDelegate);
256   };
257 
RunTaskCallback()258   void RunTaskCallback() {
259     AutoSchedulerLock auto_lock(lock_);
260     ++num_run_tasks_;
261     EXPECT_LE(num_run_tasks_, created_sequences_.size());
262   }
263 
264   TaskTracker task_tracker_ = {"Test"};
265 
266   // Synchronizes access to all members below.
267   mutable SchedulerLock lock_;
268 
269   // Signaled once OnMainEntry() has been called.
270   WaitableEvent main_entry_called_;
271 
272   // Number of Sequences that should be created by GetWork(). When this
273   // is 0, GetWork() returns nullptr.
274   size_t num_sequences_to_create_ = 0;
275 
276   // Number of times that GetWork() has been called.
277   size_t num_get_work_ = 0;
278 
279   // Maximum number of times that GetWork() can be called.
280   size_t max_get_work_ = 0;
281 
282   // Condition variable signaled when |num_get_work_| is incremented.
283   std::unique_ptr<ConditionVariable> num_get_work_cv_;
284 
285   // Sequences created by GetWork().
286   std::vector<scoped_refptr<Sequence>> created_sequences_;
287 
288   // Sequences passed to EnqueueSequence().
289   std::vector<scoped_refptr<Sequence>> re_enqueued_sequences_;
290 
291   // Number of times that RunTaskCallback() has been called.
292   size_t num_run_tasks_ = 0;
293 
294   // Signaled after |worker_| is set.
295   WaitableEvent worker_set_;
296 
297   DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerTest);
298 };
299 
300 }  // namespace
301 
302 // Verify that when GetWork() continuously returns Sequences, all Tasks in these
303 // Sequences run successfully. The test wakes up the SchedulerWorker once.
TEST_P(TaskSchedulerWorkerTest,ContinuousWork)304 TEST_P(TaskSchedulerWorkerTest, ContinuousWork) {
305   // Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to
306   // return nullptr.
307   SetNumSequencesToCreate(kNumSequencesPerTest);
308 
309   // Expect |kNumSequencesPerTest| calls to GetWork() in which it returns a
310   // Sequence and one call in which its returns nullptr.
311   const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1;
312   SetMaxGetWork(kExpectedNumGetWork);
313 
314   // Wake up |worker_| and wait until GetWork() has been invoked the
315   // expected amount of times.
316   worker_->WakeUp();
317   WaitForNumGetWork(kExpectedNumGetWork);
318 
319   // All tasks should have run.
320   EXPECT_EQ(kNumSequencesPerTest, NumRunTasks());
321 
322   // If Sequences returned by GetWork() contain more than one Task, they aren't
323   // empty after the worker pops Tasks from them and thus should be returned to
324   // EnqueueSequence().
325   if (TasksPerSequence() > 1)
326     EXPECT_EQ(CreatedSequences(), EnqueuedSequences());
327   else
328     EXPECT_TRUE(EnqueuedSequences().empty());
329 }
330 
331 // Verify that when GetWork() alternates between returning a Sequence and
332 // returning nullptr, all Tasks in the returned Sequences run successfully. The
333 // test wakes up the SchedulerWorker once for each Sequence.
TEST_P(TaskSchedulerWorkerTest,IntermittentWork)334 TEST_P(TaskSchedulerWorkerTest, IntermittentWork) {
335   for (size_t i = 0; i < kNumSequencesPerTest; ++i) {
336     // Set GetWork() to return 1 Sequence before starting to return
337     // nullptr.
338     SetNumSequencesToCreate(1);
339 
340     // Expect |i + 1| calls to GetWork() in which it returns a Sequence and
341     // |i + 1| calls in which it returns nullptr.
342     const size_t expected_num_get_work = 2 * (i + 1);
343     SetMaxGetWork(expected_num_get_work);
344 
345     // Wake up |worker_| and wait until GetWork() has been invoked
346     // the expected amount of times.
347     worker_->WakeUp();
348     WaitForNumGetWork(expected_num_get_work);
349 
350     // The Task should have run
351     EXPECT_EQ(i + 1, NumRunTasks());
352 
353     // If Sequences returned by GetWork() contain more than one Task, they
354     // aren't empty after the worker pops Tasks from them and thus should be
355     // returned to EnqueueSequence().
356     if (TasksPerSequence() > 1)
357       EXPECT_EQ(CreatedSequences(), EnqueuedSequences());
358     else
359       EXPECT_TRUE(EnqueuedSequences().empty());
360   }
361 }
362 
363 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence,
364                         TaskSchedulerWorkerTest,
365                         ::testing::Values(1));
366 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence,
367                         TaskSchedulerWorkerTest,
368                         ::testing::Values(2));
369 
370 namespace {
371 
372 class ControllableCleanupDelegate : public SchedulerWorkerDefaultDelegate {
373  public:
374   class Controls : public RefCountedThreadSafe<Controls> {
375    public:
376     Controls() = default;
377 
HaveWorkBlock()378     void HaveWorkBlock() { work_running_.Reset(); }
379 
UnblockWork()380     void UnblockWork() { work_running_.Signal(); }
381 
WaitForWorkToRun()382     void WaitForWorkToRun() { work_processed_.Wait(); }
383 
WaitForCleanupRequest()384     void WaitForCleanupRequest() { cleanup_requested_.Wait(); }
385 
WaitForDelegateDestroy()386     void WaitForDelegateDestroy() { destroyed_.Wait(); }
387 
WaitForMainExit()388     void WaitForMainExit() { exited_.Wait(); }
389 
set_expect_get_work(bool expect_get_work)390     void set_expect_get_work(bool expect_get_work) {
391       expect_get_work_ = expect_get_work;
392     }
393 
ResetState()394     void ResetState() {
395       work_running_.Signal();
396       work_processed_.Reset();
397       cleanup_requested_.Reset();
398       exited_.Reset();
399       work_requested_ = false;
400     }
401 
set_can_cleanup(bool can_cleanup)402     void set_can_cleanup(bool can_cleanup) { can_cleanup_ = can_cleanup; }
403 
404    private:
405     friend class ControllableCleanupDelegate;
406     friend class RefCountedThreadSafe<Controls>;
407     ~Controls() = default;
408 
409     WaitableEvent work_running_{WaitableEvent::ResetPolicy::MANUAL,
410                                 WaitableEvent::InitialState::SIGNALED};
411     WaitableEvent work_processed_;
412     WaitableEvent cleanup_requested_;
413     WaitableEvent destroyed_;
414     WaitableEvent exited_;
415 
416     bool expect_get_work_ = true;
417     bool can_cleanup_ = false;
418     bool work_requested_ = false;
419 
420     DISALLOW_COPY_AND_ASSIGN(Controls);
421   };
422 
ControllableCleanupDelegate(TaskTracker * task_tracker)423   ControllableCleanupDelegate(TaskTracker* task_tracker)
424       : task_tracker_(task_tracker), controls_(new Controls()) {}
425 
~ControllableCleanupDelegate()426   ~ControllableCleanupDelegate() override { controls_->destroyed_.Signal(); }
427 
GetWork(SchedulerWorker * worker)428   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker)
429       override {
430     EXPECT_TRUE(controls_->expect_get_work_);
431 
432     // Sends one item of work to signal |work_processed_|. On subsequent calls,
433     // sends nullptr to indicate there's no more work to be done.
434     if (controls_->work_requested_) {
435       if (CanCleanup(worker)) {
436         OnCleanup();
437         worker->Cleanup();
438         controls_->set_expect_get_work(false);
439       }
440       return nullptr;
441     }
442 
443     controls_->work_requested_ = true;
444     scoped_refptr<Sequence> sequence(new Sequence);
445     Task task(
446         FROM_HERE,
447         BindOnce(
448             [](WaitableEvent* work_processed, WaitableEvent* work_running) {
449               work_processed->Signal();
450               work_running->Wait();
451             },
452             Unretained(&controls_->work_processed_),
453             Unretained(&controls_->work_running_)),
454         {WithBaseSyncPrimitives(), TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
455         TimeDelta());
456     EXPECT_TRUE(task_tracker_->WillPostTask(&task));
457     sequence->PushTask(std::move(task));
458     sequence =
459         task_tracker_->WillScheduleSequence(std::move(sequence), nullptr);
460     EXPECT_TRUE(sequence);
461     return sequence;
462   }
463 
DidRunTask()464   void DidRunTask() override {}
465 
OnMainExit(SchedulerWorker * worker)466   void OnMainExit(SchedulerWorker* worker) override {
467     controls_->exited_.Signal();
468   }
469 
CanCleanup(SchedulerWorker * worker)470   bool CanCleanup(SchedulerWorker* worker) {
471     // Saving |can_cleanup_| now so that callers waiting on |cleanup_requested_|
472     // have the thread go to sleep and then allow timing out.
473     bool can_cleanup = controls_->can_cleanup_;
474     controls_->cleanup_requested_.Signal();
475     return can_cleanup;
476   }
477 
OnCleanup()478   void OnCleanup() {
479     EXPECT_TRUE(controls_->can_cleanup_);
480     EXPECT_TRUE(controls_->cleanup_requested_.IsSignaled());
481   }
482 
483   // ControllableCleanupDelegate:
controls()484   scoped_refptr<Controls> controls() { return controls_; }
485 
486  private:
487   scoped_refptr<Sequence> work_sequence_;
488   TaskTracker* const task_tracker_;
489   scoped_refptr<Controls> controls_;
490 
491   DISALLOW_COPY_AND_ASSIGN(ControllableCleanupDelegate);
492 };
493 
494 class MockedControllableCleanupDelegate : public ControllableCleanupDelegate {
495  public:
MockedControllableCleanupDelegate(TaskTracker * task_tracker)496   MockedControllableCleanupDelegate(TaskTracker* task_tracker)
497       : ControllableCleanupDelegate(task_tracker){};
498   ~MockedControllableCleanupDelegate() override = default;
499 
500   // SchedulerWorker::Delegate:
501   MOCK_METHOD1(OnMainEntry, void(const SchedulerWorker* worker));
502 
503  private:
504   DISALLOW_COPY_AND_ASSIGN(MockedControllableCleanupDelegate);
505 };
506 
507 }  // namespace
508 
509 // Verify that calling SchedulerWorker::Cleanup() from GetWork() causes
510 // the SchedulerWorker's thread to exit.
TEST(TaskSchedulerWorkerTest,WorkerCleanupFromGetWork)511 TEST(TaskSchedulerWorkerTest, WorkerCleanupFromGetWork) {
512   TaskTracker task_tracker("Test");
513   // Will be owned by SchedulerWorker.
514   MockedControllableCleanupDelegate* delegate =
515       new StrictMock<MockedControllableCleanupDelegate>(&task_tracker);
516   scoped_refptr<ControllableCleanupDelegate::Controls> controls =
517       delegate->controls();
518   controls->set_can_cleanup(true);
519   EXPECT_CALL(*delegate, OnMainEntry(_));
520   auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL,
521                                                 WrapUnique(delegate),
522                                                 task_tracker.GetTrackedRef());
523   worker->Start();
524   worker->WakeUp();
525   controls->WaitForWorkToRun();
526   Mock::VerifyAndClear(delegate);
527   controls->WaitForMainExit();
528 }
529 
TEST(TaskSchedulerWorkerTest,WorkerCleanupDuringWork)530 TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringWork) {
531   TaskTracker task_tracker("Test");
532   // Will be owned by SchedulerWorker.
533   // No mock here as that's reasonably covered by other tests and the delegate
534   // may destroy on a different thread. Mocks aren't designed with that in mind.
535   std::unique_ptr<ControllableCleanupDelegate> delegate =
536       std::make_unique<ControllableCleanupDelegate>(&task_tracker);
537   scoped_refptr<ControllableCleanupDelegate::Controls> controls =
538       delegate->controls();
539 
540   controls->HaveWorkBlock();
541 
542   auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL,
543                                                 std::move(delegate),
544                                                 task_tracker.GetTrackedRef());
545   worker->Start();
546   worker->WakeUp();
547 
548   controls->WaitForWorkToRun();
549   worker->Cleanup();
550   worker = nullptr;
551   controls->UnblockWork();
552   controls->WaitForDelegateDestroy();
553 }
554 
TEST(TaskSchedulerWorkerTest,WorkerCleanupDuringWait)555 TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringWait) {
556   TaskTracker task_tracker("Test");
557   // Will be owned by SchedulerWorker.
558   // No mock here as that's reasonably covered by other tests and the delegate
559   // may destroy on a different thread. Mocks aren't designed with that in mind.
560   std::unique_ptr<ControllableCleanupDelegate> delegate =
561       std::make_unique<ControllableCleanupDelegate>(&task_tracker);
562   scoped_refptr<ControllableCleanupDelegate::Controls> controls =
563       delegate->controls();
564 
565   auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL,
566                                                 std::move(delegate),
567                                                 task_tracker.GetTrackedRef());
568   worker->Start();
569   worker->WakeUp();
570 
571   controls->WaitForCleanupRequest();
572   worker->Cleanup();
573   worker = nullptr;
574   controls->WaitForDelegateDestroy();
575 }
576 
TEST(TaskSchedulerWorkerTest,WorkerCleanupDuringShutdown)577 TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringShutdown) {
578   TaskTracker task_tracker("Test");
579   // Will be owned by SchedulerWorker.
580   // No mock here as that's reasonably covered by other tests and the delegate
581   // may destroy on a different thread. Mocks aren't designed with that in mind.
582   std::unique_ptr<ControllableCleanupDelegate> delegate =
583       std::make_unique<ControllableCleanupDelegate>(&task_tracker);
584   scoped_refptr<ControllableCleanupDelegate::Controls> controls =
585       delegate->controls();
586 
587   controls->HaveWorkBlock();
588 
589   auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL,
590                                                 std::move(delegate),
591                                                 task_tracker.GetTrackedRef());
592   worker->Start();
593   worker->WakeUp();
594 
595   controls->WaitForWorkToRun();
596   task_tracker.Shutdown();
597   worker->Cleanup();
598   worker = nullptr;
599   controls->UnblockWork();
600   controls->WaitForDelegateDestroy();
601 }
602 
603 // Verify that Start() is a no-op after Cleanup().
TEST(TaskSchedulerWorkerTest,CleanupBeforeStart)604 TEST(TaskSchedulerWorkerTest, CleanupBeforeStart) {
605   TaskTracker task_tracker("Test");
606   // Will be owned by SchedulerWorker.
607   // No mock here as that's reasonably covered by other tests and the delegate
608   // may destroy on a different thread. Mocks aren't designed with that in mind.
609   std::unique_ptr<ControllableCleanupDelegate> delegate =
610       std::make_unique<ControllableCleanupDelegate>(&task_tracker);
611   scoped_refptr<ControllableCleanupDelegate::Controls> controls =
612       delegate->controls();
613   controls->set_expect_get_work(false);
614 
615   auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL,
616                                                 std::move(delegate),
617                                                 task_tracker.GetTrackedRef());
618 
619   worker->Cleanup();
620   worker->Start();
621 
622   EXPECT_FALSE(worker->ThreadAliveForTesting());
623 }
624 
625 namespace {
626 
627 class CallJoinFromDifferentThread : public SimpleThread {
628  public:
CallJoinFromDifferentThread(SchedulerWorker * worker_to_join)629   CallJoinFromDifferentThread(SchedulerWorker* worker_to_join)
630       : SimpleThread("SchedulerWorkerJoinThread"),
631         worker_to_join_(worker_to_join) {}
632 
633   ~CallJoinFromDifferentThread() override = default;
634 
Run()635   void Run() override {
636     run_started_event_.Signal();
637     worker_to_join_->JoinForTesting();
638   }
639 
WaitForRunToStart()640   void WaitForRunToStart() { run_started_event_.Wait(); }
641 
642  private:
643   SchedulerWorker* const worker_to_join_;
644   WaitableEvent run_started_event_;
645   DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread);
646 };
647 
648 }  // namespace
649 
TEST(TaskSchedulerWorkerTest,WorkerCleanupDuringJoin)650 TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringJoin) {
651   TaskTracker task_tracker("Test");
652   // Will be owned by SchedulerWorker.
653   // No mock here as that's reasonably covered by other tests and the
654   // delegate may destroy on a different thread. Mocks aren't designed with that
655   // in mind.
656   std::unique_ptr<ControllableCleanupDelegate> delegate =
657       std::make_unique<ControllableCleanupDelegate>(&task_tracker);
658   scoped_refptr<ControllableCleanupDelegate::Controls> controls =
659       delegate->controls();
660 
661   controls->HaveWorkBlock();
662 
663   auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL,
664                                                 std::move(delegate),
665                                                 task_tracker.GetTrackedRef());
666   worker->Start();
667   worker->WakeUp();
668 
669   controls->WaitForWorkToRun();
670   CallJoinFromDifferentThread join_from_different_thread(worker.get());
671   join_from_different_thread.Start();
672   join_from_different_thread.WaitForRunToStart();
673   // Sleep here to give the other thread a chance to call JoinForTesting().
674   // Receiving a signal that Run() was called doesn't mean JoinForTesting() was
675   // necessarily called, and we can't signal after JoinForTesting() as
676   // JoinForTesting() blocks until we call UnblockWork().
677   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
678   worker->Cleanup();
679   worker = nullptr;
680   controls->UnblockWork();
681   controls->WaitForDelegateDestroy();
682   join_from_different_thread.Join();
683 }
684 
685 namespace {
686 
687 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate {
688  public:
ExpectThreadPriorityDelegate()689   ExpectThreadPriorityDelegate()
690       : priority_verified_in_get_work_event_(
691             WaitableEvent::ResetPolicy::AUTOMATIC,
692             WaitableEvent::InitialState::NOT_SIGNALED),
693         expected_thread_priority_(ThreadPriority::BACKGROUND) {}
694 
SetExpectedThreadPriority(ThreadPriority expected_thread_priority)695   void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) {
696     expected_thread_priority_ = expected_thread_priority;
697   }
698 
WaitForPriorityVerifiedInGetWork()699   void WaitForPriorityVerifiedInGetWork() {
700     priority_verified_in_get_work_event_.Wait();
701   }
702 
703   // SchedulerWorker::Delegate:
OnMainEntry(const SchedulerWorker * worker)704   void OnMainEntry(const SchedulerWorker* worker) override {
705     VerifyThreadPriority();
706   }
GetWork(SchedulerWorker * worker)707   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
708     VerifyThreadPriority();
709     priority_verified_in_get_work_event_.Signal();
710     return nullptr;
711   }
712 
713  private:
VerifyThreadPriority()714   void VerifyThreadPriority() {
715     AutoSchedulerLock auto_lock(expected_thread_priority_lock_);
716     EXPECT_EQ(expected_thread_priority_,
717               PlatformThread::GetCurrentThreadPriority());
718   }
719 
720   // Signaled after GetWork() has verified the priority of the worker thread.
721   WaitableEvent priority_verified_in_get_work_event_;
722 
723   // Synchronizes access to |expected_thread_priority_|.
724   SchedulerLock expected_thread_priority_lock_;
725 
726   // Expected thread priority for the next call to OnMainEntry() or GetWork().
727   ThreadPriority expected_thread_priority_;
728 
729   DISALLOW_COPY_AND_ASSIGN(ExpectThreadPriorityDelegate);
730 };
731 
732 }  // namespace
733 
TEST(TaskSchedulerWorkerTest,BumpPriorityOfAliveThreadDuringShutdown)734 TEST(TaskSchedulerWorkerTest, BumpPriorityOfAliveThreadDuringShutdown) {
735   if (!CanUseBackgroundPriorityForSchedulerWorker())
736     return;
737 
738   TaskTracker task_tracker("Test");
739 
740   std::unique_ptr<ExpectThreadPriorityDelegate> delegate(
741       new ExpectThreadPriorityDelegate);
742   ExpectThreadPriorityDelegate* delegate_raw = delegate.get();
743   delegate_raw->SetExpectedThreadPriority(ThreadPriority::BACKGROUND);
744   auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::BACKGROUND,
745                                                 std::move(delegate),
746                                                 task_tracker.GetTrackedRef());
747   worker->Start();
748 
749   // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread
750   // priority can't be increased).
751   worker->WakeUp();
752   delegate_raw->WaitForPriorityVerifiedInGetWork();
753 
754   // Verify that the thread priority is bumped to NORMAL during shutdown.
755   delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL);
756   task_tracker.SetHasShutdownStartedForTesting();
757   worker->WakeUp();
758   delegate_raw->WaitForPriorityVerifiedInGetWork();
759 
760   worker->JoinForTesting();
761 }
762 
763 namespace {
764 
765 class VerifyCallsToObserverDelegate : public SchedulerWorkerDefaultDelegate {
766  public:
VerifyCallsToObserverDelegate(test::MockSchedulerWorkerObserver * observer)767   VerifyCallsToObserverDelegate(test::MockSchedulerWorkerObserver* observer)
768       : observer_(observer) {}
769 
770   // SchedulerWorker::Delegate:
OnMainEntry(const SchedulerWorker * worker)771   void OnMainEntry(const SchedulerWorker* worker) override {
772     Mock::VerifyAndClear(observer_);
773   }
774 
OnMainExit(SchedulerWorker * worker)775   void OnMainExit(SchedulerWorker* worker) override {
776     EXPECT_CALL(*observer_, OnSchedulerWorkerMainExit());
777   }
778 
779  private:
780   test::MockSchedulerWorkerObserver* const observer_;
781 
782   DISALLOW_COPY_AND_ASSIGN(VerifyCallsToObserverDelegate);
783 };
784 
785 }  // namespace
786 
787 // Flaky: crbug.com/846121
788 #if defined(OS_LINUX) && defined(ADDRESS_SANITIZER)
789 #define MAYBE_SchedulerWorkerObserver DISABLED_SchedulerWorkerObserver
790 #else
791 #define MAYBE_SchedulerWorkerObserver SchedulerWorkerObserver
792 #endif
793 
794 // Verify that the SchedulerWorkerObserver is notified when the worker enters
795 // and exits its main function.
TEST(TaskSchedulerWorkerTest,MAYBE_SchedulerWorkerObserver)796 TEST(TaskSchedulerWorkerTest, MAYBE_SchedulerWorkerObserver) {
797   StrictMock<test::MockSchedulerWorkerObserver> observer;
798   {
799     TaskTracker task_tracker("Test");
800     auto delegate = std::make_unique<VerifyCallsToObserverDelegate>(&observer);
801     auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL,
802                                                   std::move(delegate),
803                                                   task_tracker.GetTrackedRef());
804 
805     EXPECT_CALL(observer, OnSchedulerWorkerMainEntry());
806     worker->Start(&observer);
807     worker->Cleanup();
808     worker = nullptr;
809   }
810   Mock::VerifyAndClear(&observer);
811 }
812 
813 #if defined(OS_WIN)
814 
815 namespace {
816 
817 class CoInitializeDelegate : public SchedulerWorkerDefaultDelegate {
818  public:
819   CoInitializeDelegate() = default;
820 
GetWork(SchedulerWorker * worker)821   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
822     EXPECT_FALSE(get_work_returned_.IsSignaled());
823     EXPECT_EQ(E_UNEXPECTED, coinitialize_hresult_);
824 
825     coinitialize_hresult_ = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
826     if (SUCCEEDED(coinitialize_hresult_))
827       CoUninitialize();
828 
829     get_work_returned_.Signal();
830     return nullptr;
831   }
832 
WaitUntilGetWorkReturned()833   void WaitUntilGetWorkReturned() { get_work_returned_.Wait(); }
834 
coinitialize_hresult() const835   HRESULT coinitialize_hresult() const { return coinitialize_hresult_; }
836 
837  private:
838   WaitableEvent get_work_returned_;
839   HRESULT coinitialize_hresult_ = E_UNEXPECTED;
840 
841   DISALLOW_COPY_AND_ASSIGN(CoInitializeDelegate);
842 };
843 
844 }  // namespace
845 
TEST(TaskSchedulerWorkerTest,BackwardCompatibilityEnabled)846 TEST(TaskSchedulerWorkerTest, BackwardCompatibilityEnabled) {
847   TaskTracker task_tracker("Test");
848   auto delegate = std::make_unique<CoInitializeDelegate>();
849   CoInitializeDelegate* const delegate_raw = delegate.get();
850 
851   // Create a worker with backward compatibility ENABLED. Wake it up and wait
852   // until GetWork() returns.
853   auto worker = MakeRefCounted<SchedulerWorker>(
854       ThreadPriority::NORMAL, std::move(delegate), task_tracker.GetTrackedRef(),
855       nullptr, SchedulerBackwardCompatibility::INIT_COM_STA);
856   worker->Start();
857   worker->WakeUp();
858   delegate_raw->WaitUntilGetWorkReturned();
859 
860   // The call to CoInitializeEx() should have returned S_FALSE to indicate that
861   // the COM library was already initialized on the thread.
862   // See SchedulerWorker::Thread::ThreadMain for why we expect two different
863   // results here.
864 #if defined(COM_INIT_CHECK_HOOK_ENABLED)
865   EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult());
866 #else
867   EXPECT_EQ(S_FALSE, delegate_raw->coinitialize_hresult());
868 #endif
869 
870   worker->JoinForTesting();
871 }
872 
TEST(TaskSchedulerWorkerTest,BackwardCompatibilityDisabled)873 TEST(TaskSchedulerWorkerTest, BackwardCompatibilityDisabled) {
874   TaskTracker task_tracker("Test");
875   auto delegate = std::make_unique<CoInitializeDelegate>();
876   CoInitializeDelegate* const delegate_raw = delegate.get();
877 
878   // Create a worker with backward compatibility DISABLED. Wake it up and wait
879   // until GetWork() returns.
880   auto worker = MakeRefCounted<SchedulerWorker>(
881       ThreadPriority::NORMAL, std::move(delegate), task_tracker.GetTrackedRef(),
882       nullptr, SchedulerBackwardCompatibility::DISABLED);
883   worker->Start();
884   worker->WakeUp();
885   delegate_raw->WaitUntilGetWorkReturned();
886 
887   // The call to CoInitializeEx() should have returned S_OK to indicate that the
888   // COM library wasn't already initialized on the thread.
889   EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult());
890 
891   worker->JoinForTesting();
892 }
893 
894 #endif  // defined(OS_WIN)
895 
896 }  // namespace internal
897 }  // namespace base
898