blob: ea57362e0d21f483905d561983063834e2f81900 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/mutex/mutex.h"
Brian Silverman653491d2014-05-13 16:53:29 -07002
Brian Silverman653491d2014-05-13 16:53:29 -07003#include <pthread.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08004#include <sched.h>
Brian Silverman653491d2014-05-13 16:53:29 -07005
Austin Schuhf2a50ba2016-12-24 16:16:26 -08006#include <chrono>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07007#include <cmath>
Brian Silverman119b3b12015-03-29 17:26:05 -04008#include <thread>
9
Philipp Schrader790cb542023-07-05 21:06:52 -070010#include "gtest/gtest.h"
11
John Park33858a32018-09-28 23:05:48 -070012#include "aos/die.h"
John Park398c74a2018-10-20 21:17:39 -070013#include "aos/ipc_lib/aos_sync.h"
14#include "aos/ipc_lib/core_lib.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050015#include "aos/testing/test_logging.h"
Brian Silverman71c55c52014-08-19 14:31:59 -040016#include "aos/testing/test_shm.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070017#include "aos/time/time.h"
18#include "aos/util/death_test_log_implementation.h"
Brian Silverman653491d2014-05-13 16:53:29 -070019
20namespace aos {
21namespace testing {
22
Austin Schuhf2a50ba2016-12-24 16:16:26 -080023namespace chrono = ::std::chrono;
24namespace this_thread = ::std::this_thread;
25
Brian Silverman653491d2014-05-13 16:53:29 -070026class MutexTest : public ::testing::Test {
27 public:
Brian Silverman1dfe48b2014-09-06 16:13:02 -040028 Mutex test_mutex_;
Brian Silverman653491d2014-05-13 16:53:29 -070029
30 protected:
31 void SetUp() override {
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050032 ::aos::testing::EnableTestLogging();
Brian Silverman653491d2014-05-13 16:53:29 -070033 SetDieTestMode(true);
34 }
35};
36
37typedef MutexTest MutexDeathTest;
Brian Silvermandc1eb272014-08-19 14:25:59 -040038typedef MutexTest MutexLockerTest;
39typedef MutexTest MutexLockerDeathTest;
40typedef MutexTest IPCMutexLockerTest;
41typedef MutexTest IPCMutexLockerDeathTest;
Brian Silverman1dfe48b2014-09-06 16:13:02 -040042typedef MutexTest IPCRecursiveMutexLockerTest;
Brian Silverman653491d2014-05-13 16:53:29 -070043
44TEST_F(MutexTest, TryLock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040045 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Daniel Petti88a15662015-04-12 17:42:22 -040046 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040047
Brian Silverman1dfe48b2014-09-06 16:13:02 -040048 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070049}
50
51TEST_F(MutexTest, Lock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040052 ASSERT_FALSE(test_mutex_.Lock());
Daniel Petti88a15662015-04-12 17:42:22 -040053 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040054
Brian Silverman1dfe48b2014-09-06 16:13:02 -040055 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070056}
57
58TEST_F(MutexTest, Unlock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040059 ASSERT_FALSE(test_mutex_.Lock());
Daniel Petti88a15662015-04-12 17:42:22 -040060 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040061 test_mutex_.Unlock();
62 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040063
Brian Silverman1dfe48b2014-09-06 16:13:02 -040064 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070065}
66
67// Sees what happens with multiple unlocks.
68TEST_F(MutexDeathTest, RepeatUnlock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040069 ASSERT_FALSE(test_mutex_.Lock());
70 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070071 EXPECT_DEATH(
72 {
Austin Schuha0c41ba2020-09-10 22:59:14 -070073 logging::SetImplementation(
74 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040075 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070076 },
77 ".*multiple unlock.*");
78}
79
80// Sees what happens if you unlock without ever locking (or unlocking) it.
81TEST_F(MutexDeathTest, NeverLock) {
Brian Silverman653491d2014-05-13 16:53:29 -070082 EXPECT_DEATH(
83 {
Austin Schuha0c41ba2020-09-10 22:59:14 -070084 logging::SetImplementation(
85 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040086 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070087 },
88 ".*multiple unlock.*");
89}
90
Brian Silverman71c55c52014-08-19 14:31:59 -040091// Tests that locking a mutex multiple times from the same thread fails nicely.
Brian Silvermandc1eb272014-08-19 14:25:59 -040092TEST_F(MutexDeathTest, RepeatLock) {
93 EXPECT_DEATH(
94 {
Austin Schuha0c41ba2020-09-10 22:59:14 -070095 logging::SetImplementation(
96 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040097 ASSERT_FALSE(test_mutex_.Lock());
98 ASSERT_FALSE(test_mutex_.Lock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040099 },
100 ".*multiple lock.*");
Brian Silverman653491d2014-05-13 16:53:29 -0700101}
102
Brian Silverman71c55c52014-08-19 14:31:59 -0400103// Tests that Lock behaves correctly when the previous owner exits with the lock
104// held (which is the same as dying any other way).
105TEST_F(MutexTest, OwnerDiedDeathLock) {
106 testing::TestSharedMemory my_shm;
107 Mutex *mutex =
108 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
109 new (mutex) Mutex();
110
Austin Schuha0c41ba2020-09-10 22:59:14 -0700111 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800112 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400113 EXPECT_TRUE(mutex->Lock());
114
115 mutex->Unlock();
116 mutex->~Mutex();
117}
118
119// Tests that TryLock behaves correctly when the previous owner dies.
120TEST_F(MutexTest, OwnerDiedDeathTryLock) {
121 testing::TestSharedMemory my_shm;
122 Mutex *mutex =
123 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
124 new (mutex) Mutex();
125
Austin Schuha0c41ba2020-09-10 22:59:14 -0700126 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800127 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400128 EXPECT_EQ(Mutex::State::kOwnerDied, mutex->TryLock());
129
130 mutex->Unlock();
131 mutex->~Mutex();
132}
133
134// TODO(brians): Test owner dying by being SIGKILLed and SIGTERMed.
135
136// This sequence of mutex operations used to mess up the robust list and cause
137// one of the mutexes to not get owner-died like it should.
138TEST_F(MutexTest, DontCorruptRobustList) {
139 // I think this was the allocator lock in the original failure.
140 Mutex mutex1;
141 // This one should get owner-died afterwards (iff the kernel accepts the
142 // robust list and uses it). I think it was the task_death_notification lock
143 // in the original failure.
144 Mutex mutex2;
145
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800146 std::thread thread([&]() {
Brian Silverman71c55c52014-08-19 14:31:59 -0400147 ASSERT_FALSE(mutex1.Lock());
148 ASSERT_FALSE(mutex2.Lock());
149 mutex1.Unlock();
150 });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800151 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400152
153 EXPECT_EQ(Mutex::State::kLocked, mutex1.TryLock());
154 EXPECT_EQ(Mutex::State::kOwnerDied, mutex2.TryLock());
155
156 mutex1.Unlock();
157 mutex2.Unlock();
158}
159
Brian Silverman653491d2014-05-13 16:53:29 -0700160// Verifies that ThreadSanitizer understands that a contended mutex establishes
161// a happens-before relationship.
162TEST_F(MutexTest, ThreadSanitizerContended) {
163 int counter = 0;
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800164 std::thread thread1([this, &counter]() {
165 std::this_thread::sleep_for(std::chrono::milliseconds(200));
166 MutexLocker locker(&test_mutex_);
167 ++counter;
168 });
169 std::thread thread2([this, &counter]() {
170 MutexLocker locker(&test_mutex_);
171 ++counter;
172 });
173 thread1.join();
174 thread2.join();
Brian Silverman653491d2014-05-13 16:53:29 -0700175 EXPECT_EQ(2, counter);
176}
177
Brian Silverman119b3b12015-03-29 17:26:05 -0400178// Verifiers that ThreadSanitizer understands how a mutex works.
179// For some reason this used to fail when the other tests didn't...
Brian Silverman71c55c52014-08-19 14:31:59 -0400180// The loops make it fail more reliably when it's going to.
Brian Silverman119b3b12015-03-29 17:26:05 -0400181TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
Brian Silverman71c55c52014-08-19 14:31:59 -0400182 for (int i = 0; i < 100; ++i) {
183 int counter = 0;
184 ::std::thread thread([&counter, this]() {
185 for (int i = 0; i < 300; ++i) {
186 MutexLocker locker(&test_mutex_);
187 ++counter;
188 }
189 });
190 for (int i = 0; i < 300; ++i) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400191 MutexLocker locker(&test_mutex_);
Brian Silverman71c55c52014-08-19 14:31:59 -0400192 --counter;
Brian Silverman119b3b12015-03-29 17:26:05 -0400193 }
Brian Silverman71c55c52014-08-19 14:31:59 -0400194 thread.join();
195 EXPECT_EQ(0, counter);
Brian Silverman119b3b12015-03-29 17:26:05 -0400196 }
Brian Silverman119b3b12015-03-29 17:26:05 -0400197}
198
Brian Silverman653491d2014-05-13 16:53:29 -0700199// Verifies that ThreadSanitizer understands that an uncontended mutex
200// establishes a happens-before relationship.
201TEST_F(MutexTest, ThreadSanitizerUncontended) {
202 int counter = 0;
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800203 std::thread thread1([this, &counter]() {
204 MutexLocker locker(&test_mutex_);
205 ++counter;
206 });
207 std::thread thread2([this, &counter]() {
208 std::this_thread::sleep_for(std::chrono::milliseconds(200));
209 MutexLocker locker(&test_mutex_);
210 ++counter;
211 });
212 thread1.join();
213 thread2.join();
Brian Silverman653491d2014-05-13 16:53:29 -0700214 EXPECT_EQ(2, counter);
215}
216
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400217// Makes sure that we don't SIGSEGV or something with multiple threads.
218TEST_F(MutexTest, MultiThreadedLock) {
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800219 std::thread thread([this] {
220 ASSERT_FALSE(test_mutex_.Lock());
221 test_mutex_.Unlock();
222 });
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400223 ASSERT_FALSE(test_mutex_.Lock());
224 test_mutex_.Unlock();
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800225 thread.join();
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400226}
227
Brian Silvermandc1eb272014-08-19 14:25:59 -0400228TEST_F(MutexLockerTest, Basic) {
229 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400230 aos::MutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400231 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400232 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400233 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400234
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400235 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400236}
237
Brian Silverman71c55c52014-08-19 14:31:59 -0400238// Tests that MutexLocker behaves correctly when the previous owner dies.
239TEST_F(MutexLockerDeathTest, OwnerDied) {
240 testing::TestSharedMemory my_shm;
241 Mutex *mutex =
242 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
243 new (mutex) Mutex();
244
Austin Schuha0c41ba2020-09-10 22:59:14 -0700245 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800246 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400247 EXPECT_DEATH(
248 {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700249 logging::SetImplementation(
250 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman71c55c52014-08-19 14:31:59 -0400251 MutexLocker locker(mutex);
252 },
253 ".*previous owner of mutex [^ ]+ died.*");
254
255 mutex->~Mutex();
256}
257
Brian Silvermandc1eb272014-08-19 14:25:59 -0400258TEST_F(IPCMutexLockerTest, Basic) {
259 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400260 aos::IPCMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400261 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400262 EXPECT_FALSE(locker.owner_died());
263 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400264 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400265
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400266 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400267}
268
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400269// Tests what happens when the caller doesn't check if the previous owner died
270// with an IPCMutexLocker.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400271TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400272 EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex_); },
Brian Silvermandc1eb272014-08-19 14:25:59 -0400273 "nobody checked if the previous owner of mutex [^ ]+ died.*");
274}
275
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400276TEST_F(IPCRecursiveMutexLockerTest, Basic) {
277 {
278 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400279 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400280 EXPECT_FALSE(locker.owner_died());
281 }
282 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
283
284 test_mutex_.Unlock();
285}
286
287// Tests actually locking a mutex recursively with IPCRecursiveMutexLocker.
288TEST_F(IPCRecursiveMutexLockerTest, RecursiveLock) {
289 {
290 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400291 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400292 {
293 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400294 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400295 EXPECT_FALSE(locker.owner_died());
296 }
Daniel Petti88a15662015-04-12 17:42:22 -0400297 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400298 EXPECT_FALSE(locker.owner_died());
299 }
300 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
301
302 test_mutex_.Unlock();
303}
304
Brian Silverman71c55c52014-08-19 14:31:59 -0400305// Tests that IPCMutexLocker behaves correctly when the previous owner dies.
306TEST_F(IPCMutexLockerTest, OwnerDied) {
307 testing::TestSharedMemory my_shm;
308 Mutex *mutex =
309 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
310 new (mutex) Mutex();
311
Austin Schuha0c41ba2020-09-10 22:59:14 -0700312 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800313 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400314 {
315 aos::IPCMutexLocker locker(mutex);
316 EXPECT_EQ(Mutex::State::kLockFailed, mutex->TryLock());
317 EXPECT_TRUE(locker.owner_died());
318 }
319 EXPECT_EQ(Mutex::State::kLocked, mutex->TryLock());
320
321 mutex->Unlock();
322 mutex->~Mutex();
323}
324
Brian Silverman653491d2014-05-13 16:53:29 -0700325} // namespace testing
326} // namespace aos