xref: /aosp_15_r20/external/pigweed/pw_sync/binary_semaphore_facade_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 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 <chrono>
16 
17 #include "pw_chrono/system_clock.h"
18 #include "pw_sync/binary_semaphore.h"
19 #include "pw_unit_test/framework.h"
20 
21 using pw::chrono::SystemClock;
22 using namespace std::chrono_literals;
23 
24 namespace pw::sync {
25 namespace {
26 
27 extern "C" {
28 
29 // Functions defined in binary_semaphore_facade_test_c.c which call the API
30 // from C.
31 void pw_sync_BinarySemaphore_CallRelease(pw_sync_BinarySemaphore* semaphore);
32 void pw_sync_BinarySemaphore_CallAcquire(pw_sync_BinarySemaphore* semaphore);
33 bool pw_sync_BinarySemaphore_CallTryAcquire(pw_sync_BinarySemaphore* semaphore);
34 bool pw_sync_BinarySemaphore_CallTryAcquireFor(
35     pw_sync_BinarySemaphore* semaphore, pw_chrono_SystemClock_Duration timeout);
36 bool pw_sync_BinarySemaphore_CallTryAcquireUntil(
37     pw_sync_BinarySemaphore* semaphore,
38     pw_chrono_SystemClock_TimePoint deadline);
39 ptrdiff_t pw_sync_BinarySemaphore_CallMax(void);
40 
41 }  // extern "C"
42 
43 // We can't control the SystemClock's period configuration, so just in case
44 // duration cannot be accurately expressed in integer ticks, round the
45 // duration up.
46 constexpr SystemClock::duration kRoundedArbitraryDuration =
47     SystemClock::for_at_least(42ms);
48 constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
49     PW_SYSTEM_CLOCK_MS(42);
50 
TEST(BinarySemaphore,EmptyInitialState)51 TEST(BinarySemaphore, EmptyInitialState) {
52   BinarySemaphore semaphore;
53   EXPECT_FALSE(semaphore.try_acquire());
54 }
55 
56 // TODO: b/235284163 - Add real concurrency tests once we have pw::thread.
57 
TEST(BinarySemaphore,Release)58 TEST(BinarySemaphore, Release) {
59   BinarySemaphore semaphore;
60   semaphore.release();
61   semaphore.release();
62   semaphore.acquire();
63   // Ensure it fails when empty.
64   EXPECT_FALSE(semaphore.try_acquire());
65 }
66 
67 BinarySemaphore empty_initial_semaphore;
TEST(BinarySemaphore,EmptyInitialStateStatic)68 TEST(BinarySemaphore, EmptyInitialStateStatic) {
69   EXPECT_FALSE(empty_initial_semaphore.try_acquire());
70 }
71 
72 BinarySemaphore release_semaphore;
TEST(BinarySemaphore,ReleaseStatic)73 TEST(BinarySemaphore, ReleaseStatic) {
74   release_semaphore.release();
75   release_semaphore.release();
76   release_semaphore.acquire();
77   // Ensure it fails when empty.
78   EXPECT_FALSE(release_semaphore.try_acquire());
79 }
80 
TEST(BinarySemaphore,TryAcquireForFull)81 TEST(BinarySemaphore, TryAcquireForFull) {
82   BinarySemaphore semaphore;
83   semaphore.release();
84 
85   // Ensure it doesn't block and succeeds if not empty.
86   SystemClock::time_point before = SystemClock::now();
87   EXPECT_TRUE(semaphore.try_acquire_for(kRoundedArbitraryDuration));
88   SystemClock::duration time_elapsed = SystemClock::now() - before;
89   EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
90 }
91 
TEST(BinarySemaphore,TryAcquireForEmptyPositiveTimeout)92 TEST(BinarySemaphore, TryAcquireForEmptyPositiveTimeout) {
93   BinarySemaphore semaphore;
94 
95   // Ensure it blocks and fails when empty.
96   SystemClock::time_point before = SystemClock::now();
97   EXPECT_FALSE(semaphore.try_acquire_for(kRoundedArbitraryDuration));
98   SystemClock::duration time_elapsed = SystemClock::now() - before;
99   EXPECT_GE(time_elapsed, kRoundedArbitraryDuration);
100 }
101 
TEST(BinarySemaphore,TryAcquireForEmptyZeroLengthTimeout)102 TEST(BinarySemaphore, TryAcquireForEmptyZeroLengthTimeout) {
103   BinarySemaphore semaphore;
104 
105   // Ensure it doesn't block and fails when empty and a zero length duration is
106   // used.
107   SystemClock::time_point before = SystemClock::now();
108   EXPECT_FALSE(semaphore.try_acquire_for(SystemClock::duration::zero()));
109   SystemClock::duration time_elapsed = SystemClock::now() - before;
110   EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
111 }
112 
TEST(BinarySemaphore,TryAcquireForEmptyNegativeTimeout)113 TEST(BinarySemaphore, TryAcquireForEmptyNegativeTimeout) {
114   BinarySemaphore semaphore;
115 
116   // Ensure it doesn't block and fails when empty and a negative duration is
117   // used.
118   SystemClock::time_point before = SystemClock::now();
119   EXPECT_FALSE(semaphore.try_acquire_for(-kRoundedArbitraryDuration));
120   SystemClock::duration time_elapsed = SystemClock::now() - before;
121   EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
122 }
123 
TEST(BinarySemaphore,TryAcquireUntilFull)124 TEST(BinarySemaphore, TryAcquireUntilFull) {
125   BinarySemaphore semaphore;
126   semaphore.release();
127 
128   // Ensure it doesn't block and succeeds if not empty.
129   SystemClock::time_point deadline =
130       SystemClock::now() + kRoundedArbitraryDuration;
131   EXPECT_TRUE(semaphore.try_acquire_until(deadline));
132   EXPECT_LT(SystemClock::now(), deadline);
133 }
134 
TEST(BinarySemaphore,TryAcquireUntilEmptyFutureDeadline)135 TEST(BinarySemaphore, TryAcquireUntilEmptyFutureDeadline) {
136   BinarySemaphore semaphore;
137 
138   // Ensure it blocks and fails when empty.
139   SystemClock::time_point deadline =
140       SystemClock::now() + kRoundedArbitraryDuration;
141   EXPECT_FALSE(semaphore.try_acquire_until(deadline));
142   EXPECT_GE(SystemClock::now(), deadline);
143 }
144 
TEST(BinarySemaphore,TryAcquireUntilEmptyCurrentDeadline)145 TEST(BinarySemaphore, TryAcquireUntilEmptyCurrentDeadline) {
146   BinarySemaphore semaphore;
147 
148   // Ensure it doesn't block and fails when empty and now is used.
149   SystemClock::time_point deadline =
150       SystemClock::now() + kRoundedArbitraryDuration;
151   EXPECT_FALSE(semaphore.try_acquire_until(SystemClock::now()));
152   EXPECT_LT(SystemClock::now(), deadline);
153 }
154 
TEST(BinarySemaphore,TryAcquireUntilEmptyPastDeadline)155 TEST(BinarySemaphore, TryAcquireUntilEmptyPastDeadline) {
156   BinarySemaphore semaphore;
157 
158   // Ensure it doesn't block and fails when empty and a timestamp in the past is
159   // used.
160   SystemClock::time_point deadline =
161       SystemClock::now() + kRoundedArbitraryDuration;
162   EXPECT_FALSE(semaphore.try_acquire_until(SystemClock::now() -
163                                            kRoundedArbitraryDuration));
164   EXPECT_LT(SystemClock::now(), deadline);
165 }
166 
TEST(BinarySemaphore,EmptyInitialStateInC)167 TEST(BinarySemaphore, EmptyInitialStateInC) {
168   BinarySemaphore semaphore;
169   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquire(&semaphore));
170 }
171 
TEST(BinarySemaphore,ReleaseInC)172 TEST(BinarySemaphore, ReleaseInC) {
173   BinarySemaphore semaphore;
174   pw_sync_BinarySemaphore_CallRelease(&semaphore);
175   pw_sync_BinarySemaphore_CallRelease(&semaphore);
176   pw_sync_BinarySemaphore_CallAcquire(&semaphore);
177   // Ensure it fails when empty.
178   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquire(&semaphore));
179 }
180 
TEST(BinarySemaphore,TryAcquireForFullInC)181 TEST(BinarySemaphore, TryAcquireForFullInC) {
182   BinarySemaphore semaphore;
183   pw_sync_BinarySemaphore_CallRelease(&semaphore);
184 
185   // Ensure it doesn't block and succeeds if not empty.
186   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
187   ASSERT_TRUE(pw_sync_BinarySemaphore_CallTryAcquireFor(
188       &semaphore, kRoundedArbitraryDurationInC));
189   pw_chrono_SystemClock_Duration time_elapsed =
190       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
191   EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
192 }
193 
TEST(BinarySemaphore,TryAcquireForEmptyPositiveTimeoutInC)194 TEST(BinarySemaphore, TryAcquireForEmptyPositiveTimeoutInC) {
195   BinarySemaphore semaphore;
196 
197   // Ensure it blocks and fails when empty.
198   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
199   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquireFor(
200       &semaphore, kRoundedArbitraryDurationInC));
201   pw_chrono_SystemClock_Duration time_elapsed =
202       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
203   EXPECT_GE(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
204 }
205 
TEST(BinarySemaphore,TryAcquireForEmptyZeroLengthTimeoutInC)206 TEST(BinarySemaphore, TryAcquireForEmptyZeroLengthTimeoutInC) {
207   BinarySemaphore semaphore;
208 
209   // Ensure it doesn't block and fails when empty and a zero length duration is
210   // used.
211   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
212   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquireFor(
213       &semaphore, PW_SYSTEM_CLOCK_MS(0)));
214   pw_chrono_SystemClock_Duration time_elapsed =
215       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
216   EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
217 }
218 
TEST(BinarySemaphore,TryAcquireForEmptyNegativeTimeoutInC)219 TEST(BinarySemaphore, TryAcquireForEmptyNegativeTimeoutInC) {
220   BinarySemaphore semaphore;
221 
222   // Ensure it doesn't block and fails when empty and a negative duration is
223   // used.
224   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
225   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquireFor(
226       &semaphore, PW_SYSTEM_CLOCK_MS(-kRoundedArbitraryDurationInC.ticks)));
227   pw_chrono_SystemClock_Duration time_elapsed =
228       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
229   EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
230 }
231 
TEST(BinarySemaphore,TryAcquireUntilFullInC)232 TEST(BinarySemaphore, TryAcquireUntilFullInC) {
233   BinarySemaphore semaphore;
234   pw_sync_BinarySemaphore_CallRelease(&semaphore);
235 
236   pw_chrono_SystemClock_TimePoint deadline;
237   deadline.duration_since_epoch.ticks =
238       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
239       kRoundedArbitraryDurationInC.ticks;
240   ASSERT_TRUE(
241       pw_sync_BinarySemaphore_CallTryAcquireUntil(&semaphore, deadline));
242   EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
243             deadline.duration_since_epoch.ticks);
244 }
245 
TEST(BinarySemaphore,TryAcquireUntilEmptyFutureDeadlineInC)246 TEST(BinarySemaphore, TryAcquireUntilEmptyFutureDeadlineInC) {
247   BinarySemaphore semaphore;
248 
249   // Ensure it blocks and fails when empty.
250   pw_chrono_SystemClock_TimePoint deadline;
251   deadline.duration_since_epoch.ticks =
252       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
253       kRoundedArbitraryDurationInC.ticks;
254   EXPECT_FALSE(
255       pw_sync_BinarySemaphore_CallTryAcquireUntil(&semaphore, deadline));
256   EXPECT_GE(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
257             deadline.duration_since_epoch.ticks);
258 }
259 
TEST(BinarySemaphore,TryAcquireUntilEmptyCurrentDeadlineInC)260 TEST(BinarySemaphore, TryAcquireUntilEmptyCurrentDeadlineInC) {
261   BinarySemaphore semaphore;
262 
263   // Ensure it doesn't block and fails when empty and now is used.
264   pw_chrono_SystemClock_TimePoint deadline;
265   deadline.duration_since_epoch.ticks =
266       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
267       kRoundedArbitraryDurationInC.ticks;
268   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquireUntil(
269       &semaphore, pw_chrono_SystemClock_Now()));
270   EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
271             deadline.duration_since_epoch.ticks);
272 }
273 
TEST(BinarySemaphore,TryAcquireUntilEmptyPastDeadlineInC)274 TEST(BinarySemaphore, TryAcquireUntilEmptyPastDeadlineInC) {
275   BinarySemaphore semaphore;
276 
277   // Ensure it doesn't block and fails when empty and a timestamp in the past is
278   // used.
279   pw_chrono_SystemClock_TimePoint deadline;
280   deadline.duration_since_epoch.ticks =
281       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
282       kRoundedArbitraryDurationInC.ticks;
283   pw_chrono_SystemClock_TimePoint old_timestamp;
284   old_timestamp.duration_since_epoch.ticks =
285       pw_chrono_SystemClock_Now().duration_since_epoch.ticks -
286       kRoundedArbitraryDurationInC.ticks;
287   EXPECT_FALSE(
288       pw_sync_BinarySemaphore_CallTryAcquireUntil(&semaphore, old_timestamp));
289   EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
290             deadline.duration_since_epoch.ticks);
291 }
292 
TEST(BinarySemaphore,MaxInC)293 TEST(BinarySemaphore, MaxInC) {
294   EXPECT_EQ(BinarySemaphore::max(), pw_sync_BinarySemaphore_Max());
295 }
296 
297 }  // namespace
298 }  // namespace pw::sync
299