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 14using base::Thread; 15 16typedef PlatformTest ThreadTest; 17 18namespace { 19 20class ToggleValue : public Task { 21 public: 22 explicit ToggleValue(bool* value) : value_(value) { 23 ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean " 24 "in base/thread_unittest"); 25 } 26 virtual void Run() { 27 *value_ = !*value_; 28 } 29 private: 30 bool* value_; 31}; 32 33class SleepSome : public Task { 34 public: 35 explicit SleepSome(int msec) : msec_(msec) { 36 } 37 virtual void Run() { 38 base::PlatformThread::Sleep(msec_); 39 } 40 private: 41 int msec_; 42}; 43 44class SleepInsideInitThread : public Thread { 45 public: 46 SleepInsideInitThread() : Thread("none") { init_called_ = false; } 47 virtual ~SleepInsideInitThread() { } 48 49 virtual void Init() { 50 base::PlatformThread::Sleep(500); 51 init_called_ = true; 52 } 53 bool InitCalled() { return init_called_; } 54 private: 55 bool init_called_; 56}; 57 58enum 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 72typedef std::vector<ThreadEvent> EventList; 73 74class 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. 79 explicit CaptureToEventList(EventList* event_list) 80 : Thread("none"), event_list_(event_list) { 81 } 82 83 virtual ~CaptureToEventList() { 84 // Must call Stop() manually to have our CleanUp() function called. 85 Stop(); 86 } 87 88 virtual void Init() { 89 event_list_->push_back(THREAD_EVENT_INIT); 90 } 91 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. 102class CapturingDestructionObserver : public MessageLoop::DestructionObserver { 103 public: 104 // |event_list| must remain valid throughout the observer's lifetime. 105 explicit CapturingDestructionObserver(EventList* event_list) 106 : event_list_(event_list) { 107 } 108 109 // DestructionObserver implementation: 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. 120class RegisterDestructionObserver : public Task { 121 public: 122 explicit RegisterDestructionObserver( 123 MessageLoop::DestructionObserver* observer) 124 : observer_(observer) { 125 } 126 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 138TEST_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 160TEST_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 182TEST_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 198TEST_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 210TEST_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(). 217TEST_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. 229TEST_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