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