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