xref: /aosp_15_r20/external/cronet/base/threading/simple_thread_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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