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 <stddef.h>
      8 
      9 #include <vector>
     10 
     11 #include "base/bind.h"
     12 #include "base/location.h"
     13 #include "base/single_thread_task_runner.h"
     14 #include "base/synchronization/waitable_event.h"
     15 #include "build/build_config.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 #include "testing/platform_test.h"
     18 
     19 using base::Thread;
     20 
     21 typedef PlatformTest ThreadTest;
     22 
     23 namespace {
     24 
     25 void ToggleValue(bool* value) {
     26   *value = !*value;
     27 }
     28 
     29 class SleepInsideInitThread : public Thread {
     30  public:
     31   SleepInsideInitThread() : Thread("none") {
     32     init_called_ = false;
     33   }
     34   ~SleepInsideInitThread() override { Stop(); }
     35 
     36   void Init() override {
     37     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
     38     init_called_ = true;
     39   }
     40   bool InitCalled() { return init_called_; }
     41  private:
     42   bool init_called_;
     43 };
     44 
     45 enum ThreadEvent {
     46   // Thread::Init() was called.
     47   THREAD_EVENT_INIT = 0,
     48 
     49   // The MessageLoop for the thread was deleted.
     50   THREAD_EVENT_MESSAGE_LOOP_DESTROYED,
     51 
     52   // Thread::CleanUp() was called.
     53   THREAD_EVENT_CLEANUP,
     54 
     55   // Keep at end of list.
     56   THREAD_NUM_EVENTS
     57 };
     58 
     59 typedef std::vector<ThreadEvent> EventList;
     60 
     61 class CaptureToEventList : public Thread {
     62  public:
     63   // This Thread pushes events into the vector |event_list| to show
     64   // the order they occured in. |event_list| must remain valid for the
     65   // lifetime of this thread.
     66   explicit CaptureToEventList(EventList* event_list)
     67       : Thread("none"),
     68         event_list_(event_list) {
     69   }
     70 
     71   ~CaptureToEventList() override { Stop(); }
     72 
     73   void Init() override { event_list_->push_back(THREAD_EVENT_INIT); }
     74 
     75   void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); }
     76 
     77  private:
     78   EventList* event_list_;
     79 };
     80 
     81 // Observer that writes a value into |event_list| when a message loop has been
     82 // destroyed.
     83 class CapturingDestructionObserver
     84     : public base::MessageLoop::DestructionObserver {
     85  public:
     86   // |event_list| must remain valid throughout the observer's lifetime.
     87   explicit CapturingDestructionObserver(EventList* event_list)
     88       : event_list_(event_list) {
     89   }
     90 
     91   // DestructionObserver implementation:
     92   void WillDestroyCurrentMessageLoop() override {
     93     event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED);
     94     event_list_ = NULL;
     95   }
     96 
     97  private:
     98   EventList* event_list_;
     99 };
    100 
    101 // Task that adds a destruction observer to the current message loop.
    102 void RegisterDestructionObserver(
    103     base::MessageLoop::DestructionObserver* observer) {
    104   base::MessageLoop::current()->AddDestructionObserver(observer);
    105 }
    106 
    107 // Task that calls GetThreadId() of |thread|, stores the result into |id|, then
    108 // signal |event|.
    109 void ReturnThreadId(base::Thread* thread,
    110                     base::PlatformThreadId* id,
    111                     base::WaitableEvent* event) {
    112   *id = thread->GetThreadId();
    113   event->Signal();
    114 }
    115 
    116 }  // namespace
    117 
    118 TEST_F(ThreadTest, Restart) {
    119   Thread a("Restart");
    120   a.Stop();
    121   EXPECT_FALSE(a.message_loop());
    122   EXPECT_FALSE(a.IsRunning());
    123   EXPECT_TRUE(a.Start());
    124   EXPECT_TRUE(a.message_loop());
    125   EXPECT_TRUE(a.IsRunning());
    126   a.Stop();
    127   EXPECT_FALSE(a.message_loop());
    128   EXPECT_FALSE(a.IsRunning());
    129   EXPECT_TRUE(a.Start());
    130   EXPECT_TRUE(a.message_loop());
    131   EXPECT_TRUE(a.IsRunning());
    132   a.Stop();
    133   EXPECT_FALSE(a.message_loop());
    134   EXPECT_FALSE(a.IsRunning());
    135   a.Stop();
    136   EXPECT_FALSE(a.message_loop());
    137   EXPECT_FALSE(a.IsRunning());
    138 }
    139 
    140 TEST_F(ThreadTest, StartWithOptions_StackSize) {
    141   Thread a("StartWithStackSize");
    142   // Ensure that the thread can work with only 12 kb and still process a
    143   // message.
    144   Thread::Options options;
    145 #if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)
    146   // ASan bloats the stack variables and overflows the 12 kb stack on OSX.
    147   options.stack_size = 24*1024;
    148 #else
    149   options.stack_size = 12*1024;
    150 #endif
    151   EXPECT_TRUE(a.StartWithOptions(options));
    152   EXPECT_TRUE(a.message_loop());
    153   EXPECT_TRUE(a.IsRunning());
    154 
    155   bool was_invoked = false;
    156   a.task_runner()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
    157 
    158   // wait for the task to run (we could use a kernel event here
    159   // instead to avoid busy waiting, but this is sufficient for
    160   // testing purposes).
    161   for (int i = 100; i >= 0 && !was_invoked; --i) {
    162     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
    163   }
    164   EXPECT_TRUE(was_invoked);
    165 }
    166 
    167 TEST_F(ThreadTest, TwoTasks) {
    168   bool was_invoked = false;
    169   {
    170     Thread a("TwoTasks");
    171     EXPECT_TRUE(a.Start());
    172     EXPECT_TRUE(a.message_loop());
    173 
    174     // Test that all events are dispatched before the Thread object is
    175     // destroyed.  We do this by dispatching a sleep event before the
    176     // event that will toggle our sentinel value.
    177     a.task_runner()->PostTask(
    178         FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>(
    179                                   &base::PlatformThread::Sleep),
    180                               base::TimeDelta::FromMilliseconds(20)));
    181     a.task_runner()->PostTask(FROM_HERE,
    182                               base::Bind(&ToggleValue, &was_invoked));
    183   }
    184   EXPECT_TRUE(was_invoked);
    185 }
    186 
    187 TEST_F(ThreadTest, StopSoon) {
    188   Thread a("StopSoon");
    189   EXPECT_TRUE(a.Start());
    190   EXPECT_TRUE(a.message_loop());
    191   EXPECT_TRUE(a.IsRunning());
    192   a.StopSoon();
    193   a.StopSoon();
    194   a.Stop();
    195   EXPECT_FALSE(a.message_loop());
    196   EXPECT_FALSE(a.IsRunning());
    197 }
    198 
    199 TEST_F(ThreadTest, ThreadName) {
    200   Thread a("ThreadName");
    201   EXPECT_TRUE(a.Start());
    202   EXPECT_EQ("ThreadName", a.thread_name());
    203 }
    204 
    205 TEST_F(ThreadTest, ThreadId) {
    206   Thread a("ThreadId0");
    207   Thread b("ThreadId1");
    208   a.Start();
    209   b.Start();
    210 
    211   // Post a task that calls GetThreadId() on the created thread.
    212   base::WaitableEvent event(false, false);
    213   base::PlatformThreadId id_from_new_thread;
    214   a.task_runner()->PostTask(
    215       FROM_HERE, base::Bind(ReturnThreadId, &a, &id_from_new_thread, &event));
    216 
    217   // Call GetThreadId() on the current thread before calling event.Wait() so
    218   // that this test can find a race issue with TSAN.
    219   base::PlatformThreadId id_from_current_thread = a.GetThreadId();
    220 
    221   // Check if GetThreadId() returns consistent value in both threads.
    222   event.Wait();
    223   EXPECT_EQ(id_from_current_thread, id_from_new_thread);
    224 
    225   // A started thread should have a valid ID.
    226   EXPECT_NE(base::kInvalidThreadId, a.GetThreadId());
    227   EXPECT_NE(base::kInvalidThreadId, b.GetThreadId());
    228 
    229   // Each thread should have a different thread ID.
    230   EXPECT_NE(a.GetThreadId(), b.GetThreadId());
    231 }
    232 
    233 TEST_F(ThreadTest, ThreadIdWithRestart) {
    234   Thread a("ThreadIdWithRestart");
    235   base::PlatformThreadId previous_id = base::kInvalidThreadId;
    236 
    237   for (size_t i = 0; i < 16; ++i) {
    238     EXPECT_TRUE(a.Start());
    239     base::PlatformThreadId current_id = a.GetThreadId();
    240     EXPECT_NE(previous_id, current_id);
    241     previous_id = current_id;
    242     a.Stop();
    243   }
    244 }
    245 
    246 // Make sure Init() is called after Start() and before
    247 // WaitUntilThreadInitialized() returns.
    248 TEST_F(ThreadTest, SleepInsideInit) {
    249   SleepInsideInitThread t;
    250   EXPECT_FALSE(t.InitCalled());
    251   t.StartAndWaitForTesting();
    252   EXPECT_TRUE(t.InitCalled());
    253 }
    254 
    255 // Make sure that the destruction sequence is:
    256 //
    257 //  (1) Thread::CleanUp()
    258 //  (2) MessageLoop::~MessageLoop()
    259 //      MessageLoop::DestructionObservers called.
    260 TEST_F(ThreadTest, CleanUp) {
    261   EventList captured_events;
    262   CapturingDestructionObserver loop_destruction_observer(&captured_events);
    263 
    264   {
    265     // Start a thread which writes its event into |captured_events|.
    266     CaptureToEventList t(&captured_events);
    267     EXPECT_TRUE(t.Start());
    268     EXPECT_TRUE(t.message_loop());
    269     EXPECT_TRUE(t.IsRunning());
    270 
    271     // Register an observer that writes into |captured_events| once the
    272     // thread's message loop is destroyed.
    273     t.task_runner()->PostTask(
    274         FROM_HERE, base::Bind(&RegisterDestructionObserver,
    275                               base::Unretained(&loop_destruction_observer)));
    276 
    277     // Upon leaving this scope, the thread is deleted.
    278   }
    279 
    280   // Check the order of events during shutdown.
    281   ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
    282   EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
    283   EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
    284   EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
    285 }
    286 
    287 TEST_F(ThreadTest, ThreadNotStarted) {
    288   Thread a("Inert");
    289   EXPECT_EQ(nullptr, a.task_runner());
    290 }
    291