blob: 8cc4e73b5b8b13cf58c7e7304d35bc0272830502 [file] [log] [blame]
Brian Silverman653491d2014-05-13 16:53:29 -07001#include "aos/common/mutex.h"
2
3#include <sched.h>
4#include <math.h>
5#include <pthread.h>
6
Brian Silverman119b3b12015-03-29 17:26:05 -04007#include <thread>
8
Brian Silverman653491d2014-05-13 16:53:29 -07009#include "gtest/gtest.h"
10
11#include "aos/linux_code/ipc_lib/aos_sync.h"
12#include "aos/common/die.h"
13#include "aos/common/util/death_test_log_implementation.h"
14#include "aos/common/util/thread.h"
15#include "aos/common/time.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050016#include "aos/testing/test_logging.h"
Brian Silverman71c55c52014-08-19 14:31:59 -040017#include "aos/testing/test_shm.h"
Brian Silvermandc1eb272014-08-19 14:25:59 -040018#include "aos/linux_code/ipc_lib/core_lib.h"
Brian Silverman653491d2014-05-13 16:53:29 -070019
20namespace aos {
21namespace testing {
22
23class MutexTest : public ::testing::Test {
24 public:
Brian Silverman1dfe48b2014-09-06 16:13:02 -040025 Mutex test_mutex_;
Brian Silverman653491d2014-05-13 16:53:29 -070026
27 protected:
28 void SetUp() override {
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050029 ::aos::testing::EnableTestLogging();
Brian Silverman653491d2014-05-13 16:53:29 -070030 SetDieTestMode(true);
31 }
32};
33
34typedef MutexTest MutexDeathTest;
Brian Silvermandc1eb272014-08-19 14:25:59 -040035typedef MutexTest MutexLockerTest;
36typedef MutexTest MutexLockerDeathTest;
37typedef MutexTest IPCMutexLockerTest;
38typedef MutexTest IPCMutexLockerDeathTest;
Brian Silverman1dfe48b2014-09-06 16:13:02 -040039typedef MutexTest IPCRecursiveMutexLockerTest;
Brian Silverman653491d2014-05-13 16:53:29 -070040
41TEST_F(MutexTest, TryLock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040042 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Daniel Petti88a15662015-04-12 17:42:22 -040043 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040044
Brian Silverman1dfe48b2014-09-06 16:13:02 -040045 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070046}
47
48TEST_F(MutexTest, Lock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040049 ASSERT_FALSE(test_mutex_.Lock());
Daniel Petti88a15662015-04-12 17:42:22 -040050 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040051
Brian Silverman1dfe48b2014-09-06 16:13:02 -040052 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070053}
54
55TEST_F(MutexTest, Unlock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040056 ASSERT_FALSE(test_mutex_.Lock());
Daniel Petti88a15662015-04-12 17:42:22 -040057 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040058 test_mutex_.Unlock();
59 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040060
Brian Silverman1dfe48b2014-09-06 16:13:02 -040061 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070062}
63
64// Sees what happens with multiple unlocks.
65TEST_F(MutexDeathTest, RepeatUnlock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070066 logging::Init();
Brian Silverman1dfe48b2014-09-06 16:13:02 -040067 ASSERT_FALSE(test_mutex_.Lock());
68 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070069 EXPECT_DEATH(
70 {
71 logging::AddImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040072 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070073 },
74 ".*multiple unlock.*");
75}
76
77// Sees what happens if you unlock without ever locking (or unlocking) it.
78TEST_F(MutexDeathTest, NeverLock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070079 logging::Init();
Brian Silverman653491d2014-05-13 16:53:29 -070080 EXPECT_DEATH(
81 {
82 logging::AddImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040083 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070084 },
85 ".*multiple unlock.*");
86}
87
Brian Silverman71c55c52014-08-19 14:31:59 -040088// Tests that locking a mutex multiple times from the same thread fails nicely.
Brian Silvermandc1eb272014-08-19 14:25:59 -040089TEST_F(MutexDeathTest, RepeatLock) {
90 EXPECT_DEATH(
91 {
92 logging::AddImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040093 ASSERT_FALSE(test_mutex_.Lock());
94 ASSERT_FALSE(test_mutex_.Lock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040095 },
96 ".*multiple lock.*");
Brian Silverman653491d2014-05-13 16:53:29 -070097}
98
Brian Silverman71c55c52014-08-19 14:31:59 -040099// Tests that destroying a locked mutex fails nicely.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400100TEST_F(MutexDeathTest, DestroyLocked) {
101 EXPECT_DEATH(
102 {
103 logging::AddImplementation(new util::DeathTestLogImplementation());
104 Mutex new_mutex;
105 ASSERT_FALSE(new_mutex.Lock());
106 },
107 ".*destroying locked mutex.*");
Brian Silverman653491d2014-05-13 16:53:29 -0700108}
109
Brian Silverman71c55c52014-08-19 14:31:59 -0400110// Tests that Lock behaves correctly when the previous owner exits with the lock
111// held (which is the same as dying any other way).
112TEST_F(MutexTest, OwnerDiedDeathLock) {
113 testing::TestSharedMemory my_shm;
114 Mutex *mutex =
115 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
116 new (mutex) Mutex();
117
118 util::FunctionThread::RunInOtherThread([&]() {
119 ASSERT_FALSE(mutex->Lock());
120 });
121 EXPECT_TRUE(mutex->Lock());
122
123 mutex->Unlock();
124 mutex->~Mutex();
125}
126
127// Tests that TryLock behaves correctly when the previous owner dies.
128TEST_F(MutexTest, OwnerDiedDeathTryLock) {
129 testing::TestSharedMemory my_shm;
130 Mutex *mutex =
131 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
132 new (mutex) Mutex();
133
134 util::FunctionThread::RunInOtherThread([&]() {
135 ASSERT_FALSE(mutex->Lock());
136 });
137 EXPECT_EQ(Mutex::State::kOwnerDied, mutex->TryLock());
138
139 mutex->Unlock();
140 mutex->~Mutex();
141}
142
143// TODO(brians): Test owner dying by being SIGKILLed and SIGTERMed.
144
145// This sequence of mutex operations used to mess up the robust list and cause
146// one of the mutexes to not get owner-died like it should.
147TEST_F(MutexTest, DontCorruptRobustList) {
148 // I think this was the allocator lock in the original failure.
149 Mutex mutex1;
150 // This one should get owner-died afterwards (iff the kernel accepts the
151 // robust list and uses it). I think it was the task_death_notification lock
152 // in the original failure.
153 Mutex mutex2;
154
155 util::FunctionThread::RunInOtherThread([&]() {
156 ASSERT_FALSE(mutex1.Lock());
157 ASSERT_FALSE(mutex2.Lock());
158 mutex1.Unlock();
159 });
160
161 EXPECT_EQ(Mutex::State::kLocked, mutex1.TryLock());
162 EXPECT_EQ(Mutex::State::kOwnerDied, mutex2.TryLock());
163
164 mutex1.Unlock();
165 mutex2.Unlock();
166}
167
Brian Silverman653491d2014-05-13 16:53:29 -0700168namespace {
169
170class AdderThread : public ::aos::util::Thread {
171 public:
172 AdderThread(int *counter, Mutex *mutex, ::aos::time::Time sleep_before_time,
173 ::aos::time::Time sleep_after_time)
174 : counter_(counter),
175 mutex_(mutex),
176 sleep_before_time_(sleep_before_time),
177 sleep_after_time_(sleep_after_time) {}
Brian Silverman71c55c52014-08-19 14:31:59 -0400178
179 private:
Brian Silverman653491d2014-05-13 16:53:29 -0700180 virtual void Run() override {
181 ::aos::time::SleepFor(sleep_before_time_);
182 MutexLocker locker(mutex_);
183 ++(*counter_);
184 ::aos::time::SleepFor(sleep_after_time_);
185 }
186
Brian Silverman653491d2014-05-13 16:53:29 -0700187 int *const counter_;
188 Mutex *const mutex_;
189 const ::aos::time::Time sleep_before_time_, sleep_after_time_;
190};
191
192} // namespace
193
194// Verifies that ThreadSanitizer understands that a contended mutex establishes
195// a happens-before relationship.
196TEST_F(MutexTest, ThreadSanitizerContended) {
197 int counter = 0;
198 AdderThread threads[2]{
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400199 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0.2),
Brian Silverman653491d2014-05-13 16:53:29 -0700200 ::aos::time::Time::InSeconds(0)},
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400201 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0),
Brian Silverman653491d2014-05-13 16:53:29 -0700202 ::aos::time::Time::InSeconds(0)}, };
203 for (auto &c : threads) {
204 c.Start();
205 }
206 for (auto &c : threads) {
207 c.WaitUntilDone();
208 }
209 EXPECT_EQ(2, counter);
210}
211
Brian Silverman119b3b12015-03-29 17:26:05 -0400212// Verifiers that ThreadSanitizer understands how a mutex works.
213// For some reason this used to fail when the other tests didn't...
Brian Silverman71c55c52014-08-19 14:31:59 -0400214// The loops make it fail more reliably when it's going to.
Brian Silverman119b3b12015-03-29 17:26:05 -0400215TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
Brian Silverman71c55c52014-08-19 14:31:59 -0400216 for (int i = 0; i < 100; ++i) {
217 int counter = 0;
218 ::std::thread thread([&counter, this]() {
219 for (int i = 0; i < 300; ++i) {
220 MutexLocker locker(&test_mutex_);
221 ++counter;
222 }
223 });
224 for (int i = 0; i < 300; ++i) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400225 MutexLocker locker(&test_mutex_);
Brian Silverman71c55c52014-08-19 14:31:59 -0400226 --counter;
Brian Silverman119b3b12015-03-29 17:26:05 -0400227 }
Brian Silverman71c55c52014-08-19 14:31:59 -0400228 thread.join();
229 EXPECT_EQ(0, counter);
Brian Silverman119b3b12015-03-29 17:26:05 -0400230 }
Brian Silverman119b3b12015-03-29 17:26:05 -0400231}
232
Brian Silverman653491d2014-05-13 16:53:29 -0700233// Verifies that ThreadSanitizer understands that an uncontended mutex
234// establishes a happens-before relationship.
235TEST_F(MutexTest, ThreadSanitizerUncontended) {
236 int counter = 0;
237 AdderThread threads[2]{
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400238 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0),
Brian Silverman71c55c52014-08-19 14:31:59 -0400239 ::aos::time::Time::InSeconds(0)},
240 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0.2),
Brian Silverman653491d2014-05-13 16:53:29 -0700241 ::aos::time::Time::InSeconds(0)}, };
242 for (auto &c : threads) {
243 c.Start();
244 }
245 for (auto &c : threads) {
246 c.WaitUntilDone();
247 }
248 EXPECT_EQ(2, counter);
249}
250
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400251namespace {
252
253class LockerThread : public util::Thread {
254 public:
255 LockerThread(Mutex *mutex, bool lock, bool unlock)
256 : mutex_(mutex), lock_(lock), unlock_(unlock) {}
257
258 private:
259 virtual void Run() override {
260 if (lock_) ASSERT_FALSE(mutex_->Lock());
261 if (unlock_) mutex_->Unlock();
262 }
263
264 Mutex *const mutex_;
265 const bool lock_, unlock_;
266};
267
268} // namespace
269
270// Makes sure that we don't SIGSEGV or something with multiple threads.
271TEST_F(MutexTest, MultiThreadedLock) {
272 LockerThread t(&test_mutex_, true, true);
273 t.Start();
274 ASSERT_FALSE(test_mutex_.Lock());
275 test_mutex_.Unlock();
276 t.Join();
277}
278
Brian Silvermandc1eb272014-08-19 14:25:59 -0400279TEST_F(MutexLockerTest, Basic) {
280 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400281 aos::MutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400282 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400283 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400284 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400285
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400286 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400287}
288
Brian Silverman71c55c52014-08-19 14:31:59 -0400289// Tests that MutexLocker behaves correctly when the previous owner dies.
290TEST_F(MutexLockerDeathTest, OwnerDied) {
291 testing::TestSharedMemory my_shm;
292 Mutex *mutex =
293 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
294 new (mutex) Mutex();
295
296 util::FunctionThread::RunInOtherThread([&]() {
297 ASSERT_FALSE(mutex->Lock());
298 });
299 EXPECT_DEATH(
300 {
301 logging::AddImplementation(new util::DeathTestLogImplementation());
302 MutexLocker locker(mutex);
303 },
304 ".*previous owner of mutex [^ ]+ died.*");
305
306 mutex->~Mutex();
307}
308
Brian Silvermandc1eb272014-08-19 14:25:59 -0400309TEST_F(IPCMutexLockerTest, Basic) {
310 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400311 aos::IPCMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400312 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400313 EXPECT_FALSE(locker.owner_died());
314 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400315 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400316
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400317 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400318}
319
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400320// Tests what happens when the caller doesn't check if the previous owner died
321// with an IPCMutexLocker.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400322TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400323 EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex_); },
Brian Silvermandc1eb272014-08-19 14:25:59 -0400324 "nobody checked if the previous owner of mutex [^ ]+ died.*");
325}
326
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400327TEST_F(IPCRecursiveMutexLockerTest, Basic) {
328 {
329 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400330 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400331 EXPECT_FALSE(locker.owner_died());
332 }
333 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
334
335 test_mutex_.Unlock();
336}
337
338// Tests actually locking a mutex recursively with IPCRecursiveMutexLocker.
339TEST_F(IPCRecursiveMutexLockerTest, RecursiveLock) {
340 {
341 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400342 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400343 {
344 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400345 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400346 EXPECT_FALSE(locker.owner_died());
347 }
Daniel Petti88a15662015-04-12 17:42:22 -0400348 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400349 EXPECT_FALSE(locker.owner_died());
350 }
351 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
352
353 test_mutex_.Unlock();
354}
355
Brian Silverman71c55c52014-08-19 14:31:59 -0400356// Tests that IPCMutexLocker behaves correctly when the previous owner dies.
357TEST_F(IPCMutexLockerTest, OwnerDied) {
358 testing::TestSharedMemory my_shm;
359 Mutex *mutex =
360 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
361 new (mutex) Mutex();
362
363 util::FunctionThread::RunInOtherThread([&]() {
364 ASSERT_FALSE(mutex->Lock());
365 });
366 {
367 aos::IPCMutexLocker locker(mutex);
368 EXPECT_EQ(Mutex::State::kLockFailed, mutex->TryLock());
369 EXPECT_TRUE(locker.owner_died());
370 }
371 EXPECT_EQ(Mutex::State::kLocked, mutex->TryLock());
372
373 mutex->Unlock();
374 mutex->~Mutex();
375}
376
Brian Silverman653491d2014-05-13 16:53:29 -0700377} // namespace testing
378} // namespace aos