• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gtest/gtest.h"
18 #include "pw_chrono/system_clock.h"
19 #include "pw_sync/binary_semaphore.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,
36     pw_chrono_SystemClock_Duration for_at_least);
37 bool pw_sync_BinarySemaphore_CallTryAcquireUntil(
38     pw_sync_BinarySemaphore* semaphore,
39     pw_chrono_SystemClock_TimePoint until_at_least);
40 ptrdiff_t pw_sync_BinarySemaphore_CallMax(void);
41 
42 }  // extern "C"
43 
44 // We can't control the SystemClock's period configuration, so just in case
45 // duration cannot be accurately expressed in integer ticks, round the
46 // duration up.
47 constexpr SystemClock::duration kRoundedArbitraryDuration =
48     SystemClock::for_at_least(42ms);
49 constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
50     PW_SYSTEM_CLOCK_MS(42);
51 
TEST(BinarySemaphore,EmptyInitialState)52 TEST(BinarySemaphore, EmptyInitialState) {
53   BinarySemaphore semaphore;
54   EXPECT_FALSE(semaphore.try_acquire());
55 }
56 
57 // TODO(pwbug/291): Add real concurrency tests once we have pw::thread.
58 
TEST(BinarySemaphore,Release)59 TEST(BinarySemaphore, Release) {
60   BinarySemaphore semaphore;
61   semaphore.release();
62   semaphore.release();
63   semaphore.acquire();
64   // Ensure it fails when empty.
65   EXPECT_FALSE(semaphore.try_acquire());
66 }
67 
68 BinarySemaphore empty_initial_semaphore;
TEST(BinarySemaphore,EmptyInitialStateStatic)69 TEST(BinarySemaphore, EmptyInitialStateStatic) {
70   EXPECT_FALSE(empty_initial_semaphore.try_acquire());
71 }
72 
73 BinarySemaphore release_semaphore;
TEST(BinarySemaphore,ReleaseStatic)74 TEST(BinarySemaphore, ReleaseStatic) {
75   release_semaphore.release();
76   release_semaphore.release();
77   release_semaphore.acquire();
78   // Ensure it fails when empty.
79   EXPECT_FALSE(release_semaphore.try_acquire());
80 }
81 
TEST(BinarySemaphore,TryAcquireFor)82 TEST(BinarySemaphore, TryAcquireFor) {
83   BinarySemaphore semaphore;
84   semaphore.release();
85 
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   // Ensure it blocks and fails when empty.
92   before = SystemClock::now();
93   EXPECT_FALSE(semaphore.try_acquire_for(kRoundedArbitraryDuration));
94   time_elapsed = SystemClock::now() - before;
95   EXPECT_GE(time_elapsed, kRoundedArbitraryDuration);
96 }
97 
TEST(BinarySemaphore,TryAcquireUntil)98 TEST(BinarySemaphore, TryAcquireUntil) {
99   BinarySemaphore semaphore;
100   semaphore.release();
101 
102   const SystemClock::time_point deadline =
103       SystemClock::now() + kRoundedArbitraryDuration;
104   EXPECT_TRUE(semaphore.try_acquire_until(deadline));
105   EXPECT_LT(SystemClock::now(), deadline);
106 
107   // Ensure it blocks and fails when empty.
108   EXPECT_FALSE(semaphore.try_acquire_until(deadline));
109   EXPECT_GE(SystemClock::now(), deadline);
110 }
111 
TEST(BinarySemaphore,EmptyInitialStateInC)112 TEST(BinarySemaphore, EmptyInitialStateInC) {
113   BinarySemaphore semaphore;
114   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquire(&semaphore));
115 }
116 
TEST(BinarySemaphore,ReleaseInC)117 TEST(BinarySemaphore, ReleaseInC) {
118   BinarySemaphore semaphore;
119   pw_sync_BinarySemaphore_CallRelease(&semaphore);
120   pw_sync_BinarySemaphore_CallRelease(&semaphore);
121   pw_sync_BinarySemaphore_CallAcquire(&semaphore);
122   // Ensure it fails when empty.
123   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquire(&semaphore));
124 }
125 
TEST(BinarySemaphore,TryAcquireForInC)126 TEST(BinarySemaphore, TryAcquireForInC) {
127   BinarySemaphore semaphore;
128   pw_sync_BinarySemaphore_CallRelease(&semaphore);
129 
130   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
131   ASSERT_TRUE(pw_sync_BinarySemaphore_CallTryAcquireFor(
132       &semaphore, kRoundedArbitraryDurationInC));
133   pw_chrono_SystemClock_Duration time_elapsed =
134       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
135   EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
136 
137   // Ensure it blocks and fails when empty.
138   before = pw_chrono_SystemClock_Now();
139   EXPECT_FALSE(pw_sync_BinarySemaphore_CallTryAcquireFor(
140       &semaphore, kRoundedArbitraryDurationInC));
141   time_elapsed =
142       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
143   EXPECT_GE(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
144 }
145 
TEST(BinarySemaphore,TryAcquireUntilInC)146 TEST(BinarySemaphore, TryAcquireUntilInC) {
147   BinarySemaphore semaphore;
148   pw_sync_BinarySemaphore_CallRelease(&semaphore);
149 
150   pw_chrono_SystemClock_TimePoint deadline;
151   deadline.duration_since_epoch = {
152       .ticks = pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
153                kRoundedArbitraryDurationInC.ticks,
154   };
155   ASSERT_TRUE(
156       pw_sync_BinarySemaphore_CallTryAcquireUntil(&semaphore, deadline));
157   EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
158             deadline.duration_since_epoch.ticks);
159 
160   // Ensure it blocks and fails when empty.
161   EXPECT_FALSE(
162       pw_sync_BinarySemaphore_CallTryAcquireUntil(&semaphore, deadline));
163   EXPECT_GE(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
164             deadline.duration_since_epoch.ticks);
165 }
166 
TEST(BinarySemaphore,MaxInC)167 TEST(BinarySemaphore, MaxInC) {
168   EXPECT_EQ(BinarySemaphore::max(), pw_sync_BinarySemaphore_Max());
169 }
170 
171 }  // namespace
172 }  // namespace pw::sync
173