Home | History | Annotate | Download | only in threading
      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