blob: 07de9dcb3302447c721b097abd15c5a8dd4b9d43 [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 <math.h>
4#include <pthread.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08005#include <sched.h>
Brian Silverman653491d2014-05-13 16:53:29 -07006
Austin Schuhf2a50ba2016-12-24 16:16:26 -08007#include <chrono>
Brian Silverman119b3b12015-03-29 17:26:05 -04008#include <thread>
9
Brian Silverman653491d2014-05-13 16:53:29 -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 Silverman5c201e22014-06-12 22:40:28 -070069 logging::Init();
Brian Silverman1dfe48b2014-09-06 16:13:02 -040070 ASSERT_FALSE(test_mutex_.Lock());
71 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070072 EXPECT_DEATH(
73 {
Austin Schuha0c41ba2020-09-10 22:59:14 -070074 logging::SetImplementation(
75 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040076 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070077 },
78 ".*multiple unlock.*");
79}
80
81// Sees what happens if you unlock without ever locking (or unlocking) it.
82TEST_F(MutexDeathTest, NeverLock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070083 logging::Init();
Brian Silverman653491d2014-05-13 16:53:29 -070084 EXPECT_DEATH(
85 {
Austin Schuha0c41ba2020-09-10 22:59:14 -070086 logging::SetImplementation(
87 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040088 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070089 },
90 ".*multiple unlock.*");
91}
92
Brian Silverman71c55c52014-08-19 14:31:59 -040093// Tests that locking a mutex multiple times from the same thread fails nicely.
Brian Silvermandc1eb272014-08-19 14:25:59 -040094TEST_F(MutexDeathTest, RepeatLock) {
95 EXPECT_DEATH(
96 {
Austin Schuha0c41ba2020-09-10 22:59:14 -070097 logging::SetImplementation(
98 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040099 ASSERT_FALSE(test_mutex_.Lock());
100 ASSERT_FALSE(test_mutex_.Lock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400101 },
102 ".*multiple lock.*");
Brian Silverman653491d2014-05-13 16:53:29 -0700103}
104
Brian Silverman71c55c52014-08-19 14:31:59 -0400105// Tests that Lock behaves correctly when the previous owner exits with the lock
106// held (which is the same as dying any other way).
107TEST_F(MutexTest, OwnerDiedDeathLock) {
108 testing::TestSharedMemory my_shm;
109 Mutex *mutex =
110 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
111 new (mutex) Mutex();
112
Austin Schuha0c41ba2020-09-10 22:59:14 -0700113 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800114 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400115 EXPECT_TRUE(mutex->Lock());
116
117 mutex->Unlock();
118 mutex->~Mutex();
119}
120
121// Tests that TryLock behaves correctly when the previous owner dies.
122TEST_F(MutexTest, OwnerDiedDeathTryLock) {
123 testing::TestSharedMemory my_shm;
124 Mutex *mutex =
125 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
126 new (mutex) Mutex();
127
Austin Schuha0c41ba2020-09-10 22:59:14 -0700128 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800129 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400130 EXPECT_EQ(Mutex::State::kOwnerDied, mutex->TryLock());
131
132 mutex->Unlock();
133 mutex->~Mutex();
134}
135
136// TODO(brians): Test owner dying by being SIGKILLed and SIGTERMed.
137
138// This sequence of mutex operations used to mess up the robust list and cause
139// one of the mutexes to not get owner-died like it should.
140TEST_F(MutexTest, DontCorruptRobustList) {
141 // I think this was the allocator lock in the original failure.
142 Mutex mutex1;
143 // This one should get owner-died afterwards (iff the kernel accepts the
144 // robust list and uses it). I think it was the task_death_notification lock
145 // in the original failure.
146 Mutex mutex2;
147
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800148 std::thread thread([&]() {
Brian Silverman71c55c52014-08-19 14:31:59 -0400149 ASSERT_FALSE(mutex1.Lock());
150 ASSERT_FALSE(mutex2.Lock());
151 mutex1.Unlock();
152 });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800153 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400154
155 EXPECT_EQ(Mutex::State::kLocked, mutex1.TryLock());
156 EXPECT_EQ(Mutex::State::kOwnerDied, mutex2.TryLock());
157
158 mutex1.Unlock();
159 mutex2.Unlock();
160}
161
Brian Silverman653491d2014-05-13 16:53:29 -0700162// Verifies that ThreadSanitizer understands that a contended mutex establishes
163// a happens-before relationship.
164TEST_F(MutexTest, ThreadSanitizerContended) {
165 int counter = 0;
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800166 std::thread thread1([this, &counter]() {
167 std::this_thread::sleep_for(std::chrono::milliseconds(200));
168 MutexLocker locker(&test_mutex_);
169 ++counter;
170 });
171 std::thread thread2([this, &counter]() {
172 MutexLocker locker(&test_mutex_);
173 ++counter;
174 });
175 thread1.join();
176 thread2.join();
Brian Silverman653491d2014-05-13 16:53:29 -0700177 EXPECT_EQ(2, counter);
178}
179
Brian Silverman119b3b12015-03-29 17:26:05 -0400180// Verifiers that ThreadSanitizer understands how a mutex works.
181// For some reason this used to fail when the other tests didn't...
Brian Silverman71c55c52014-08-19 14:31:59 -0400182// The loops make it fail more reliably when it's going to.
Brian Silverman119b3b12015-03-29 17:26:05 -0400183TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
Brian Silverman71c55c52014-08-19 14:31:59 -0400184 for (int i = 0; i < 100; ++i) {
185 int counter = 0;
186 ::std::thread thread([&counter, this]() {
187 for (int i = 0; i < 300; ++i) {
188 MutexLocker locker(&test_mutex_);
189 ++counter;
190 }
191 });
192 for (int i = 0; i < 300; ++i) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400193 MutexLocker locker(&test_mutex_);
Brian Silverman71c55c52014-08-19 14:31:59 -0400194 --counter;
Brian Silverman119b3b12015-03-29 17:26:05 -0400195 }
Brian Silverman71c55c52014-08-19 14:31:59 -0400196 thread.join();
197 EXPECT_EQ(0, counter);
Brian Silverman119b3b12015-03-29 17:26:05 -0400198 }
Brian Silverman119b3b12015-03-29 17:26:05 -0400199}
200
Brian Silverman653491d2014-05-13 16:53:29 -0700201// Verifies that ThreadSanitizer understands that an uncontended mutex
202// establishes a happens-before relationship.
203TEST_F(MutexTest, ThreadSanitizerUncontended) {
204 int counter = 0;
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800205 std::thread thread1([this, &counter]() {
206 MutexLocker locker(&test_mutex_);
207 ++counter;
208 });
209 std::thread thread2([this, &counter]() {
210 std::this_thread::sleep_for(std::chrono::milliseconds(200));
211 MutexLocker locker(&test_mutex_);
212 ++counter;
213 });
214 thread1.join();
215 thread2.join();
Brian Silverman653491d2014-05-13 16:53:29 -0700216 EXPECT_EQ(2, counter);
217}
218
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400219// Makes sure that we don't SIGSEGV or something with multiple threads.
220TEST_F(MutexTest, MultiThreadedLock) {
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800221 std::thread thread([this] {
222 ASSERT_FALSE(test_mutex_.Lock());
223 test_mutex_.Unlock();
224 });
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400225 ASSERT_FALSE(test_mutex_.Lock());
226 test_mutex_.Unlock();
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800227 thread.join();
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400228}
229
Brian Silvermandc1eb272014-08-19 14:25:59 -0400230TEST_F(MutexLockerTest, Basic) {
231 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400232 aos::MutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400233 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400234 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400235 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400236
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400237 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400238}
239
Brian Silverman71c55c52014-08-19 14:31:59 -0400240// Tests that MutexLocker behaves correctly when the previous owner dies.
241TEST_F(MutexLockerDeathTest, OwnerDied) {
242 testing::TestSharedMemory my_shm;
243 Mutex *mutex =
244 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
245 new (mutex) Mutex();
246
Austin Schuha0c41ba2020-09-10 22:59:14 -0700247 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800248 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400249 EXPECT_DEATH(
250 {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700251 logging::SetImplementation(
252 std::make_shared<util::DeathTestLogImplementation>());
Brian Silverman71c55c52014-08-19 14:31:59 -0400253 MutexLocker locker(mutex);
254 },
255 ".*previous owner of mutex [^ ]+ died.*");
256
257 mutex->~Mutex();
258}
259
Brian Silvermandc1eb272014-08-19 14:25:59 -0400260TEST_F(IPCMutexLockerTest, Basic) {
261 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400262 aos::IPCMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400263 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400264 EXPECT_FALSE(locker.owner_died());
265 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400266 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400267
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400268 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400269}
270
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400271// Tests what happens when the caller doesn't check if the previous owner died
272// with an IPCMutexLocker.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400273TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400274 EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex_); },
Brian Silvermandc1eb272014-08-19 14:25:59 -0400275 "nobody checked if the previous owner of mutex [^ ]+ died.*");
276}
277
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400278TEST_F(IPCRecursiveMutexLockerTest, Basic) {
279 {
280 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400281 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400282 EXPECT_FALSE(locker.owner_died());
283 }
284 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
285
286 test_mutex_.Unlock();
287}
288
289// Tests actually locking a mutex recursively with IPCRecursiveMutexLocker.
290TEST_F(IPCRecursiveMutexLockerTest, RecursiveLock) {
291 {
292 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400293 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400294 {
295 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400296 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400297 EXPECT_FALSE(locker.owner_died());
298 }
Daniel Petti88a15662015-04-12 17:42:22 -0400299 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400300 EXPECT_FALSE(locker.owner_died());
301 }
302 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
303
304 test_mutex_.Unlock();
305}
306
Brian Silverman71c55c52014-08-19 14:31:59 -0400307// Tests that IPCMutexLocker behaves correctly when the previous owner dies.
308TEST_F(IPCMutexLockerTest, OwnerDied) {
309 testing::TestSharedMemory my_shm;
310 Mutex *mutex =
311 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
312 new (mutex) Mutex();
313
Austin Schuha0c41ba2020-09-10 22:59:14 -0700314 std::thread thread([&]() { ASSERT_FALSE(mutex->Lock()); });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800315 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400316 {
317 aos::IPCMutexLocker locker(mutex);
318 EXPECT_EQ(Mutex::State::kLockFailed, mutex->TryLock());
319 EXPECT_TRUE(locker.owner_died());
320 }
321 EXPECT_EQ(Mutex::State::kLocked, mutex->TryLock());
322
323 mutex->Unlock();
324 mutex->~Mutex();
325}
326
Brian Silverman653491d2014-05-13 16:53:29 -0700327} // namespace testing
328} // namespace aos