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