blob: bd47ae0d4a1b7daad377dd1235d88e95c62c1081 [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 {
Tyler Chatow4b471e12020-01-05 20:19:36 -080074 logging::SetImplementation(new 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 Silverman5c201e22014-06-12 22:40:28 -070082 logging::Init();
Brian Silverman653491d2014-05-13 16:53:29 -070083 EXPECT_DEATH(
84 {
Tyler Chatow4b471e12020-01-05 20:19:36 -080085 logging::SetImplementation(new 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 {
Tyler Chatow4b471e12020-01-05 20:19:36 -080095 logging::SetImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040096 ASSERT_FALSE(test_mutex_.Lock());
97 ASSERT_FALSE(test_mutex_.Lock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040098 },
99 ".*multiple lock.*");
Brian Silverman653491d2014-05-13 16:53:29 -0700100}
101
Brian Silverman71c55c52014-08-19 14:31:59 -0400102// Tests that Lock behaves correctly when the previous owner exits with the lock
103// held (which is the same as dying any other way).
104TEST_F(MutexTest, OwnerDiedDeathLock) {
105 testing::TestSharedMemory my_shm;
106 Mutex *mutex =
107 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
108 new (mutex) Mutex();
109
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800110 std::thread thread([&]() {
Brian Silverman71c55c52014-08-19 14:31:59 -0400111 ASSERT_FALSE(mutex->Lock());
112 });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800113 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400114 EXPECT_TRUE(mutex->Lock());
115
116 mutex->Unlock();
117 mutex->~Mutex();
118}
119
120// Tests that TryLock behaves correctly when the previous owner dies.
121TEST_F(MutexTest, OwnerDiedDeathTryLock) {
122 testing::TestSharedMemory my_shm;
123 Mutex *mutex =
124 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
125 new (mutex) Mutex();
126
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800127 std::thread thread([&]() {
Brian Silverman71c55c52014-08-19 14:31:59 -0400128 ASSERT_FALSE(mutex->Lock());
129 });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800130 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400131 EXPECT_EQ(Mutex::State::kOwnerDied, mutex->TryLock());
132
133 mutex->Unlock();
134 mutex->~Mutex();
135}
136
137// TODO(brians): Test owner dying by being SIGKILLed and SIGTERMed.
138
139// This sequence of mutex operations used to mess up the robust list and cause
140// one of the mutexes to not get owner-died like it should.
141TEST_F(MutexTest, DontCorruptRobustList) {
142 // I think this was the allocator lock in the original failure.
143 Mutex mutex1;
144 // This one should get owner-died afterwards (iff the kernel accepts the
145 // robust list and uses it). I think it was the task_death_notification lock
146 // in the original failure.
147 Mutex mutex2;
148
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800149 std::thread thread([&]() {
Brian Silverman71c55c52014-08-19 14:31:59 -0400150 ASSERT_FALSE(mutex1.Lock());
151 ASSERT_FALSE(mutex2.Lock());
152 mutex1.Unlock();
153 });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800154 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400155
156 EXPECT_EQ(Mutex::State::kLocked, mutex1.TryLock());
157 EXPECT_EQ(Mutex::State::kOwnerDied, mutex2.TryLock());
158
159 mutex1.Unlock();
160 mutex2.Unlock();
161}
162
Brian Silverman653491d2014-05-13 16:53:29 -0700163// Verifies that ThreadSanitizer understands that a contended mutex establishes
164// a happens-before relationship.
165TEST_F(MutexTest, ThreadSanitizerContended) {
166 int counter = 0;
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800167 std::thread thread1([this, &counter]() {
168 std::this_thread::sleep_for(std::chrono::milliseconds(200));
169 MutexLocker locker(&test_mutex_);
170 ++counter;
171 });
172 std::thread thread2([this, &counter]() {
173 MutexLocker locker(&test_mutex_);
174 ++counter;
175 });
176 thread1.join();
177 thread2.join();
Brian Silverman653491d2014-05-13 16:53:29 -0700178 EXPECT_EQ(2, counter);
179}
180
Brian Silverman119b3b12015-03-29 17:26:05 -0400181// Verifiers that ThreadSanitizer understands how a mutex works.
182// For some reason this used to fail when the other tests didn't...
Brian Silverman71c55c52014-08-19 14:31:59 -0400183// The loops make it fail more reliably when it's going to.
Brian Silverman119b3b12015-03-29 17:26:05 -0400184TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
Brian Silverman71c55c52014-08-19 14:31:59 -0400185 for (int i = 0; i < 100; ++i) {
186 int counter = 0;
187 ::std::thread thread([&counter, this]() {
188 for (int i = 0; i < 300; ++i) {
189 MutexLocker locker(&test_mutex_);
190 ++counter;
191 }
192 });
193 for (int i = 0; i < 300; ++i) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400194 MutexLocker locker(&test_mutex_);
Brian Silverman71c55c52014-08-19 14:31:59 -0400195 --counter;
Brian Silverman119b3b12015-03-29 17:26:05 -0400196 }
Brian Silverman71c55c52014-08-19 14:31:59 -0400197 thread.join();
198 EXPECT_EQ(0, counter);
Brian Silverman119b3b12015-03-29 17:26:05 -0400199 }
Brian Silverman119b3b12015-03-29 17:26:05 -0400200}
201
Brian Silverman653491d2014-05-13 16:53:29 -0700202// Verifies that ThreadSanitizer understands that an uncontended mutex
203// establishes a happens-before relationship.
204TEST_F(MutexTest, ThreadSanitizerUncontended) {
205 int counter = 0;
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800206 std::thread thread1([this, &counter]() {
207 MutexLocker locker(&test_mutex_);
208 ++counter;
209 });
210 std::thread thread2([this, &counter]() {
211 std::this_thread::sleep_for(std::chrono::milliseconds(200));
212 MutexLocker locker(&test_mutex_);
213 ++counter;
214 });
215 thread1.join();
216 thread2.join();
Brian Silverman653491d2014-05-13 16:53:29 -0700217 EXPECT_EQ(2, counter);
218}
219
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400220// Makes sure that we don't SIGSEGV or something with multiple threads.
221TEST_F(MutexTest, MultiThreadedLock) {
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800222 std::thread thread([this] {
223 ASSERT_FALSE(test_mutex_.Lock());
224 test_mutex_.Unlock();
225 });
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400226 ASSERT_FALSE(test_mutex_.Lock());
227 test_mutex_.Unlock();
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800228 thread.join();
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400229}
230
Brian Silvermandc1eb272014-08-19 14:25:59 -0400231TEST_F(MutexLockerTest, Basic) {
232 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400233 aos::MutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400234 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400235 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400236 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400237
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400238 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400239}
240
Brian Silverman71c55c52014-08-19 14:31:59 -0400241// Tests that MutexLocker behaves correctly when the previous owner dies.
242TEST_F(MutexLockerDeathTest, OwnerDied) {
243 testing::TestSharedMemory my_shm;
244 Mutex *mutex =
245 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
246 new (mutex) Mutex();
247
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800248 std::thread thread([&]() {
Brian Silverman71c55c52014-08-19 14:31:59 -0400249 ASSERT_FALSE(mutex->Lock());
250 });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800251 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400252 EXPECT_DEATH(
253 {
Tyler Chatow4b471e12020-01-05 20:19:36 -0800254 logging::SetImplementation(new util::DeathTestLogImplementation());
Brian Silverman71c55c52014-08-19 14:31:59 -0400255 MutexLocker locker(mutex);
256 },
257 ".*previous owner of mutex [^ ]+ died.*");
258
259 mutex->~Mutex();
260}
261
Brian Silvermandc1eb272014-08-19 14:25:59 -0400262TEST_F(IPCMutexLockerTest, Basic) {
263 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400264 aos::IPCMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400265 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400266 EXPECT_FALSE(locker.owner_died());
267 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400268 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400269
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400270 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400271}
272
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400273// Tests what happens when the caller doesn't check if the previous owner died
274// with an IPCMutexLocker.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400275TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400276 EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex_); },
Brian Silvermandc1eb272014-08-19 14:25:59 -0400277 "nobody checked if the previous owner of mutex [^ ]+ died.*");
278}
279
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400280TEST_F(IPCRecursiveMutexLockerTest, Basic) {
281 {
282 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400283 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400284 EXPECT_FALSE(locker.owner_died());
285 }
286 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
287
288 test_mutex_.Unlock();
289}
290
291// Tests actually locking a mutex recursively with IPCRecursiveMutexLocker.
292TEST_F(IPCRecursiveMutexLockerTest, RecursiveLock) {
293 {
294 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400295 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400296 {
297 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400298 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400299 EXPECT_FALSE(locker.owner_died());
300 }
Daniel Petti88a15662015-04-12 17:42:22 -0400301 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400302 EXPECT_FALSE(locker.owner_died());
303 }
304 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
305
306 test_mutex_.Unlock();
307}
308
Brian Silverman71c55c52014-08-19 14:31:59 -0400309// Tests that IPCMutexLocker behaves correctly when the previous owner dies.
310TEST_F(IPCMutexLockerTest, OwnerDied) {
311 testing::TestSharedMemory my_shm;
312 Mutex *mutex =
313 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
314 new (mutex) Mutex();
315
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800316 std::thread thread([&]() {
Brian Silverman71c55c52014-08-19 14:31:59 -0400317 ASSERT_FALSE(mutex->Lock());
318 });
Kai Tinkessbf1385d2020-01-18 14:18:49 -0800319 thread.join();
Brian Silverman71c55c52014-08-19 14:31:59 -0400320 {
321 aos::IPCMutexLocker locker(mutex);
322 EXPECT_EQ(Mutex::State::kLockFailed, mutex->TryLock());
323 EXPECT_TRUE(locker.owner_died());
324 }
325 EXPECT_EQ(Mutex::State::kLocked, mutex->TryLock());
326
327 mutex->Unlock();
328 mutex->~Mutex();
329}
330
Brian Silverman653491d2014-05-13 16:53:29 -0700331} // namespace testing
332} // namespace aos