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/mutex.h"
21 using pw::chrono::SystemClock;
22 using namespace std::chrono_literals;
29 // Functions defined in mutex_facade_test_c.c which call the API from C.
30 void pw_sync_Mutex_CallLock(pw_sync_Mutex* mutex);
31 bool pw_sync_Mutex_CallTryLock(pw_sync_Mutex* mutex);
32 bool pw_sync_Mutex_CallTryLockFor(pw_sync_Mutex* mutex,
33 pw_chrono_SystemClock_Duration for_at_least);
34 bool pw_sync_Mutex_CallTryLockUntil(
35 pw_sync_Mutex* mutex, pw_chrono_SystemClock_TimePoint until_at_least);
36 void pw_sync_Mutex_CallUnlock(pw_sync_Mutex* mutex);
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
43 constexpr auto kRoundedArbitraryDuration =
44 std::chrono::ceil<SystemClock::duration>(42ms);
45 constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
46 PW_SYSTEM_CLOCK_MS(42);
48 // TODO(pwbug/291): Add real concurrency tests once we have pw::thread.
50 TEST(Mutex, LockUnlock) {
51 pw::sync::Mutex mutex;
53 // TODO(pwbug/291): Ensure it fails to lock when already held.
54 // EXPECT_FALSE(mutex.try_lock());
59 TEST(Mutex, LockUnlockStatic) {
61 // TODO(pwbug/291): Ensure it fails to lock when already held.
62 // EXPECT_FALSE(static_mutex.try_lock());
63 static_mutex.unlock();
66 TEST(Mutex, TryLockUnlock) {
67 pw::sync::Mutex mutex;
68 ASSERT_TRUE(mutex.try_lock());
69 // TODO(pwbug/291): Ensure it fails to lock when already held.
70 // EXPECT_FALSE(mutex.try_lock());
74 TEST(Mutex, TryLockUnlockFor) {
75 pw::sync::Mutex mutex;
77 SystemClock::time_point before = SystemClock::now();
78 ASSERT_TRUE(mutex.try_lock_for(kRoundedArbitraryDuration));
79 SystemClock::duration time_elapsed = SystemClock::now() - before;
80 EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
82 // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
83 // before = SystemClock::now();
84 // EXPECT_FALSE(mutex.try_lock_for(kRoundedArbitraryDuration));
85 // time_elapsed = SystemClock::now() - before;
86 /// EXPECT_GE(time_elapsed, kRoundedArbitraryDuration);
91 TEST(Mutex, TryLockUnlockUntil) {
92 pw::sync::Mutex mutex;
94 const SystemClock::time_point deadline =
95 SystemClock::now() + kRoundedArbitraryDuration;
96 ASSERT_TRUE(mutex.try_lock_until(deadline));
97 EXPECT_LT(SystemClock::now(), deadline);
99 // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
101 // mutex.try_lock_until(SystemClock::now() + kRoundedArbitraryDuration));
102 // EXPECT_GE(SystemClock::now(), deadline);
107 TEST(Mutex, LockUnlockInC) {
108 pw::sync::Mutex mutex;
109 pw_sync_Mutex_CallLock(&mutex);
110 pw_sync_Mutex_CallUnlock(&mutex);
113 TEST(Mutex, TryLockUnlockInC) {
114 pw::sync::Mutex mutex;
115 ASSERT_TRUE(pw_sync_Mutex_CallTryLock(&mutex));
116 // TODO(pwbug/291): Ensure it fails to lock when already held.
117 // EXPECT_FALSE(pw_sync_Mutex_CallTryLock(&mutex));
118 pw_sync_Mutex_CallUnlock(&mutex);
121 TEST(Mutex, TryLockUnlockForInC) {
122 pw::sync::Mutex mutex;
124 pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
126 pw_sync_Mutex_CallTryLockFor(&mutex, kRoundedArbitraryDurationInC));
127 pw_chrono_SystemClock_Duration time_elapsed =
128 pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
129 EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
131 // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
132 // before = pw_chrono_SystemClock_Now();
134 // pw_sync_Mutex_CallTryLockFor(&mutex, kRoundedArbitraryDurationInC));
136 // pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
137 // EXPECT_GE(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
139 pw_sync_Mutex_CallUnlock(&mutex);
142 TEST(Mutex, TryLockUnlockUntilInC) {
143 pw::sync::Mutex mutex;
144 pw_chrono_SystemClock_TimePoint deadline;
145 deadline.duration_since_epoch.ticks =
146 pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
147 kRoundedArbitraryDurationInC.ticks;
148 ASSERT_TRUE(pw_sync_Mutex_CallTryLockUntil(&mutex, deadline));
149 EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
150 deadline.duration_since_epoch.ticks);
152 // TODO(pwbug/291): Ensure it blocks fails to lock when already held.
153 // EXPECT_FALSE(pw_sync_Mutex_CallTryLockUntil(&mutex, deadline));
154 // EXPECT_GE(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
155 // deadline.duration_since_epoch.ticks);
161 } // namespace pw::sync