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/atomic_sequence_num.h"
      6 #include "base/strings/string_number_conversions.h"
      7 #include "base/synchronization/waitable_event.h"
      8 #include "base/threading/simple_thread.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace base {
     12 
     13 namespace {
     14 
     15 class SetIntRunner : public DelegateSimpleThread::Delegate {
     16  public:
     17   SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
     18   virtual ~SetIntRunner() { }
     19 
     20   virtual void Run() OVERRIDE {
     21     *ptr_ = val_;
     22   }
     23 
     24  private:
     25   int* ptr_;
     26   int val_;
     27 };
     28 
     29 class WaitEventRunner : public DelegateSimpleThread::Delegate {
     30  public:
     31   explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
     32   virtual ~WaitEventRunner() { }
     33 
     34   virtual void Run() OVERRIDE {
     35     EXPECT_FALSE(event_->IsSignaled());
     36     event_->Signal();
     37     EXPECT_TRUE(event_->IsSignaled());
     38   }
     39  private:
     40   WaitableEvent* event_;
     41 };
     42 
     43 class SeqRunner : public DelegateSimpleThread::Delegate {
     44  public:
     45   explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
     46   virtual void Run() OVERRIDE {
     47     seq_->GetNext();
     48   }
     49 
     50  private:
     51   AtomicSequenceNumber* seq_;
     52 };
     53 
     54 // We count up on a sequence number, firing on the event when we've hit our
     55 // expected amount, otherwise we wait on the event.  This will ensure that we
     56 // have all threads outstanding until we hit our expected thread pool size.
     57 class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
     58  public:
     59   VerifyPoolRunner(AtomicSequenceNumber* seq,
     60                    int total, WaitableEvent* event)
     61       : seq_(seq), total_(total), event_(event) { }
     62 
     63   virtual void Run() OVERRIDE {
     64     if (seq_->GetNext() == total_) {
     65       event_->Signal();
     66     } else {
     67       event_->Wait();
     68     }
     69   }
     70 
     71  private:
     72   AtomicSequenceNumber* seq_;
     73   int total_;
     74   WaitableEvent* event_;
     75 };
     76 
     77 }  // namespace
     78 
     79 TEST(SimpleThreadTest, CreateAndJoin) {
     80   int stack_int = 0;
     81 
     82   SetIntRunner runner(&stack_int, 7);
     83   EXPECT_EQ(0, stack_int);
     84 
     85   DelegateSimpleThread thread(&runner, "int_setter");
     86   EXPECT_FALSE(thread.HasBeenStarted());
     87   EXPECT_FALSE(thread.HasBeenJoined());
     88   EXPECT_EQ(0, stack_int);
     89 
     90   thread.Start();
     91   EXPECT_TRUE(thread.HasBeenStarted());
     92   EXPECT_FALSE(thread.HasBeenJoined());
     93 
     94   thread.Join();
     95   EXPECT_TRUE(thread.HasBeenStarted());
     96   EXPECT_TRUE(thread.HasBeenJoined());
     97   EXPECT_EQ(7, stack_int);
     98 }
     99 
    100 TEST(SimpleThreadTest, WaitForEvent) {
    101   // Create a thread, and wait for it to signal us.
    102   WaitableEvent event(true, false);
    103 
    104   WaitEventRunner runner(&event);
    105   DelegateSimpleThread thread(&runner, "event_waiter");
    106 
    107   EXPECT_FALSE(event.IsSignaled());
    108   thread.Start();
    109   event.Wait();
    110   EXPECT_TRUE(event.IsSignaled());
    111   thread.Join();
    112 }
    113 
    114 TEST(SimpleThreadTest, NamedWithOptions) {
    115   WaitableEvent event(true, false);
    116 
    117   WaitEventRunner runner(&event);
    118   SimpleThread::Options options;
    119   DelegateSimpleThread thread(&runner, "event_waiter", options);
    120   EXPECT_EQ(thread.name_prefix(), "event_waiter");
    121   EXPECT_FALSE(event.IsSignaled());
    122 
    123   thread.Start();
    124   EXPECT_EQ(thread.name_prefix(), "event_waiter");
    125   EXPECT_EQ(thread.name(),
    126             std::string("event_waiter/") + IntToString(thread.tid()));
    127   event.Wait();
    128 
    129   EXPECT_TRUE(event.IsSignaled());
    130   thread.Join();
    131 
    132   // We keep the name and tid, even after the thread is gone.
    133   EXPECT_EQ(thread.name_prefix(), "event_waiter");
    134   EXPECT_EQ(thread.name(),
    135             std::string("event_waiter/") + IntToString(thread.tid()));
    136 }
    137 
    138 TEST(SimpleThreadTest, ThreadPool) {
    139   AtomicSequenceNumber seq;
    140   SeqRunner runner(&seq);
    141   DelegateSimpleThreadPool pool("seq_runner", 10);
    142 
    143   // Add work before we're running.
    144   pool.AddWork(&runner, 300);
    145 
    146   EXPECT_EQ(seq.GetNext(), 0);
    147   pool.Start();
    148 
    149   // Add work while we're running.
    150   pool.AddWork(&runner, 300);
    151 
    152   pool.JoinAll();
    153 
    154   EXPECT_EQ(seq.GetNext(), 601);
    155 
    156   // We can reuse our pool.  Verify that all 10 threads can actually run in
    157   // parallel, so this test will only pass if there are actually 10 threads.
    158   AtomicSequenceNumber seq2;
    159   WaitableEvent event(true, false);
    160   // Changing 9 to 10, for example, would cause us JoinAll() to never return.
    161   VerifyPoolRunner verifier(&seq2, 9, &event);
    162   pool.Start();
    163 
    164   pool.AddWork(&verifier, 10);
    165 
    166   pool.JoinAll();
    167   EXPECT_EQ(seq2.GetNext(), 10);
    168 }
    169 
    170 }  // namespace base
    171