1 // Copyright (c) 2012 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/threading/thread.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <utility>
11 #include <vector>
12 
13 #include "base/bind.h"
14 #include "base/debug/leak_annotations.h"
15 #include "base/macros.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/run_loop.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/task/post_task.h"
21 #include "base/task/sequence_manager/sequence_manager_impl.h"
22 #include "base/task/task_executor.h"
23 #include "base/test/bind_test_util.h"
24 #include "base/test/gtest_util.h"
25 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
26 #include "base/threading/platform_thread.h"
27 #include "base/time/time.h"
28 #include "build/build_config.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "testing/platform_test.h"
32 
33 using base::Thread;
34 using ::testing::NotNull;
35 
36 typedef PlatformTest ThreadTest;
37 
38 namespace {
39 
ToggleValue(bool * value)40 void ToggleValue(bool* value) {
41   ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean "
42                        "in base/thread_unittest");
43   *value = !*value;
44 }
45 
46 class SleepInsideInitThread : public Thread {
47  public:
SleepInsideInitThread()48   SleepInsideInitThread() : Thread("none") {
49     init_called_ = false;
50     ANNOTATE_BENIGN_RACE(
51         this, "Benign test-only data race on vptr - http://crbug.com/98219");
52   }
~SleepInsideInitThread()53   ~SleepInsideInitThread() override { Stop(); }
54 
Init()55   void Init() override {
56     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
57     init_called_ = true;
58   }
InitCalled()59   bool InitCalled() { return init_called_; }
60 
61  private:
62   bool init_called_;
63 
64   DISALLOW_COPY_AND_ASSIGN(SleepInsideInitThread);
65 };
66 
67 enum ThreadEvent {
68   // Thread::Init() was called.
69   THREAD_EVENT_INIT = 0,
70 
71   // The MessageLoop for the thread was deleted.
72   THREAD_EVENT_MESSAGE_LOOP_DESTROYED,
73 
74   // Thread::CleanUp() was called.
75   THREAD_EVENT_CLEANUP,
76 
77   // Keep at end of list.
78   THREAD_NUM_EVENTS
79 };
80 
81 typedef std::vector<ThreadEvent> EventList;
82 
83 class CaptureToEventList : public Thread {
84  public:
85   // This Thread pushes events into the vector |event_list| to show
86   // the order they occured in. |event_list| must remain valid for the
87   // lifetime of this thread.
CaptureToEventList(EventList * event_list)88   explicit CaptureToEventList(EventList* event_list)
89       : Thread("none"),
90         event_list_(event_list) {
91   }
92 
~CaptureToEventList()93   ~CaptureToEventList() override { Stop(); }
94 
Init()95   void Init() override { event_list_->push_back(THREAD_EVENT_INIT); }
96 
CleanUp()97   void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); }
98 
99  private:
100   EventList* event_list_;
101 
102   DISALLOW_COPY_AND_ASSIGN(CaptureToEventList);
103 };
104 
105 // Observer that writes a value into |event_list| when a message loop has been
106 // destroyed.
107 class CapturingDestructionObserver
108     : public base::MessageLoopCurrent::DestructionObserver {
109  public:
110   // |event_list| must remain valid throughout the observer's lifetime.
CapturingDestructionObserver(EventList * event_list)111   explicit CapturingDestructionObserver(EventList* event_list)
112       : event_list_(event_list) {
113   }
114 
115   // DestructionObserver implementation:
WillDestroyCurrentMessageLoop()116   void WillDestroyCurrentMessageLoop() override {
117     event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED);
118     event_list_ = nullptr;
119   }
120 
121  private:
122   EventList* event_list_;
123 
124   DISALLOW_COPY_AND_ASSIGN(CapturingDestructionObserver);
125 };
126 
127 // Task that adds a destruction observer to the current message loop.
RegisterDestructionObserver(base::MessageLoopCurrent::DestructionObserver * observer)128 void RegisterDestructionObserver(
129     base::MessageLoopCurrent::DestructionObserver* observer) {
130   base::MessageLoopCurrent::Get()->AddDestructionObserver(observer);
131 }
132 
133 // Task that calls GetThreadId() of |thread|, stores the result into |id|, then
134 // signal |event|.
ReturnThreadId(base::Thread * thread,base::PlatformThreadId * id,base::WaitableEvent * event)135 void ReturnThreadId(base::Thread* thread,
136                     base::PlatformThreadId* id,
137                     base::WaitableEvent* event) {
138   *id = thread->GetThreadId();
139   event->Signal();
140 }
141 
142 }  // namespace
143 
TEST_F(ThreadTest,StartWithOptions_StackSize)144 TEST_F(ThreadTest, StartWithOptions_StackSize) {
145   Thread a("StartWithStackSize");
146   // Ensure that the thread can work with only 12 kb and still process a
147   // message. At the same time, we should scale with the bitness of the system
148   // where 12 kb is definitely not enough.
149   // 12 kb = 3072 Slots on a 32-bit system, so we'll scale based off of that.
150   Thread::Options options;
151 #if defined(ADDRESS_SANITIZER) || !defined(NDEBUG)
152   // ASan bloats the stack variables and overflows the 3072 slot stack. Some
153   // debug builds also grow the stack too much.
154   options.stack_size = 2 * 3072 * sizeof(uintptr_t);
155 #else
156   options.stack_size = 3072 * sizeof(uintptr_t);
157 #endif
158   EXPECT_TRUE(a.StartWithOptions(options));
159   EXPECT_TRUE(a.task_runner());
160   EXPECT_TRUE(a.IsRunning());
161 
162   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
163                             base::WaitableEvent::InitialState::NOT_SIGNALED);
164   a.task_runner()->PostTask(
165       FROM_HERE,
166       base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)));
167   event.Wait();
168 }
169 
170 // Intentional test-only race for otherwise untestable code, won't fix.
171 // https://crbug.com/634383
172 #if !defined(THREAD_SANITIZER)
TEST_F(ThreadTest,StartWithOptions_NonJoinable)173 TEST_F(ThreadTest, StartWithOptions_NonJoinable) {
174   Thread* a = new Thread("StartNonJoinable");
175   // Non-joinable threads have to be leaked for now (see
176   // Thread::Options::joinable for details).
177   ANNOTATE_LEAKING_OBJECT_PTR(a);
178 
179   Thread::Options options;
180   options.joinable = false;
181   EXPECT_TRUE(a->StartWithOptions(options));
182   EXPECT_TRUE(a->task_runner());
183   EXPECT_TRUE(a->IsRunning());
184 
185   // Without this call this test is racy. The above IsRunning() succeeds because
186   // of an early-return condition while between Start() and StopSoon(), after
187   // invoking StopSoon() below this early-return condition is no longer
188   // satisfied and the real |is_running_| bit has to be checked. It could still
189   // be false if the message loop hasn't started for real in practice. This is
190   // only a requirement for this test because the non-joinable property forces
191   // it to use StopSoon() and not wait for a complete Stop().
192   EXPECT_TRUE(a->WaitUntilThreadStarted());
193 
194   // Make the thread block until |block_event| is signaled.
195   base::WaitableEvent block_event(
196       base::WaitableEvent::ResetPolicy::AUTOMATIC,
197       base::WaitableEvent::InitialState::NOT_SIGNALED);
198   a->task_runner()->PostTask(FROM_HERE,
199                              base::BindOnce(&base::WaitableEvent::Wait,
200                                             base::Unretained(&block_event)));
201 
202   a->StopSoon();
203   EXPECT_TRUE(a->IsRunning());
204 
205   // Unblock the task and give a bit of extra time to unwind QuitWhenIdle().
206   block_event.Signal();
207   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
208 
209   // The thread should now have stopped on its own.
210   EXPECT_FALSE(a->IsRunning());
211 }
212 #endif
213 
TEST_F(ThreadTest,TwoTasksOnJoinableThread)214 TEST_F(ThreadTest, TwoTasksOnJoinableThread) {
215   bool was_invoked = false;
216   {
217     Thread a("TwoTasksOnJoinableThread");
218     EXPECT_TRUE(a.Start());
219     EXPECT_TRUE(a.task_runner());
220 
221     // Test that all events are dispatched before the Thread object is
222     // destroyed.  We do this by dispatching a sleep event before the
223     // event that will toggle our sentinel value.
224     a.task_runner()->PostTask(
225         FROM_HERE, base::BindOnce(static_cast<void (*)(base::TimeDelta)>(
226                                       &base::PlatformThread::Sleep),
227                                   base::TimeDelta::FromMilliseconds(20)));
228     a.task_runner()->PostTask(FROM_HERE,
229                               base::BindOnce(&ToggleValue, &was_invoked));
230   }
231   EXPECT_TRUE(was_invoked);
232 }
233 
TEST_F(ThreadTest,DestroyWhileRunningIsSafe)234 TEST_F(ThreadTest, DestroyWhileRunningIsSafe) {
235   Thread a("DestroyWhileRunningIsSafe");
236   EXPECT_TRUE(a.Start());
237   EXPECT_TRUE(a.WaitUntilThreadStarted());
238 }
239 
240 // TODO(gab): Enable this test when destroying a non-joinable Thread instance
241 // is supported (proposal @ https://crbug.com/629139#c14).
TEST_F(ThreadTest,DISABLED_DestroyWhileRunningNonJoinableIsSafe)242 TEST_F(ThreadTest, DISABLED_DestroyWhileRunningNonJoinableIsSafe) {
243   {
244     Thread a("DestroyWhileRunningNonJoinableIsSafe");
245     Thread::Options options;
246     options.joinable = false;
247     EXPECT_TRUE(a.StartWithOptions(options));
248     EXPECT_TRUE(a.WaitUntilThreadStarted());
249   }
250 
251   // Attempt to catch use-after-frees from the non-joinable thread in the
252   // scope of this test if any.
253   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
254 }
255 
TEST_F(ThreadTest,StopSoon)256 TEST_F(ThreadTest, StopSoon) {
257   Thread a("StopSoon");
258   EXPECT_TRUE(a.Start());
259   EXPECT_TRUE(a.task_runner());
260   EXPECT_TRUE(a.IsRunning());
261   a.StopSoon();
262   a.Stop();
263   EXPECT_FALSE(a.task_runner());
264   EXPECT_FALSE(a.IsRunning());
265 }
266 
TEST_F(ThreadTest,StopTwiceNop)267 TEST_F(ThreadTest, StopTwiceNop) {
268   Thread a("StopTwiceNop");
269   EXPECT_TRUE(a.Start());
270   EXPECT_TRUE(a.task_runner());
271   EXPECT_TRUE(a.IsRunning());
272   a.StopSoon();
273   // Calling StopSoon() a second time should be a nop.
274   a.StopSoon();
275   a.Stop();
276   // Same with Stop().
277   a.Stop();
278   EXPECT_FALSE(a.task_runner());
279   EXPECT_FALSE(a.IsRunning());
280   // Calling them when not running should also nop.
281   a.StopSoon();
282   a.Stop();
283 }
284 
285 // TODO(gab): Enable this test in conjunction with re-enabling the sequence
286 // check in Thread::Stop() as part of http://crbug.com/629139.
TEST_F(ThreadTest,DISABLED_StopOnNonOwningThreadIsDeath)287 TEST_F(ThreadTest, DISABLED_StopOnNonOwningThreadIsDeath) {
288   Thread a("StopOnNonOwningThreadDeath");
289   EXPECT_TRUE(a.StartAndWaitForTesting());
290 
291   Thread b("NonOwningThread");
292   b.Start();
293   EXPECT_DCHECK_DEATH({
294     // Stopping |a| on |b| isn't allowed.
295     b.task_runner()->PostTask(
296         FROM_HERE, base::BindOnce(&Thread::Stop, base::Unretained(&a)));
297     // Block here so the DCHECK on |b| always happens in this scope.
298     base::PlatformThread::Sleep(base::TimeDelta::Max());
299   });
300 }
301 
TEST_F(ThreadTest,TransferOwnershipAndStop)302 TEST_F(ThreadTest, TransferOwnershipAndStop) {
303   std::unique_ptr<Thread> a =
304       std::make_unique<Thread>("TransferOwnershipAndStop");
305   EXPECT_TRUE(a->StartAndWaitForTesting());
306   EXPECT_TRUE(a->IsRunning());
307 
308   Thread b("TakingOwnershipThread");
309   b.Start();
310 
311   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
312                             base::WaitableEvent::InitialState::NOT_SIGNALED);
313 
314   // a->DetachFromSequence() should allow |b| to use |a|'s Thread API.
315   a->DetachFromSequence();
316   b.task_runner()->PostTask(
317       FROM_HERE, base::BindOnce(
318                      [](std::unique_ptr<Thread> thread_to_stop,
319                         base::WaitableEvent* event_to_signal) -> void {
320                        thread_to_stop->Stop();
321                        event_to_signal->Signal();
322                      },
323                      std::move(a), base::Unretained(&event)));
324 
325   event.Wait();
326 }
327 
TEST_F(ThreadTest,StartTwice)328 TEST_F(ThreadTest, StartTwice) {
329   Thread a("StartTwice");
330 
331   EXPECT_FALSE(a.task_runner());
332   EXPECT_FALSE(a.IsRunning());
333 
334   EXPECT_TRUE(a.Start());
335   EXPECT_TRUE(a.task_runner());
336   EXPECT_TRUE(a.IsRunning());
337 
338   a.Stop();
339   EXPECT_FALSE(a.task_runner());
340   EXPECT_FALSE(a.IsRunning());
341 
342   EXPECT_TRUE(a.Start());
343   EXPECT_TRUE(a.task_runner());
344   EXPECT_TRUE(a.IsRunning());
345 
346   a.Stop();
347   EXPECT_FALSE(a.task_runner());
348   EXPECT_FALSE(a.IsRunning());
349 }
350 
351 // Intentional test-only race for otherwise untestable code, won't fix.
352 // https://crbug.com/634383
353 #if !defined(THREAD_SANITIZER)
TEST_F(ThreadTest,StartTwiceNonJoinableNotAllowed)354 TEST_F(ThreadTest, StartTwiceNonJoinableNotAllowed) {
355   LOG(ERROR) << __FUNCTION__;
356   Thread* a = new Thread("StartTwiceNonJoinable");
357   // Non-joinable threads have to be leaked for now (see
358   // Thread::Options::joinable for details).
359   ANNOTATE_LEAKING_OBJECT_PTR(a);
360 
361   Thread::Options options;
362   options.joinable = false;
363   EXPECT_TRUE(a->StartWithOptions(options));
364   EXPECT_TRUE(a->task_runner());
365   EXPECT_TRUE(a->IsRunning());
366 
367   // Signaled when last task on |a| is processed.
368   base::WaitableEvent last_task_event(
369       base::WaitableEvent::ResetPolicy::AUTOMATIC,
370       base::WaitableEvent::InitialState::NOT_SIGNALED);
371   a->task_runner()->PostTask(
372       FROM_HERE, base::BindOnce(&base::WaitableEvent::Signal,
373                                 base::Unretained(&last_task_event)));
374 
375   // StopSoon() is non-blocking, Yield() to |a|, wait for last task to be
376   // processed and a little more for QuitWhenIdle() to unwind before considering
377   // the thread "stopped".
378   a->StopSoon();
379   base::PlatformThread::YieldCurrentThread();
380   last_task_event.Wait();
381   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
382 
383   // This test assumes that the above was sufficient to let the thread fully
384   // stop.
385   ASSERT_FALSE(a->IsRunning());
386 
387   // Restarting it should not be allowed.
388   EXPECT_DCHECK_DEATH(a->Start());
389 }
390 #endif
391 
TEST_F(ThreadTest,ThreadName)392 TEST_F(ThreadTest, ThreadName) {
393   Thread a("ThreadName");
394   EXPECT_TRUE(a.Start());
395   EXPECT_EQ("ThreadName", a.thread_name());
396 }
397 
TEST_F(ThreadTest,ThreadId)398 TEST_F(ThreadTest, ThreadId) {
399   Thread a("ThreadId0");
400   Thread b("ThreadId1");
401   a.Start();
402   b.Start();
403 
404   // Post a task that calls GetThreadId() on the created thread.
405   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
406                             base::WaitableEvent::InitialState::NOT_SIGNALED);
407   base::PlatformThreadId id_from_new_thread;
408   a.task_runner()->PostTask(
409       FROM_HERE,
410       base::BindOnce(ReturnThreadId, &a, &id_from_new_thread, &event));
411 
412   // Call GetThreadId() on the current thread before calling event.Wait() so
413   // that this test can find a race issue with TSAN.
414   base::PlatformThreadId id_from_current_thread = a.GetThreadId();
415 
416   // Check if GetThreadId() returns consistent value in both threads.
417   event.Wait();
418   EXPECT_EQ(id_from_current_thread, id_from_new_thread);
419 
420   // A started thread should have a valid ID.
421   EXPECT_NE(base::kInvalidThreadId, a.GetThreadId());
422   EXPECT_NE(base::kInvalidThreadId, b.GetThreadId());
423 
424   // Each thread should have a different thread ID.
425   EXPECT_NE(a.GetThreadId(), b.GetThreadId());
426 }
427 
TEST_F(ThreadTest,ThreadIdWithRestart)428 TEST_F(ThreadTest, ThreadIdWithRestart) {
429   Thread a("ThreadIdWithRestart");
430   base::PlatformThreadId previous_id = base::kInvalidThreadId;
431 
432   for (size_t i = 0; i < 16; ++i) {
433     EXPECT_TRUE(a.Start());
434     base::PlatformThreadId current_id = a.GetThreadId();
435     EXPECT_NE(previous_id, current_id);
436     previous_id = current_id;
437     a.Stop();
438   }
439 }
440 
441 // Make sure Init() is called after Start() and before
442 // WaitUntilThreadInitialized() returns.
TEST_F(ThreadTest,SleepInsideInit)443 TEST_F(ThreadTest, SleepInsideInit) {
444   SleepInsideInitThread t;
445   EXPECT_FALSE(t.InitCalled());
446   t.StartAndWaitForTesting();
447   EXPECT_TRUE(t.InitCalled());
448 }
449 
450 // Make sure that the destruction sequence is:
451 //
452 //  (1) Thread::CleanUp()
453 //  (2) MessageLoop::~MessageLoop()
454 //      MessageLoopCurrent::DestructionObservers called.
TEST_F(ThreadTest,CleanUp)455 TEST_F(ThreadTest, CleanUp) {
456   EventList captured_events;
457   CapturingDestructionObserver loop_destruction_observer(&captured_events);
458 
459   {
460     // Start a thread which writes its event into |captured_events|.
461     CaptureToEventList t(&captured_events);
462     EXPECT_TRUE(t.Start());
463     EXPECT_TRUE(t.task_runner());
464     EXPECT_TRUE(t.IsRunning());
465 
466     // Register an observer that writes into |captured_events| once the
467     // thread's message loop is destroyed.
468     t.task_runner()->PostTask(
469         FROM_HERE,
470         base::BindOnce(&RegisterDestructionObserver,
471                        base::Unretained(&loop_destruction_observer)));
472 
473     // Upon leaving this scope, the thread is deleted.
474   }
475 
476   // Check the order of events during shutdown.
477   ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
478   EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
479   EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
480   EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
481 }
482 
TEST_F(ThreadTest,ThreadNotStarted)483 TEST_F(ThreadTest, ThreadNotStarted) {
484   Thread a("Inert");
485   EXPECT_FALSE(a.task_runner());
486 }
487 
TEST_F(ThreadTest,MultipleWaitUntilThreadStarted)488 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) {
489   Thread a("MultipleWaitUntilThreadStarted");
490   EXPECT_TRUE(a.Start());
491   // It's OK to call WaitUntilThreadStarted() multiple times.
492   EXPECT_TRUE(a.WaitUntilThreadStarted());
493   EXPECT_TRUE(a.WaitUntilThreadStarted());
494 }
495 
TEST_F(ThreadTest,FlushForTesting)496 TEST_F(ThreadTest, FlushForTesting) {
497   Thread a("FlushForTesting");
498 
499   // Flushing a non-running thread should be a no-op.
500   a.FlushForTesting();
501 
502   ASSERT_TRUE(a.Start());
503 
504   // Flushing a thread with no tasks shouldn't block.
505   a.FlushForTesting();
506 
507   constexpr base::TimeDelta kSleepPerTestTask =
508       base::TimeDelta::FromMilliseconds(50);
509   constexpr size_t kNumSleepTasks = 5;
510 
511   const base::TimeTicks ticks_before_post = base::TimeTicks::Now();
512 
513   for (size_t i = 0; i < kNumSleepTasks; ++i) {
514     a.task_runner()->PostTask(
515         FROM_HERE,
516         base::BindOnce(&base::PlatformThread::Sleep, kSleepPerTestTask));
517   }
518 
519   // All tasks should have executed, as reflected by the elapsed time.
520   a.FlushForTesting();
521   EXPECT_GE(base::TimeTicks::Now() - ticks_before_post,
522             kNumSleepTasks * kSleepPerTestTask);
523 
524   a.Stop();
525 
526   // Flushing a stopped thread should be a no-op.
527   a.FlushForTesting();
528 }
529 
TEST_F(ThreadTest,GetTaskExecutorForCurrentThread)530 TEST_F(ThreadTest, GetTaskExecutorForCurrentThread) {
531   Thread a("GetTaskExecutorForCurrentThread");
532   ASSERT_TRUE(a.Start());
533 
534   base::WaitableEvent event;
535 
536   a.task_runner()->PostTask(
537       FROM_HERE, base::BindLambdaForTesting([&]() {
538         EXPECT_THAT(base::GetTaskExecutorForCurrentThread(), NotNull());
539         event.Signal();
540       }));
541 
542   event.Wait();
543   a.Stop();
544 }
545 
546 namespace {
547 
548 class SequenceManagerThreadDelegate : public Thread::Delegate {
549  public:
SequenceManagerThreadDelegate()550   SequenceManagerThreadDelegate()
551       : sequence_manager_(
552             base::sequence_manager::CreateUnboundSequenceManager()),
553         task_queue_(
554             sequence_manager_
555                 ->CreateTaskQueueWithType<base::sequence_manager::TaskQueue>(
556                     base::sequence_manager::TaskQueue::Spec("default_tq"))) {
557     sequence_manager_->SetDefaultTaskRunner(GetDefaultTaskRunner());
558   }
559 
~SequenceManagerThreadDelegate()560   ~SequenceManagerThreadDelegate() override {}
561 
562   // Thread::Delegate:
563 
GetDefaultTaskRunner()564   scoped_refptr<base::SingleThreadTaskRunner> GetDefaultTaskRunner() override {
565     return task_queue_->task_runner();
566   }
567 
BindToCurrentThread(base::TimerSlack timer_slack)568   void BindToCurrentThread(base::TimerSlack timer_slack) override {
569     sequence_manager_->BindToMessagePump(
570         base::MessagePump::Create(base::MessagePumpType::DEFAULT));
571     sequence_manager_->SetTimerSlack(timer_slack);
572   }
573 
574  private:
575   std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager_;
576   scoped_refptr<base::sequence_manager::TaskQueue> task_queue_;
577 
578   DISALLOW_COPY_AND_ASSIGN(SequenceManagerThreadDelegate);
579 };
580 
581 }  // namespace
582 
TEST_F(ThreadTest,ProvidedThreadDelegate)583 TEST_F(ThreadTest, ProvidedThreadDelegate) {
584   Thread thread("ThreadDelegate");
585   base::Thread::Options options;
586   options.delegate = new SequenceManagerThreadDelegate();
587   thread.StartWithOptions(options);
588 
589   base::WaitableEvent event;
590 
591   options.delegate->GetDefaultTaskRunner()->PostTask(
592       FROM_HERE,
593       base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)));
594   event.Wait();
595 
596   thread.Stop();
597 }
598