• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 using base::Thread;
20 
21 typedef PlatformTest ThreadTest;
22 
23 namespace {
24 
ToggleValue(bool * value)25 void ToggleValue(bool* value) {
26   *value = !*value;
27 }
28 
29 class SleepInsideInitThread : public Thread {
30  public:
SleepInsideInitThread()31   SleepInsideInitThread() : Thread("none") {
32     init_called_ = false;
33   }
~SleepInsideInitThread()34   ~SleepInsideInitThread() override { Stop(); }
35 
Init()36   void Init() override {
37     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
38     init_called_ = true;
39   }
InitCalled()40   bool InitCalled() { return init_called_; }
41  private:
42   bool init_called_;
43 };
44 
45 enum 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 
59 typedef std::vector<ThreadEvent> EventList;
60 
61 class 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.
CaptureToEventList(EventList * event_list)66   explicit CaptureToEventList(EventList* event_list)
67       : Thread("none"),
68         event_list_(event_list) {
69   }
70 
~CaptureToEventList()71   ~CaptureToEventList() override { Stop(); }
72 
Init()73   void Init() override { event_list_->push_back(THREAD_EVENT_INIT); }
74 
CleanUp()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.
83 class CapturingDestructionObserver
84     : public base::MessageLoop::DestructionObserver {
85  public:
86   // |event_list| must remain valid throughout the observer's lifetime.
CapturingDestructionObserver(EventList * event_list)87   explicit CapturingDestructionObserver(EventList* event_list)
88       : event_list_(event_list) {
89   }
90 
91   // DestructionObserver implementation:
WillDestroyCurrentMessageLoop()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.
RegisterDestructionObserver(base::MessageLoop::DestructionObserver * observer)102 void 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|.
ReturnThreadId(base::Thread * thread,base::PlatformThreadId * id,base::WaitableEvent * event)109 void ReturnThreadId(base::Thread* thread,
110                     base::PlatformThreadId* id,
111                     base::WaitableEvent* event) {
112   *id = thread->GetThreadId();
113   event->Signal();
114 }
115 
116 }  // namespace
117 
TEST_F(ThreadTest,Restart)118 TEST_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 
TEST_F(ThreadTest,StartWithOptions_StackSize)140 TEST_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)
146   // ASan bloats the stack variables and overflows the 12 kb stack.
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 
TEST_F(ThreadTest,TwoTasks)167 TEST_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 
TEST_F(ThreadTest,StopSoon)187 TEST_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 
TEST_F(ThreadTest,ThreadName)199 TEST_F(ThreadTest, ThreadName) {
200   Thread a("ThreadName");
201   EXPECT_TRUE(a.Start());
202   EXPECT_EQ("ThreadName", a.thread_name());
203 }
204 
TEST_F(ThreadTest,ThreadId)205 TEST_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(base::WaitableEvent::ResetPolicy::AUTOMATIC,
213                             base::WaitableEvent::InitialState::NOT_SIGNALED);
214   base::PlatformThreadId id_from_new_thread;
215   a.task_runner()->PostTask(
216       FROM_HERE, base::Bind(ReturnThreadId, &a, &id_from_new_thread, &event));
217 
218   // Call GetThreadId() on the current thread before calling event.Wait() so
219   // that this test can find a race issue with TSAN.
220   base::PlatformThreadId id_from_current_thread = a.GetThreadId();
221 
222   // Check if GetThreadId() returns consistent value in both threads.
223   event.Wait();
224   EXPECT_EQ(id_from_current_thread, id_from_new_thread);
225 
226   // A started thread should have a valid ID.
227   EXPECT_NE(base::kInvalidThreadId, a.GetThreadId());
228   EXPECT_NE(base::kInvalidThreadId, b.GetThreadId());
229 
230   // Each thread should have a different thread ID.
231   EXPECT_NE(a.GetThreadId(), b.GetThreadId());
232 }
233 
TEST_F(ThreadTest,ThreadIdWithRestart)234 TEST_F(ThreadTest, ThreadIdWithRestart) {
235   Thread a("ThreadIdWithRestart");
236   base::PlatformThreadId previous_id = base::kInvalidThreadId;
237 
238   for (size_t i = 0; i < 16; ++i) {
239     EXPECT_TRUE(a.Start());
240     base::PlatformThreadId current_id = a.GetThreadId();
241     EXPECT_NE(previous_id, current_id);
242     previous_id = current_id;
243     a.Stop();
244   }
245 }
246 
247 // Make sure Init() is called after Start() and before
248 // WaitUntilThreadInitialized() returns.
TEST_F(ThreadTest,SleepInsideInit)249 TEST_F(ThreadTest, SleepInsideInit) {
250   SleepInsideInitThread t;
251   EXPECT_FALSE(t.InitCalled());
252   t.StartAndWaitForTesting();
253   EXPECT_TRUE(t.InitCalled());
254 }
255 
256 // Make sure that the destruction sequence is:
257 //
258 //  (1) Thread::CleanUp()
259 //  (2) MessageLoop::~MessageLoop()
260 //      MessageLoop::DestructionObservers called.
TEST_F(ThreadTest,CleanUp)261 TEST_F(ThreadTest, CleanUp) {
262   EventList captured_events;
263   CapturingDestructionObserver loop_destruction_observer(&captured_events);
264 
265   {
266     // Start a thread which writes its event into |captured_events|.
267     CaptureToEventList t(&captured_events);
268     EXPECT_TRUE(t.Start());
269     EXPECT_TRUE(t.message_loop());
270     EXPECT_TRUE(t.IsRunning());
271 
272     // Register an observer that writes into |captured_events| once the
273     // thread's message loop is destroyed.
274     t.task_runner()->PostTask(
275         FROM_HERE, base::Bind(&RegisterDestructionObserver,
276                               base::Unretained(&loop_destruction_observer)));
277 
278     // Upon leaving this scope, the thread is deleted.
279   }
280 
281   // Check the order of events during shutdown.
282   ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
283   EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
284   EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
285   EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
286 }
287 
TEST_F(ThreadTest,ThreadNotStarted)288 TEST_F(ThreadTest, ThreadNotStarted) {
289   Thread a("Inert");
290   EXPECT_FALSE(a.task_runner());
291 }
292 
TEST_F(ThreadTest,MultipleWaitUntilThreadStarted)293 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) {
294   Thread a("MultipleWaitUntilThreadStarted");
295   EXPECT_TRUE(a.Start());
296   // It's OK to call WaitUntilThreadStarted() multiple times.
297   EXPECT_TRUE(a.WaitUntilThreadStarted());
298   EXPECT_TRUE(a.WaitUntilThreadStarted());
299 }
300