• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(WaitableEvent::ResetPolicy::MANUAL,
99                       WaitableEvent::InitialState::NOT_SIGNALED);
100 
101   WaitEventRunner runner(&event);
102   DelegateSimpleThread thread(&runner, "event_waiter");
103 
104   EXPECT_FALSE(event.IsSignaled());
105   thread.Start();
106   event.Wait();
107   EXPECT_TRUE(event.IsSignaled());
108   thread.Join();
109 }
110 
TEST(SimpleThreadTest,NamedWithOptions)111 TEST(SimpleThreadTest, NamedWithOptions) {
112   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
113                       WaitableEvent::InitialState::NOT_SIGNALED);
114 
115   WaitEventRunner runner(&event);
116   SimpleThread::Options options;
117   DelegateSimpleThread thread(&runner, "event_waiter", options);
118   EXPECT_EQ(thread.name_prefix(), "event_waiter");
119   EXPECT_FALSE(event.IsSignaled());
120 
121   thread.Start();
122   EXPECT_EQ(thread.name_prefix(), "event_waiter");
123   EXPECT_EQ(thread.name(),
124             std::string("event_waiter/") + IntToString(thread.tid()));
125   event.Wait();
126 
127   EXPECT_TRUE(event.IsSignaled());
128   thread.Join();
129 
130   // We keep the name and tid, even after the thread is gone.
131   EXPECT_EQ(thread.name_prefix(), "event_waiter");
132   EXPECT_EQ(thread.name(),
133             std::string("event_waiter/") + IntToString(thread.tid()));
134 }
135 
TEST(SimpleThreadTest,ThreadPool)136 TEST(SimpleThreadTest, ThreadPool) {
137   AtomicSequenceNumber seq;
138   SeqRunner runner(&seq);
139   DelegateSimpleThreadPool pool("seq_runner", 10);
140 
141   // Add work before we're running.
142   pool.AddWork(&runner, 300);
143 
144   EXPECT_EQ(seq.GetNext(), 0);
145   pool.Start();
146 
147   // Add work while we're running.
148   pool.AddWork(&runner, 300);
149 
150   pool.JoinAll();
151 
152   EXPECT_EQ(seq.GetNext(), 601);
153 
154   // We can reuse our pool.  Verify that all 10 threads can actually run in
155   // parallel, so this test will only pass if there are actually 10 threads.
156   AtomicSequenceNumber seq2;
157   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
158                       WaitableEvent::InitialState::NOT_SIGNALED);
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 
169 }  // namespace base
170