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