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