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:
SetIntRunner(int * ptr,int val)17   SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
~SetIntRunner()18   ~SetIntRunner() override {}
19 
Run()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:
WaitEventRunner(WaitableEvent * event)29   explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
~WaitEventRunner()30   ~WaitEventRunner() override {}
31 
Run()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:
SeqRunner(AtomicSequenceNumber * seq)43   explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
Run()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:
VerifyPoolRunner(AtomicSequenceNumber * seq,int total,WaitableEvent * event)55   VerifyPoolRunner(AtomicSequenceNumber* seq,
56                    int total, WaitableEvent* event)
57       : seq_(seq), total_(total), event_(event) { }
58 
Run()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 
TEST(SimpleThreadTest,CreateAndJoin)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 
TEST(SimpleThreadTest,WaitForEvent)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 
TEST(SimpleThreadTest,NamedWithOptions)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 
TEST(SimpleThreadTest,ThreadPool)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