1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
17 #include "gtest/gtest.h"
18 #include "pw_chrono/system_clock.h"
19 #include "pw_sync/counting_semaphore.h"
21 using pw::chrono::SystemClock;
22 using namespace std::chrono_literals;
29 // Functions defined in counting_semaphore_facade_test_c.c which call the API
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 for_at_least);
42 bool pw_sync_CountingSemaphore_CallTryAcquireUntil(
43 pw_sync_CountingSemaphore* semaphore,
44 pw_chrono_SystemClock_TimePoint until_at_least);
45 ptrdiff_t pw_sync_CountingSemaphore_CallMax(void);
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
52 constexpr auto kRoundedArbitraryDuration =
53 std::chrono::ceil<SystemClock::duration>(42ms);
54 constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
55 PW_SYSTEM_CLOCK_MS(42);
57 TEST(CountingSemaphore, EmptyInitialState) {
58 CountingSemaphore semaphore;
59 EXPECT_FALSE(semaphore.try_acquire());
62 // TODO(pwbug/291): Add real concurrency tests once we have pw::thread.
64 TEST(CountingSemaphore, SingleRelease) {
65 CountingSemaphore semaphore;
70 // Ensure it fails when empty.
71 EXPECT_FALSE(semaphore.try_acquire());
74 CountingSemaphore empty_initial_semaphore;
75 TEST(CountingSemaphore, EmptyInitialStateStatic) {
76 EXPECT_FALSE(empty_initial_semaphore.try_acquire());
79 CountingSemaphore release_semaphore;
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());
89 TEST(CountingSemaphore, MultiRelease) {
90 CountingSemaphore semaphore;
96 // Ensure it fails when empty.
97 EXPECT_FALSE(semaphore.try_acquire());
100 TEST(CountingSemaphore, TryAcquireFor) {
101 CountingSemaphore semaphore;
104 SystemClock::time_point before = SystemClock::now();
105 EXPECT_TRUE(semaphore.try_acquire_for(kRoundedArbitraryDuration));
106 SystemClock::duration time_elapsed = SystemClock::now() - before;
107 EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
109 // Ensure it blocks and fails when empty.
110 before = SystemClock::now();
111 EXPECT_FALSE(semaphore.try_acquire_for(kRoundedArbitraryDuration));
112 time_elapsed = SystemClock::now() - before;
113 EXPECT_GE(time_elapsed, kRoundedArbitraryDuration);
116 TEST(CountingSemaphore, TryAcquireUntil) {
117 CountingSemaphore semaphore;
120 const SystemClock::time_point deadline =
121 SystemClock::now() + kRoundedArbitraryDuration;
122 EXPECT_TRUE(semaphore.try_acquire_until(deadline));
123 EXPECT_LT(SystemClock::now(), deadline);
125 // Ensure it blocks and fails when empty.
126 EXPECT_FALSE(semaphore.try_acquire_until(deadline));
127 EXPECT_GE(SystemClock::now(), deadline);
130 TEST(CountingSemaphore, EmptyInitialStateInC) {
131 CountingSemaphore semaphore;
132 EXPECT_FALSE(pw_sync_CountingSemaphore_CallTryAcquire(&semaphore));
135 TEST(CountingSemaphore, SingeReleaseInC) {
136 CountingSemaphore semaphore;
137 pw_sync_CountingSemaphore_CallRelease(&semaphore);
138 pw_sync_CountingSemaphore_CallRelease(&semaphore);
139 pw_sync_CountingSemaphore_CallAcquire(&semaphore);
140 pw_sync_CountingSemaphore_CallAcquire(&semaphore);
141 // Ensure it fails when empty.
142 EXPECT_FALSE(pw_sync_CountingSemaphore_CallTryAcquire(&semaphore));
145 TEST(CountingSemaphore, MultiReleaseInC) {
146 CountingSemaphore semaphore;
147 pw_sync_CountingSemaphore_CallReleaseNum(&semaphore, 2);
148 pw_sync_CountingSemaphore_CallReleaseNum(&semaphore, 1);
149 pw_sync_CountingSemaphore_CallAcquire(&semaphore);
150 pw_sync_CountingSemaphore_CallAcquire(&semaphore);
151 pw_sync_CountingSemaphore_CallAcquire(&semaphore);
152 // Ensure it fails when empty.
153 EXPECT_FALSE(pw_sync_CountingSemaphore_CallTryAcquire(&semaphore));
156 TEST(CountingSemaphore, TryAcquireForInC) {
157 CountingSemaphore semaphore;
158 pw_sync_CountingSemaphore_CallRelease(&semaphore);
160 pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
161 ASSERT_TRUE(pw_sync_CountingSemaphore_CallTryAcquireFor(
162 &semaphore, kRoundedArbitraryDurationInC));
163 pw_chrono_SystemClock_Duration time_elapsed =
164 pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
165 EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
167 // Ensure it blocks and fails when empty.
168 before = pw_chrono_SystemClock_Now();
169 EXPECT_FALSE(pw_sync_CountingSemaphore_CallTryAcquireFor(
170 &semaphore, kRoundedArbitraryDurationInC));
172 pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
173 EXPECT_GE(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
176 TEST(CountingSemaphore, TryAcquireUntilInC) {
177 CountingSemaphore semaphore;
178 pw_sync_CountingSemaphore_CallRelease(&semaphore);
180 pw_chrono_SystemClock_TimePoint deadline;
181 deadline.duration_since_epoch = {
182 .ticks = pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
183 kRoundedArbitraryDurationInC.ticks,
186 pw_sync_CountingSemaphore_CallTryAcquireUntil(&semaphore, deadline));
187 EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
188 deadline.duration_since_epoch.ticks);
190 // Ensure it blocks and fails when empty.
192 pw_sync_CountingSemaphore_CallTryAcquireUntil(&semaphore, deadline));
193 EXPECT_GE(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
194 deadline.duration_since_epoch.ticks);
197 TEST(CountingSemaphore, MaxInC) {
198 EXPECT_EQ(CountingSemaphore::max(), pw_sync_CountingSemaphore_Max());
202 } // namespace pw::sync