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