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
9#include <vector>
10
11#include "base/bind.h"
12#include "base/location.h"
13#include "base/single_thread_task_runner.h"
14#include "base/synchronization/waitable_event.h"
15#include "build/build_config.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "testing/platform_test.h"
18
19using base::Thread;
20
21typedef PlatformTest ThreadTest;
22
23namespace {
24
25void ToggleValue(bool* value) {
26  *value = !*value;
27}
28
29class SleepInsideInitThread : public Thread {
30 public:
31  SleepInsideInitThread() : Thread("none") {
32    init_called_ = false;
33  }
34  ~SleepInsideInitThread() override { Stop(); }
35
36  void Init() override {
37    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
38    init_called_ = true;
39  }
40  bool InitCalled() { return init_called_; }
41 private:
42  bool init_called_;
43};
44
45enum ThreadEvent {
46  // Thread::Init() was called.
47  THREAD_EVENT_INIT = 0,
48
49  // The MessageLoop for the thread was deleted.
50  THREAD_EVENT_MESSAGE_LOOP_DESTROYED,
51
52  // Thread::CleanUp() was called.
53  THREAD_EVENT_CLEANUP,
54
55  // Keep at end of list.
56  THREAD_NUM_EVENTS
57};
58
59typedef std::vector<ThreadEvent> EventList;
60
61class CaptureToEventList : public Thread {
62 public:
63  // This Thread pushes events into the vector |event_list| to show
64  // the order they occured in. |event_list| must remain valid for the
65  // lifetime of this thread.
66  explicit CaptureToEventList(EventList* event_list)
67      : Thread("none"),
68        event_list_(event_list) {
69  }
70
71  ~CaptureToEventList() override { Stop(); }
72
73  void Init() override { event_list_->push_back(THREAD_EVENT_INIT); }
74
75  void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); }
76
77 private:
78  EventList* event_list_;
79};
80
81// Observer that writes a value into |event_list| when a message loop has been
82// destroyed.
83class CapturingDestructionObserver
84    : public base::MessageLoop::DestructionObserver {
85 public:
86  // |event_list| must remain valid throughout the observer's lifetime.
87  explicit CapturingDestructionObserver(EventList* event_list)
88      : event_list_(event_list) {
89  }
90
91  // DestructionObserver implementation:
92  void WillDestroyCurrentMessageLoop() override {
93    event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED);
94    event_list_ = NULL;
95  }
96
97 private:
98  EventList* event_list_;
99};
100
101// Task that adds a destruction observer to the current message loop.
102void RegisterDestructionObserver(
103    base::MessageLoop::DestructionObserver* observer) {
104  base::MessageLoop::current()->AddDestructionObserver(observer);
105}
106
107// Task that calls GetThreadId() of |thread|, stores the result into |id|, then
108// signal |event|.
109void ReturnThreadId(base::Thread* thread,
110                    base::PlatformThreadId* id,
111                    base::WaitableEvent* event) {
112  *id = thread->GetThreadId();
113  event->Signal();
114}
115
116}  // namespace
117
118TEST_F(ThreadTest, Restart) {
119  Thread a("Restart");
120  a.Stop();
121  EXPECT_FALSE(a.message_loop());
122  EXPECT_FALSE(a.IsRunning());
123  EXPECT_TRUE(a.Start());
124  EXPECT_TRUE(a.message_loop());
125  EXPECT_TRUE(a.IsRunning());
126  a.Stop();
127  EXPECT_FALSE(a.message_loop());
128  EXPECT_FALSE(a.IsRunning());
129  EXPECT_TRUE(a.Start());
130  EXPECT_TRUE(a.message_loop());
131  EXPECT_TRUE(a.IsRunning());
132  a.Stop();
133  EXPECT_FALSE(a.message_loop());
134  EXPECT_FALSE(a.IsRunning());
135  a.Stop();
136  EXPECT_FALSE(a.message_loop());
137  EXPECT_FALSE(a.IsRunning());
138}
139
140TEST_F(ThreadTest, StartWithOptions_StackSize) {
141  Thread a("StartWithStackSize");
142  // Ensure that the thread can work with only 12 kb and still process a
143  // message.
144  Thread::Options options;
145#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)
146  // ASan bloats the stack variables and overflows the 12 kb stack on OSX.
147  options.stack_size = 24*1024;
148#else
149  options.stack_size = 12*1024;
150#endif
151  EXPECT_TRUE(a.StartWithOptions(options));
152  EXPECT_TRUE(a.message_loop());
153  EXPECT_TRUE(a.IsRunning());
154
155  bool was_invoked = false;
156  a.task_runner()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
157
158  // wait for the task to run (we could use a kernel event here
159  // instead to avoid busy waiting, but this is sufficient for
160  // testing purposes).
161  for (int i = 100; i >= 0 && !was_invoked; --i) {
162    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
163  }
164  EXPECT_TRUE(was_invoked);
165}
166
167TEST_F(ThreadTest, TwoTasks) {
168  bool was_invoked = false;
169  {
170    Thread a("TwoTasks");
171    EXPECT_TRUE(a.Start());
172    EXPECT_TRUE(a.message_loop());
173
174    // Test that all events are dispatched before the Thread object is
175    // destroyed.  We do this by dispatching a sleep event before the
176    // event that will toggle our sentinel value.
177    a.task_runner()->PostTask(
178        FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>(
179                                  &base::PlatformThread::Sleep),
180                              base::TimeDelta::FromMilliseconds(20)));
181    a.task_runner()->PostTask(FROM_HERE,
182                              base::Bind(&ToggleValue, &was_invoked));
183  }
184  EXPECT_TRUE(was_invoked);
185}
186
187TEST_F(ThreadTest, StopSoon) {
188  Thread a("StopSoon");
189  EXPECT_TRUE(a.Start());
190  EXPECT_TRUE(a.message_loop());
191  EXPECT_TRUE(a.IsRunning());
192  a.StopSoon();
193  a.StopSoon();
194  a.Stop();
195  EXPECT_FALSE(a.message_loop());
196  EXPECT_FALSE(a.IsRunning());
197}
198
199TEST_F(ThreadTest, ThreadName) {
200  Thread a("ThreadName");
201  EXPECT_TRUE(a.Start());
202  EXPECT_EQ("ThreadName", a.thread_name());
203}
204
205TEST_F(ThreadTest, ThreadId) {
206  Thread a("ThreadId0");
207  Thread b("ThreadId1");
208  a.Start();
209  b.Start();
210
211  // Post a task that calls GetThreadId() on the created thread.
212  base::WaitableEvent event(false, false);
213  base::PlatformThreadId id_from_new_thread;
214  a.task_runner()->PostTask(
215      FROM_HERE, base::Bind(ReturnThreadId, &a, &id_from_new_thread, &event));
216
217  // Call GetThreadId() on the current thread before calling event.Wait() so
218  // that this test can find a race issue with TSAN.
219  base::PlatformThreadId id_from_current_thread = a.GetThreadId();
220
221  // Check if GetThreadId() returns consistent value in both threads.
222  event.Wait();
223  EXPECT_EQ(id_from_current_thread, id_from_new_thread);
224
225  // A started thread should have a valid ID.
226  EXPECT_NE(base::kInvalidThreadId, a.GetThreadId());
227  EXPECT_NE(base::kInvalidThreadId, b.GetThreadId());
228
229  // Each thread should have a different thread ID.
230  EXPECT_NE(a.GetThreadId(), b.GetThreadId());
231}
232
233TEST_F(ThreadTest, ThreadIdWithRestart) {
234  Thread a("ThreadIdWithRestart");
235  base::PlatformThreadId previous_id = base::kInvalidThreadId;
236
237  for (size_t i = 0; i < 16; ++i) {
238    EXPECT_TRUE(a.Start());
239    base::PlatformThreadId current_id = a.GetThreadId();
240    EXPECT_NE(previous_id, current_id);
241    previous_id = current_id;
242    a.Stop();
243  }
244}
245
246// Make sure Init() is called after Start() and before
247// WaitUntilThreadInitialized() returns.
248TEST_F(ThreadTest, SleepInsideInit) {
249  SleepInsideInitThread t;
250  EXPECT_FALSE(t.InitCalled());
251  t.StartAndWaitForTesting();
252  EXPECT_TRUE(t.InitCalled());
253}
254
255// Make sure that the destruction sequence is:
256//
257//  (1) Thread::CleanUp()
258//  (2) MessageLoop::~MessageLoop()
259//      MessageLoop::DestructionObservers called.
260TEST_F(ThreadTest, CleanUp) {
261  EventList captured_events;
262  CapturingDestructionObserver loop_destruction_observer(&captured_events);
263
264  {
265    // Start a thread which writes its event into |captured_events|.
266    CaptureToEventList t(&captured_events);
267    EXPECT_TRUE(t.Start());
268    EXPECT_TRUE(t.message_loop());
269    EXPECT_TRUE(t.IsRunning());
270
271    // Register an observer that writes into |captured_events| once the
272    // thread's message loop is destroyed.
273    t.task_runner()->PostTask(
274        FROM_HERE, base::Bind(&RegisterDestructionObserver,
275                              base::Unretained(&loop_destruction_observer)));
276
277    // Upon leaving this scope, the thread is deleted.
278  }
279
280  // Check the order of events during shutdown.
281  ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
282  EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
283  EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
284  EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
285}
286
287TEST_F(ThreadTest, ThreadNotStarted) {
288  Thread a("Inert");
289  EXPECT_EQ(nullptr, a.task_runner());
290}
291