• 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/timed_mutex.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 mutex_facade_test_c.c which call the API from C.
30 void pw_sync_TimedMutex_CallLock(pw_sync_TimedMutex* mutex);
31 bool pw_sync_TimedMutex_CallTryLock(pw_sync_TimedMutex* mutex);
32 bool pw_sync_TimedMutex_CallTryLockFor(
33     pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_Duration for_at_least);
34 bool pw_sync_TimedMutex_CallTryLockUntil(
35     pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_TimePoint until_at_least);
36 void pw_sync_TimedMutex_CallUnlock(pw_sync_TimedMutex* mutex);
37 
38 }  // extern "C"
39 
40 // We can't control the SystemClock's period configuration, so just in case
41 // duration cannot be accurately expressed in integer ticks, round the
42 // duration up.
43 constexpr SystemClock::duration kRoundedArbitraryDuration =
44     SystemClock::for_at_least(42ms);
45 constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
46     PW_SYSTEM_CLOCK_MS(42);
47 
48 // TODO(pwbug/291): Add real concurrency tests once we have pw::thread.
49 
TEST(TimedMutex,LockUnlock)50 TEST(TimedMutex, LockUnlock) {
51   pw::sync::TimedMutex mutex;
52   mutex.lock();
53   // TODO(pwbug/291): Ensure it fails to lock when already held.
54   // EXPECT_FALSE(mutex.try_lock());
55   mutex.unlock();
56 }
57 
58 TimedMutex static_mutex;
TEST(TimedMutex,LockUnlockStatic)59 TEST(TimedMutex, LockUnlockStatic) {
60   static_mutex.lock();
61   // TODO(pwbug/291): Ensure it fails to lock when already held.
62   // EXPECT_FALSE(static_mutex.try_lock());
63   static_mutex.unlock();
64 }
65 
TEST(TimedMutex,TryLockUnlock)66 TEST(TimedMutex, TryLockUnlock) {
67   pw::sync::TimedMutex mutex;
68   const bool locked = mutex.try_lock();
69   EXPECT_TRUE(locked);
70   if (locked) {
71     // TODO(pwbug/291): Ensure it fails to lock when already held.
72     // EXPECT_FALSE(mutex.try_lock());
73     mutex.unlock();
74   }
75 }
76 
TEST(TimedMutex,TryLockUnlockFor)77 TEST(TimedMutex, TryLockUnlockFor) {
78   pw::sync::TimedMutex mutex;
79 
80   SystemClock::time_point before = SystemClock::now();
81   const bool locked = mutex.try_lock_for(kRoundedArbitraryDuration);
82   EXPECT_TRUE(locked);
83   if (locked) {
84     SystemClock::duration time_elapsed = SystemClock::now() - before;
85     EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
86 
87     // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
88     // before = SystemClock::now();
89     // EXPECT_FALSE(mutex.try_lock_for(kRoundedArbitraryDuration));
90     // time_elapsed = SystemClock::now() - before;
91     /// EXPECT_GE(time_elapsed, kRoundedArbitraryDuration);
92 
93     mutex.unlock();
94   }
95 }
96 
TEST(TimedMutex,TryLockUnlockUntil)97 TEST(TimedMutex, TryLockUnlockUntil) {
98   pw::sync::TimedMutex mutex;
99 
100   const SystemClock::time_point deadline =
101       SystemClock::now() + kRoundedArbitraryDuration;
102   const bool locked = mutex.try_lock_until(deadline);
103   EXPECT_TRUE(locked);
104   if (locked) {
105     EXPECT_LT(SystemClock::now(), deadline);
106 
107     // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
108     // EXPECT_FALSE(
109     //     mutex.try_lock_until(SystemClock::now() +
110     //     kRoundedArbitraryDuration));
111     // EXPECT_GE(SystemClock::now(), deadline);
112 
113     mutex.unlock();
114   }
115 }
116 
TEST(TimedMutex,LockUnlockInC)117 TEST(TimedMutex, LockUnlockInC) {
118   pw::sync::TimedMutex mutex;
119   pw_sync_TimedMutex_CallLock(&mutex);
120   pw_sync_TimedMutex_CallUnlock(&mutex);
121 }
122 
TEST(TimedMutex,TryLockUnlockInC)123 TEST(TimedMutex, TryLockUnlockInC) {
124   pw::sync::TimedMutex mutex;
125   ASSERT_TRUE(pw_sync_TimedMutex_CallTryLock(&mutex));
126   // TODO(pwbug/291): Ensure it fails to lock when already held.
127   // EXPECT_FALSE(pw_sync_TimedMutex_CallTryLock(&mutex));
128   pw_sync_TimedMutex_CallUnlock(&mutex);
129 }
130 
TEST(TimedMutex,TryLockUnlockForInC)131 TEST(TimedMutex, TryLockUnlockForInC) {
132   pw::sync::TimedMutex mutex;
133 
134   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
135   ASSERT_TRUE(
136       pw_sync_TimedMutex_CallTryLockFor(&mutex, kRoundedArbitraryDurationInC));
137   pw_chrono_SystemClock_Duration time_elapsed =
138       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
139   EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
140 
141   // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
142   // before = pw_chrono_SystemClock_Now();
143   // EXPECT_FALSE(
144   //     pw_sync_TimedMutex_CallTryLockFor(&mutex,
145   //     kRoundedArbitraryDurationInC));
146   // time_elapsed =
147   //    pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
148   // EXPECT_GE(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
149 
150   pw_sync_TimedMutex_CallUnlock(&mutex);
151 }
152 
TEST(TimedMutex,TryLockUnlockUntilInC)153 TEST(TimedMutex, TryLockUnlockUntilInC) {
154   pw::sync::TimedMutex mutex;
155   pw_chrono_SystemClock_TimePoint deadline;
156   deadline.duration_since_epoch.ticks =
157       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
158       kRoundedArbitraryDurationInC.ticks;
159   ASSERT_TRUE(pw_sync_TimedMutex_CallTryLockUntil(&mutex, deadline));
160   EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
161             deadline.duration_since_epoch.ticks);
162 
163   // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
164   // EXPECT_FALSE(pw_sync_TimedMutex_CallTryLockUntil(&mutex, deadline));
165   // EXPECT_GE(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
166   //           deadline.duration_since_epoch.ticks);
167 
168   pw_sync_TimedMutex_CallUnlock(&mutex);
169 }
170 
171 }  // namespace
172 }  // namespace pw::sync
173