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