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