1 // Copyright (c) 2006-2008 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 <vector>
8
9 #include "base/message_loop.h"
10 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "testing/platform_test.h"
13
14 using base::Thread;
15
16 typedef PlatformTest ThreadTest;
17
18 namespace {
19
20 class ToggleValue : public Task {
21 public:
ToggleValue(bool * value)22 explicit ToggleValue(bool* value) : value_(value) {
23 ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean "
24 "in base/thread_unittest");
25 }
Run()26 virtual void Run() {
27 *value_ = !*value_;
28 }
29 private:
30 bool* value_;
31 };
32
33 class SleepSome : public Task {
34 public:
SleepSome(int msec)35 explicit SleepSome(int msec) : msec_(msec) {
36 }
Run()37 virtual void Run() {
38 base::PlatformThread::Sleep(msec_);
39 }
40 private:
41 int msec_;
42 };
43
44 class SleepInsideInitThread : public Thread {
45 public:
SleepInsideInitThread()46 SleepInsideInitThread() : Thread("none") { init_called_ = false; }
~SleepInsideInitThread()47 virtual ~SleepInsideInitThread() { }
48
Init()49 virtual void Init() {
50 base::PlatformThread::Sleep(500);
51 init_called_ = true;
52 }
InitCalled()53 bool InitCalled() { return init_called_; }
54 private:
55 bool init_called_;
56 };
57
58 enum ThreadEvent {
59 // Thread::Init() was called.
60 THREAD_EVENT_INIT = 0,
61
62 // The MessageLoop for the thread was deleted.
63 THREAD_EVENT_MESSAGE_LOOP_DESTROYED,
64
65 // Thread::CleanUp() was called.
66 THREAD_EVENT_CLEANUP,
67
68 // Keep at end of list.
69 THREAD_NUM_EVENTS
70 };
71
72 typedef std::vector<ThreadEvent> EventList;
73
74 class CaptureToEventList : public Thread {
75 public:
76 // This Thread pushes events into the vector |event_list| to show
77 // the order they occured in. |event_list| must remain valid for the
78 // lifetime of this thread.
CaptureToEventList(EventList * event_list)79 explicit CaptureToEventList(EventList* event_list)
80 : Thread("none"), event_list_(event_list) {
81 }
82
~CaptureToEventList()83 virtual ~CaptureToEventList() {
84 // Must call Stop() manually to have our CleanUp() function called.
85 Stop();
86 }
87
Init()88 virtual void Init() {
89 event_list_->push_back(THREAD_EVENT_INIT);
90 }
91
CleanUp()92 virtual void CleanUp() {
93 event_list_->push_back(THREAD_EVENT_CLEANUP);
94 }
95
96 private:
97 EventList* event_list_;
98 };
99
100 // Observer that writes a value into |event_list| when a message loop has been
101 // destroyed.
102 class CapturingDestructionObserver : public MessageLoop::DestructionObserver {
103 public:
104 // |event_list| must remain valid throughout the observer's lifetime.
CapturingDestructionObserver(EventList * event_list)105 explicit CapturingDestructionObserver(EventList* event_list)
106 : event_list_(event_list) {
107 }
108
109 // DestructionObserver implementation:
WillDestroyCurrentMessageLoop()110 virtual void WillDestroyCurrentMessageLoop() {
111 event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED);
112 event_list_ = NULL;
113 }
114
115 private:
116 EventList* event_list_;
117 };
118
119 // Task that adds a destruction observer to the current message loop.
120 class RegisterDestructionObserver : public Task {
121 public:
RegisterDestructionObserver(MessageLoop::DestructionObserver * observer)122 explicit RegisterDestructionObserver(
123 MessageLoop::DestructionObserver* observer)
124 : observer_(observer) {
125 }
126
Run()127 virtual void Run() {
128 MessageLoop::current()->AddDestructionObserver(observer_);
129 observer_ = NULL;
130 }
131
132 private:
133 MessageLoop::DestructionObserver* observer_;
134 };
135
136 } // namespace
137
TEST_F(ThreadTest,Restart)138 TEST_F(ThreadTest, Restart) {
139 Thread a("Restart");
140 a.Stop();
141 EXPECT_FALSE(a.message_loop());
142 EXPECT_FALSE(a.IsRunning());
143 EXPECT_TRUE(a.Start());
144 EXPECT_TRUE(a.message_loop());
145 EXPECT_TRUE(a.IsRunning());
146 a.Stop();
147 EXPECT_FALSE(a.message_loop());
148 EXPECT_FALSE(a.IsRunning());
149 EXPECT_TRUE(a.Start());
150 EXPECT_TRUE(a.message_loop());
151 EXPECT_TRUE(a.IsRunning());
152 a.Stop();
153 EXPECT_FALSE(a.message_loop());
154 EXPECT_FALSE(a.IsRunning());
155 a.Stop();
156 EXPECT_FALSE(a.message_loop());
157 EXPECT_FALSE(a.IsRunning());
158 }
159
TEST_F(ThreadTest,StartWithOptions_StackSize)160 TEST_F(ThreadTest, StartWithOptions_StackSize) {
161 Thread a("StartWithStackSize");
162 // Ensure that the thread can work with only 12 kb and still process a
163 // message.
164 Thread::Options options;
165 options.stack_size = 12*1024;
166 EXPECT_TRUE(a.StartWithOptions(options));
167 EXPECT_TRUE(a.message_loop());
168 EXPECT_TRUE(a.IsRunning());
169
170 bool was_invoked = false;
171 a.message_loop()->PostTask(FROM_HERE, new ToggleValue(&was_invoked));
172
173 // wait for the task to run (we could use a kernel event here
174 // instead to avoid busy waiting, but this is sufficient for
175 // testing purposes).
176 for (int i = 100; i >= 0 && !was_invoked; --i) {
177 base::PlatformThread::Sleep(10);
178 }
179 EXPECT_TRUE(was_invoked);
180 }
181
TEST_F(ThreadTest,TwoTasks)182 TEST_F(ThreadTest, TwoTasks) {
183 bool was_invoked = false;
184 {
185 Thread a("TwoTasks");
186 EXPECT_TRUE(a.Start());
187 EXPECT_TRUE(a.message_loop());
188
189 // Test that all events are dispatched before the Thread object is
190 // destroyed. We do this by dispatching a sleep event before the
191 // event that will toggle our sentinel value.
192 a.message_loop()->PostTask(FROM_HERE, new SleepSome(20));
193 a.message_loop()->PostTask(FROM_HERE, new ToggleValue(&was_invoked));
194 }
195 EXPECT_TRUE(was_invoked);
196 }
197
TEST_F(ThreadTest,StopSoon)198 TEST_F(ThreadTest, StopSoon) {
199 Thread a("StopSoon");
200 EXPECT_TRUE(a.Start());
201 EXPECT_TRUE(a.message_loop());
202 EXPECT_TRUE(a.IsRunning());
203 a.StopSoon();
204 a.StopSoon();
205 a.Stop();
206 EXPECT_FALSE(a.message_loop());
207 EXPECT_FALSE(a.IsRunning());
208 }
209
TEST_F(ThreadTest,ThreadName)210 TEST_F(ThreadTest, ThreadName) {
211 Thread a("ThreadName");
212 EXPECT_TRUE(a.Start());
213 EXPECT_EQ("ThreadName", a.thread_name());
214 }
215
216 // Make sure we can't use a thread between Start() and Init().
TEST_F(ThreadTest,SleepInsideInit)217 TEST_F(ThreadTest, SleepInsideInit) {
218 SleepInsideInitThread t;
219 EXPECT_FALSE(t.InitCalled());
220 t.Start();
221 EXPECT_TRUE(t.InitCalled());
222 }
223
224 // Make sure that the destruction sequence is:
225 //
226 // (1) Thread::CleanUp()
227 // (2) MessageLoop::~MessageLoop()
228 // MessageLoop::DestructionObservers called.
TEST_F(ThreadTest,CleanUp)229 TEST_F(ThreadTest, CleanUp) {
230 EventList captured_events;
231 CapturingDestructionObserver loop_destruction_observer(&captured_events);
232
233 {
234 // Start a thread which writes its event into |captured_events|.
235 CaptureToEventList t(&captured_events);
236 EXPECT_TRUE(t.Start());
237 EXPECT_TRUE(t.message_loop());
238 EXPECT_TRUE(t.IsRunning());
239
240 // Register an observer that writes into |captured_events| once the
241 // thread's message loop is destroyed.
242 t.message_loop()->PostTask(
243 FROM_HERE,
244 new RegisterDestructionObserver(&loop_destruction_observer));
245
246 // Upon leaving this scope, the thread is deleted.
247 }
248
249 // Check the order of events during shutdown.
250 ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
251 EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
252 EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
253 EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
254 }
255