1 // Copyright 2012 The Chromium Authors
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 <memory>
6
7 #include "base/atomic_sequence_num.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/memory/raw_ptr.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/test/gtest_util.h"
13 #include "base/threading/simple_thread.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace base {
17
18 namespace {
19
20 class SetIntRunner : public DelegateSimpleThread::Delegate {
21 public:
SetIntRunner(int * ptr,int val)22 SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
23
24 SetIntRunner(const SetIntRunner&) = delete;
25 SetIntRunner& operator=(const SetIntRunner&) = delete;
26
27 ~SetIntRunner() override = default;
28
29 private:
Run()30 void Run() override { *ptr_ = val_; }
31
32 raw_ptr<int> ptr_;
33 int val_;
34 };
35
36 // Signals |started_| when Run() is invoked and waits until |released_| is
37 // signaled to return, signaling |done_| before doing so. Useful for tests that
38 // care to control Run()'s flow.
39 class ControlledRunner : public DelegateSimpleThread::Delegate {
40 public:
ControlledRunner()41 ControlledRunner()
42 : started_(WaitableEvent::ResetPolicy::MANUAL,
43 WaitableEvent::InitialState::NOT_SIGNALED),
44 released_(WaitableEvent::ResetPolicy::MANUAL,
45 WaitableEvent::InitialState::NOT_SIGNALED),
46 done_(WaitableEvent::ResetPolicy::MANUAL,
47 WaitableEvent::InitialState::NOT_SIGNALED) {}
48
49 ControlledRunner(const ControlledRunner&) = delete;
50 ControlledRunner& operator=(const ControlledRunner&) = delete;
51
~ControlledRunner()52 ~ControlledRunner() override { ReleaseAndWaitUntilDone(); }
53
WaitUntilStarted()54 void WaitUntilStarted() { started_.Wait(); }
55
ReleaseAndWaitUntilDone()56 void ReleaseAndWaitUntilDone() {
57 released_.Signal();
58 done_.Wait();
59 }
60
61 private:
Run()62 void Run() override {
63 started_.Signal();
64 released_.Wait();
65 done_.Signal();
66 }
67
68 WaitableEvent started_;
69 WaitableEvent released_;
70 WaitableEvent done_;
71 };
72
73 class WaitEventRunner : public DelegateSimpleThread::Delegate {
74 public:
WaitEventRunner(WaitableEvent * event)75 explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
76
77 WaitEventRunner(const WaitEventRunner&) = delete;
78 WaitEventRunner& operator=(const WaitEventRunner&) = delete;
79
80 ~WaitEventRunner() override = default;
81
82 private:
Run()83 void Run() override {
84 EXPECT_FALSE(event_->IsSignaled());
85 event_->Signal();
86 EXPECT_TRUE(event_->IsSignaled());
87 }
88
89 raw_ptr<WaitableEvent> event_;
90 };
91
92 class SeqRunner : public DelegateSimpleThread::Delegate {
93 public:
SeqRunner(AtomicSequenceNumber * seq)94 explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
95
96 SeqRunner(const SeqRunner&) = delete;
97 SeqRunner& operator=(const SeqRunner&) = delete;
98
99 private:
Run()100 void Run() override { seq_->GetNext(); }
101
102 raw_ptr<AtomicSequenceNumber> seq_;
103 };
104
105 // We count up on a sequence number, firing on the event when we've hit our
106 // expected amount, otherwise we wait on the event. This will ensure that we
107 // have all threads outstanding until we hit our expected thread pool size.
108 class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
109 public:
VerifyPoolRunner(AtomicSequenceNumber * seq,int total,WaitableEvent * event)110 VerifyPoolRunner(AtomicSequenceNumber* seq,
111 int total, WaitableEvent* event)
112 : seq_(seq), total_(total), event_(event) { }
113
114 VerifyPoolRunner(const VerifyPoolRunner&) = delete;
115 VerifyPoolRunner& operator=(const VerifyPoolRunner&) = delete;
116
117 private:
Run()118 void Run() override {
119 if (seq_->GetNext() == total_) {
120 event_->Signal();
121 } else {
122 event_->Wait();
123 }
124 }
125
126 raw_ptr<AtomicSequenceNumber> seq_;
127 int total_;
128 raw_ptr<WaitableEvent> event_;
129 };
130
131 } // namespace
132
TEST(SimpleThreadTest,CreateAndJoin)133 TEST(SimpleThreadTest, CreateAndJoin) {
134 int stack_int = 0;
135
136 SetIntRunner runner(&stack_int, 7);
137 EXPECT_EQ(0, stack_int);
138
139 DelegateSimpleThread thread(&runner, "int_setter");
140 EXPECT_FALSE(thread.HasBeenStarted());
141 EXPECT_FALSE(thread.HasBeenJoined());
142 EXPECT_EQ(0, stack_int);
143
144 thread.Start();
145 EXPECT_TRUE(thread.HasBeenStarted());
146 EXPECT_FALSE(thread.HasBeenJoined());
147
148 thread.Join();
149 EXPECT_TRUE(thread.HasBeenStarted());
150 EXPECT_TRUE(thread.HasBeenJoined());
151 EXPECT_EQ(7, stack_int);
152 }
153
TEST(SimpleThreadTest,WaitForEvent)154 TEST(SimpleThreadTest, WaitForEvent) {
155 // Create a thread, and wait for it to signal us.
156 WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
157 WaitableEvent::InitialState::NOT_SIGNALED);
158
159 WaitEventRunner runner(&event);
160 DelegateSimpleThread thread(&runner, "event_waiter");
161
162 EXPECT_FALSE(event.IsSignaled());
163 thread.Start();
164 event.Wait();
165 EXPECT_TRUE(event.IsSignaled());
166 thread.Join();
167 }
168
TEST(SimpleThreadTest,NonJoinableStartAndDieOnJoin)169 TEST(SimpleThreadTest, NonJoinableStartAndDieOnJoin) {
170 ControlledRunner runner;
171
172 SimpleThread::Options options;
173 options.joinable = false;
174 DelegateSimpleThread thread(&runner, "non_joinable", options);
175
176 EXPECT_FALSE(thread.HasBeenStarted());
177 thread.Start();
178 EXPECT_TRUE(thread.HasBeenStarted());
179
180 // Note: this is not quite the same as |thread.HasBeenStarted()| which
181 // represents ThreadMain() getting ready to invoke Run() whereas
182 // |runner.WaitUntilStarted()| ensures Run() was actually invoked.
183 runner.WaitUntilStarted();
184
185 EXPECT_FALSE(thread.HasBeenJoined());
186 EXPECT_DCHECK_DEATH({ thread.Join(); });
187 }
188
TEST(SimpleThreadTest,NonJoinableInactiveDelegateDestructionIsOkay)189 TEST(SimpleThreadTest, NonJoinableInactiveDelegateDestructionIsOkay) {
190 std::unique_ptr<ControlledRunner> runner(new ControlledRunner);
191
192 SimpleThread::Options options;
193 options.joinable = false;
194 std::unique_ptr<DelegateSimpleThread> thread(
195 new DelegateSimpleThread(runner.get(), "non_joinable", options));
196
197 thread->Start();
198 runner->WaitUntilStarted();
199
200 // Deleting a non-joinable SimpleThread after Run() was invoked is okay.
201 thread.reset();
202
203 runner->WaitUntilStarted();
204 runner->ReleaseAndWaitUntilDone();
205 // It should be safe to destroy a Delegate after its Run() method completed.
206 runner.reset();
207 }
208
TEST(SimpleThreadTest,ThreadPool)209 TEST(SimpleThreadTest, ThreadPool) {
210 AtomicSequenceNumber seq;
211 SeqRunner runner(&seq);
212 DelegateSimpleThreadPool pool("seq_runner", 10);
213
214 // Add work before we're running.
215 pool.AddWork(&runner, 300);
216
217 EXPECT_EQ(seq.GetNext(), 0);
218 pool.Start();
219
220 // Add work while we're running.
221 pool.AddWork(&runner, 300);
222
223 pool.JoinAll();
224
225 EXPECT_EQ(seq.GetNext(), 601);
226
227 // We can reuse our pool. Verify that all 10 threads can actually run in
228 // parallel, so this test will only pass if there are actually 10 threads.
229 AtomicSequenceNumber seq2;
230 WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
231 WaitableEvent::InitialState::NOT_SIGNALED);
232 // Changing 9 to 10, for example, would cause us JoinAll() to never return.
233 VerifyPoolRunner verifier(&seq2, 9, &event);
234 pool.Start();
235
236 pool.AddWork(&verifier, 10);
237
238 pool.JoinAll();
239 EXPECT_EQ(seq2.GetNext(), 10);
240 }
241
242 } // namespace base
243