Home | History | Annotate | Download | only in threading
      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:
     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 
     33 class 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 
     44 class 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 
     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.
     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.
    102 class 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.
    120 class 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 
    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 
    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 
    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 
    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 
    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().
    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.
    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