xref: /aosp_15_r20/external/pigweed/pw_thread/thread_facade_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/binary_semaphore.h"
16*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/non_portable_test_thread_options.h"
17*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/thread.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
19*61c4878aSAndroid Build Coastguard Worker 
20*61c4878aSAndroid Build Coastguard Worker namespace {
21*61c4878aSAndroid Build Coastguard Worker 
22*61c4878aSAndroid Build Coastguard Worker using ::pw::sync::BinarySemaphore;
23*61c4878aSAndroid Build Coastguard Worker using ::pw::thread::ThreadCore;
24*61c4878aSAndroid Build Coastguard Worker using ::pw::thread::test::TestOptionsThread0;
25*61c4878aSAndroid Build Coastguard Worker using ::pw::thread::test::TestOptionsThread1;
26*61c4878aSAndroid Build Coastguard Worker using ::pw::thread::test::WaitUntilDetachedThreadsCleanedUp;
27*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,DefaultIds)28*61c4878aSAndroid Build Coastguard Worker TEST(Thread, DefaultIds) {
29*61c4878aSAndroid Build Coastguard Worker   pw::Thread not_executing_thread;
30*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(not_executing_thread.get_id(), pw::Thread::id());
31*61c4878aSAndroid Build Coastguard Worker }
32*61c4878aSAndroid Build Coastguard Worker 
33*61c4878aSAndroid Build Coastguard Worker #if PW_THREAD_JOINING_ENABLED
TEST(Thread,DefaultConstructedThreadIsNotJoinable)34*61c4878aSAndroid Build Coastguard Worker TEST(Thread, DefaultConstructedThreadIsNotJoinable) {
35*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread;
36*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(thread.joinable());
37*61c4878aSAndroid Build Coastguard Worker }
38*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,JoinWaitsForLambdaCompletion)39*61c4878aSAndroid Build Coastguard Worker TEST(Thread, JoinWaitsForLambdaCompletion) {
40*61c4878aSAndroid Build Coastguard Worker   BinarySemaphore thread_ran;
41*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread(TestOptionsThread0(),
42*61c4878aSAndroid Build Coastguard Worker                     [&thread_ran] { thread_ran.release(); });
43*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(thread.joinable());
44*61c4878aSAndroid Build Coastguard Worker   thread.join();
45*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread.get_id(), pw::Thread::id());
46*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(thread_ran.try_acquire());
47*61c4878aSAndroid Build Coastguard Worker }
48*61c4878aSAndroid Build Coastguard Worker 
49*61c4878aSAndroid Build Coastguard Worker #endif  // PW_THREAD_JOINING_ENABLED
50*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,DetachAllowsThreadToRunAfterExitingScope)51*61c4878aSAndroid Build Coastguard Worker TEST(Thread, DetachAllowsThreadToRunAfterExitingScope) {
52*61c4878aSAndroid Build Coastguard Worker   struct {
53*61c4878aSAndroid Build Coastguard Worker     BinarySemaphore thread_blocker;
54*61c4878aSAndroid Build Coastguard Worker     BinarySemaphore thread_finished;
55*61c4878aSAndroid Build Coastguard Worker   } semaphores;
56*61c4878aSAndroid Build Coastguard Worker   {
57*61c4878aSAndroid Build Coastguard Worker     pw::Thread thread(TestOptionsThread0(), [&semaphores] {
58*61c4878aSAndroid Build Coastguard Worker       semaphores.thread_blocker.acquire();
59*61c4878aSAndroid Build Coastguard Worker       semaphores.thread_finished.release();
60*61c4878aSAndroid Build Coastguard Worker     });
61*61c4878aSAndroid Build Coastguard Worker     EXPECT_NE(thread.get_id(), pw::Thread::id());
62*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(thread.joinable());
63*61c4878aSAndroid Build Coastguard Worker     thread.detach();
64*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(thread.get_id(), pw::Thread::id());
65*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(thread.joinable());
66*61c4878aSAndroid Build Coastguard Worker   }
67*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(semaphores.thread_finished.try_acquire());
68*61c4878aSAndroid Build Coastguard Worker   semaphores.thread_blocker.release();
69*61c4878aSAndroid Build Coastguard Worker   semaphores.thread_finished.acquire();
70*61c4878aSAndroid Build Coastguard Worker 
71*61c4878aSAndroid Build Coastguard Worker   WaitUntilDetachedThreadsCleanedUp();
72*61c4878aSAndroid Build Coastguard Worker }
73*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,SwapWithoutExecution)74*61c4878aSAndroid Build Coastguard Worker TEST(Thread, SwapWithoutExecution) {
75*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_0;
76*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_1;
77*61c4878aSAndroid Build Coastguard Worker 
78*61c4878aSAndroid Build Coastguard Worker   // Make sure we can swap threads which are not associated with any execution.
79*61c4878aSAndroid Build Coastguard Worker   thread_0.swap(thread_1);
80*61c4878aSAndroid Build Coastguard Worker }
81*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,SwapWithOneExecuting)82*61c4878aSAndroid Build Coastguard Worker TEST(Thread, SwapWithOneExecuting) {
83*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_0;
84*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_0.get_id(), pw::Thread::id());
85*61c4878aSAndroid Build Coastguard Worker 
86*61c4878aSAndroid Build Coastguard Worker   BinarySemaphore thread_ran_sem;
87*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_1(TestOptionsThread1(),
88*61c4878aSAndroid Build Coastguard Worker                       [&thread_ran_sem] { thread_ran_sem.release(); });
89*61c4878aSAndroid Build Coastguard Worker 
90*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread_1.get_id(), pw::Thread::id());
91*61c4878aSAndroid Build Coastguard Worker 
92*61c4878aSAndroid Build Coastguard Worker   thread_0.swap(thread_1);
93*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread_0.get_id(), pw::Thread::id());
94*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_1.get_id(), pw::Thread::id());
95*61c4878aSAndroid Build Coastguard Worker 
96*61c4878aSAndroid Build Coastguard Worker   thread_0.detach();
97*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_0.get_id(), pw::Thread::id());
98*61c4878aSAndroid Build Coastguard Worker 
99*61c4878aSAndroid Build Coastguard Worker   thread_ran_sem.acquire();
100*61c4878aSAndroid Build Coastguard Worker   WaitUntilDetachedThreadsCleanedUp();
101*61c4878aSAndroid Build Coastguard Worker }
102*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,SwapWithTwoExecuting)103*61c4878aSAndroid Build Coastguard Worker TEST(Thread, SwapWithTwoExecuting) {
104*61c4878aSAndroid Build Coastguard Worker   BinarySemaphore thread_a_ran_sem;
105*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_0(TestOptionsThread0(),
106*61c4878aSAndroid Build Coastguard Worker                       [&thread_a_ran_sem] { thread_a_ran_sem.release(); });
107*61c4878aSAndroid Build Coastguard Worker   BinarySemaphore thread_b_ran_sem;
108*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_1(TestOptionsThread1(),
109*61c4878aSAndroid Build Coastguard Worker                       [&thread_b_ran_sem] { thread_b_ran_sem.release(); });
110*61c4878aSAndroid Build Coastguard Worker   const pw::Thread::id thread_a_id = thread_0.get_id();
111*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread_a_id, pw::Thread::id());
112*61c4878aSAndroid Build Coastguard Worker   const pw::Thread::id thread_b_id = thread_1.get_id();
113*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread_b_id, pw::Thread::id());
114*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread_a_id, thread_b_id);
115*61c4878aSAndroid Build Coastguard Worker 
116*61c4878aSAndroid Build Coastguard Worker   thread_0.swap(thread_1);
117*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_1.get_id(), thread_a_id);
118*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_0.get_id(), thread_b_id);
119*61c4878aSAndroid Build Coastguard Worker 
120*61c4878aSAndroid Build Coastguard Worker   thread_0.detach();
121*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_0.get_id(), pw::Thread::id());
122*61c4878aSAndroid Build Coastguard Worker   thread_1.detach();
123*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_1.get_id(), pw::Thread::id());
124*61c4878aSAndroid Build Coastguard Worker 
125*61c4878aSAndroid Build Coastguard Worker   thread_a_ran_sem.acquire();
126*61c4878aSAndroid Build Coastguard Worker   thread_b_ran_sem.acquire();
127*61c4878aSAndroid Build Coastguard Worker   WaitUntilDetachedThreadsCleanedUp();
128*61c4878aSAndroid Build Coastguard Worker }
129*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,MoveOperator)130*61c4878aSAndroid Build Coastguard Worker TEST(Thread, MoveOperator) {
131*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_0;
132*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_0.get_id(), pw::Thread::id());
133*61c4878aSAndroid Build Coastguard Worker 
134*61c4878aSAndroid Build Coastguard Worker   BinarySemaphore thread_ran_sem;
135*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_1(TestOptionsThread1(),
136*61c4878aSAndroid Build Coastguard Worker                       [&thread_ran_sem] { thread_ran_sem.release(); });
137*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread_1.get_id(), pw::Thread::id());
138*61c4878aSAndroid Build Coastguard Worker 
139*61c4878aSAndroid Build Coastguard Worker   thread_0 = std::move(thread_1);
140*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread_0.get_id(), pw::Thread::id());
141*61c4878aSAndroid Build Coastguard Worker #ifndef __clang_analyzer__
142*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_1.get_id(), pw::Thread::id());
143*61c4878aSAndroid Build Coastguard Worker #endif  // ignore use-after-move
144*61c4878aSAndroid Build Coastguard Worker 
145*61c4878aSAndroid Build Coastguard Worker   thread_0.detach();
146*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread_0.get_id(), pw::Thread::id());
147*61c4878aSAndroid Build Coastguard Worker 
148*61c4878aSAndroid Build Coastguard Worker   thread_ran_sem.acquire();
149*61c4878aSAndroid Build Coastguard Worker   WaitUntilDetachedThreadsCleanedUp();
150*61c4878aSAndroid Build Coastguard Worker }
151*61c4878aSAndroid Build Coastguard Worker 
152*61c4878aSAndroid Build Coastguard Worker class SemaphoreReleaser : public ThreadCore {
153*61c4878aSAndroid Build Coastguard Worker  public:
semaphore()154*61c4878aSAndroid Build Coastguard Worker   BinarySemaphore& semaphore() { return semaphore_; }
155*61c4878aSAndroid Build Coastguard Worker 
156*61c4878aSAndroid Build Coastguard Worker  private:
Run()157*61c4878aSAndroid Build Coastguard Worker   void Run() override { semaphore_.release(); }
158*61c4878aSAndroid Build Coastguard Worker 
159*61c4878aSAndroid Build Coastguard Worker   BinarySemaphore semaphore_;
160*61c4878aSAndroid Build Coastguard Worker };
161*61c4878aSAndroid Build Coastguard Worker 
TEST(Thread,ThreadCore)162*61c4878aSAndroid Build Coastguard Worker TEST(Thread, ThreadCore) {
163*61c4878aSAndroid Build Coastguard Worker   SemaphoreReleaser semaphore_releaser;
164*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread(TestOptionsThread0(), semaphore_releaser);
165*61c4878aSAndroid Build Coastguard Worker   EXPECT_NE(thread.get_id(), pw::Thread::id());
166*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(thread.joinable());
167*61c4878aSAndroid Build Coastguard Worker   thread.detach();
168*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(thread.get_id(), pw::Thread::id());
169*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(thread.joinable());
170*61c4878aSAndroid Build Coastguard Worker   semaphore_releaser.semaphore().acquire();
171*61c4878aSAndroid Build Coastguard Worker 
172*61c4878aSAndroid Build Coastguard Worker   WaitUntilDetachedThreadsCleanedUp();
173*61c4878aSAndroid Build Coastguard Worker }
174*61c4878aSAndroid Build Coastguard Worker 
175*61c4878aSAndroid Build Coastguard Worker }  // namespace
176