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