blob: 3717109a22c8c50ae5cb75c6a31e00ba43466871 [file] [log] [blame]
Brian Silverman653491d2014-05-13 16:53:29 -07001#include "aos/common/mutex.h"
2
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
Brian Silverman653491d2014-05-13 16:53:29 -070012#include "aos/common/die.h"
Austin Schuhf2a50ba2016-12-24 16:16:26 -080013#include "aos/common/time.h"
Brian Silverman653491d2014-05-13 16:53:29 -070014#include "aos/common/util/death_test_log_implementation.h"
15#include "aos/common/util/thread.h"
Austin Schuhf2a50ba2016-12-24 16:16:26 -080016#include "aos/linux_code/ipc_lib/aos_sync.h"
17#include "aos/linux_code/ipc_lib/core_lib.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050018#include "aos/testing/test_logging.h"
Brian Silverman71c55c52014-08-19 14:31:59 -040019#include "aos/testing/test_shm.h"
Brian Silverman653491d2014-05-13 16:53:29 -070020
21namespace aos {
22namespace testing {
23
Austin Schuhf2a50ba2016-12-24 16:16:26 -080024namespace chrono = ::std::chrono;
25namespace this_thread = ::std::this_thread;
26
Brian Silverman653491d2014-05-13 16:53:29 -070027class MutexTest : public ::testing::Test {
28 public:
Brian Silverman1dfe48b2014-09-06 16:13:02 -040029 Mutex test_mutex_;
Brian Silverman653491d2014-05-13 16:53:29 -070030
31 protected:
32 void SetUp() override {
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050033 ::aos::testing::EnableTestLogging();
Brian Silverman653491d2014-05-13 16:53:29 -070034 SetDieTestMode(true);
35 }
36};
37
38typedef MutexTest MutexDeathTest;
Brian Silvermandc1eb272014-08-19 14:25:59 -040039typedef MutexTest MutexLockerTest;
40typedef MutexTest MutexLockerDeathTest;
41typedef MutexTest IPCMutexLockerTest;
42typedef MutexTest IPCMutexLockerDeathTest;
Brian Silverman1dfe48b2014-09-06 16:13:02 -040043typedef MutexTest IPCRecursiveMutexLockerTest;
Brian Silverman653491d2014-05-13 16:53:29 -070044
45TEST_F(MutexTest, TryLock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040046 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Daniel Petti88a15662015-04-12 17:42:22 -040047 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040048
Brian Silverman1dfe48b2014-09-06 16:13:02 -040049 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070050}
51
52TEST_F(MutexTest, Lock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040053 ASSERT_FALSE(test_mutex_.Lock());
Daniel Petti88a15662015-04-12 17:42:22 -040054 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040055
Brian Silverman1dfe48b2014-09-06 16:13:02 -040056 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070057}
58
59TEST_F(MutexTest, Unlock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040060 ASSERT_FALSE(test_mutex_.Lock());
Daniel Petti88a15662015-04-12 17:42:22 -040061 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040062 test_mutex_.Unlock();
63 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040064
Brian Silverman1dfe48b2014-09-06 16:13:02 -040065 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070066}
67
68// Sees what happens with multiple unlocks.
69TEST_F(MutexDeathTest, RepeatUnlock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070070 logging::Init();
Brian Silverman1dfe48b2014-09-06 16:13:02 -040071 ASSERT_FALSE(test_mutex_.Lock());
72 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070073 EXPECT_DEATH(
74 {
75 logging::AddImplementation(new 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 {
86 logging::AddImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040087 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070088 },
89 ".*multiple unlock.*");
90}
91
Brian Silverman71c55c52014-08-19 14:31:59 -040092// Tests that locking a mutex multiple times from the same thread fails nicely.
Brian Silvermandc1eb272014-08-19 14:25:59 -040093TEST_F(MutexDeathTest, RepeatLock) {
94 EXPECT_DEATH(
95 {
96 logging::AddImplementation(new 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 destroying a locked mutex fails nicely.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400104TEST_F(MutexDeathTest, DestroyLocked) {
105 EXPECT_DEATH(
106 {
107 logging::AddImplementation(new util::DeathTestLogImplementation());
108 Mutex new_mutex;
109 ASSERT_FALSE(new_mutex.Lock());
110 },
111 ".*destroying locked mutex.*");
Brian Silverman653491d2014-05-13 16:53:29 -0700112}
113
Brian Silverman71c55c52014-08-19 14:31:59 -0400114// Tests that Lock behaves correctly when the previous owner exits with the lock
115// held (which is the same as dying any other way).
116TEST_F(MutexTest, OwnerDiedDeathLock) {
117 testing::TestSharedMemory my_shm;
118 Mutex *mutex =
119 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
120 new (mutex) Mutex();
121
122 util::FunctionThread::RunInOtherThread([&]() {
123 ASSERT_FALSE(mutex->Lock());
124 });
125 EXPECT_TRUE(mutex->Lock());
126
127 mutex->Unlock();
128 mutex->~Mutex();
129}
130
131// Tests that TryLock behaves correctly when the previous owner dies.
132TEST_F(MutexTest, OwnerDiedDeathTryLock) {
133 testing::TestSharedMemory my_shm;
134 Mutex *mutex =
135 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
136 new (mutex) Mutex();
137
138 util::FunctionThread::RunInOtherThread([&]() {
139 ASSERT_FALSE(mutex->Lock());
140 });
141 EXPECT_EQ(Mutex::State::kOwnerDied, mutex->TryLock());
142
143 mutex->Unlock();
144 mutex->~Mutex();
145}
146
147// TODO(brians): Test owner dying by being SIGKILLed and SIGTERMed.
148
149// This sequence of mutex operations used to mess up the robust list and cause
150// one of the mutexes to not get owner-died like it should.
151TEST_F(MutexTest, DontCorruptRobustList) {
152 // I think this was the allocator lock in the original failure.
153 Mutex mutex1;
154 // This one should get owner-died afterwards (iff the kernel accepts the
155 // robust list and uses it). I think it was the task_death_notification lock
156 // in the original failure.
157 Mutex mutex2;
158
159 util::FunctionThread::RunInOtherThread([&]() {
160 ASSERT_FALSE(mutex1.Lock());
161 ASSERT_FALSE(mutex2.Lock());
162 mutex1.Unlock();
163 });
164
165 EXPECT_EQ(Mutex::State::kLocked, mutex1.TryLock());
166 EXPECT_EQ(Mutex::State::kOwnerDied, mutex2.TryLock());
167
168 mutex1.Unlock();
169 mutex2.Unlock();
170}
171
Brian Silverman653491d2014-05-13 16:53:29 -0700172namespace {
173
174class AdderThread : public ::aos::util::Thread {
175 public:
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800176 AdderThread(int *counter, Mutex *mutex,
177 monotonic_clock::duration sleep_before_time,
178 monotonic_clock::duration sleep_after_time)
Brian Silverman653491d2014-05-13 16:53:29 -0700179 : counter_(counter),
180 mutex_(mutex),
181 sleep_before_time_(sleep_before_time),
182 sleep_after_time_(sleep_after_time) {}
Brian Silverman71c55c52014-08-19 14:31:59 -0400183
184 private:
Brian Silverman653491d2014-05-13 16:53:29 -0700185 virtual void Run() override {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800186 this_thread::sleep_for(sleep_before_time_);
Brian Silverman653491d2014-05-13 16:53:29 -0700187 MutexLocker locker(mutex_);
188 ++(*counter_);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800189 this_thread::sleep_for(sleep_after_time_);
Brian Silverman653491d2014-05-13 16:53:29 -0700190 }
191
Brian Silverman653491d2014-05-13 16:53:29 -0700192 int *const counter_;
193 Mutex *const mutex_;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800194 const monotonic_clock::duration sleep_before_time_, sleep_after_time_;
Brian Silverman653491d2014-05-13 16:53:29 -0700195};
196
197} // namespace
198
199// Verifies that ThreadSanitizer understands that a contended mutex establishes
200// a happens-before relationship.
201TEST_F(MutexTest, ThreadSanitizerContended) {
202 int counter = 0;
203 AdderThread threads[2]{
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800204 {&counter, &test_mutex_, chrono::milliseconds(200),
205 chrono::milliseconds(0)},
206 {&counter, &test_mutex_, chrono::milliseconds(0),
207 chrono::milliseconds(0)},
208 };
Brian Silverman653491d2014-05-13 16:53:29 -0700209 for (auto &c : threads) {
210 c.Start();
211 }
212 for (auto &c : threads) {
213 c.WaitUntilDone();
214 }
215 EXPECT_EQ(2, counter);
216}
217
Brian Silverman119b3b12015-03-29 17:26:05 -0400218// Verifiers that ThreadSanitizer understands how a mutex works.
219// For some reason this used to fail when the other tests didn't...
Brian Silverman71c55c52014-08-19 14:31:59 -0400220// The loops make it fail more reliably when it's going to.
Brian Silverman119b3b12015-03-29 17:26:05 -0400221TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
Brian Silverman71c55c52014-08-19 14:31:59 -0400222 for (int i = 0; i < 100; ++i) {
223 int counter = 0;
224 ::std::thread thread([&counter, this]() {
225 for (int i = 0; i < 300; ++i) {
226 MutexLocker locker(&test_mutex_);
227 ++counter;
228 }
229 });
230 for (int i = 0; i < 300; ++i) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400231 MutexLocker locker(&test_mutex_);
Brian Silverman71c55c52014-08-19 14:31:59 -0400232 --counter;
Brian Silverman119b3b12015-03-29 17:26:05 -0400233 }
Brian Silverman71c55c52014-08-19 14:31:59 -0400234 thread.join();
235 EXPECT_EQ(0, counter);
Brian Silverman119b3b12015-03-29 17:26:05 -0400236 }
Brian Silverman119b3b12015-03-29 17:26:05 -0400237}
238
Brian Silverman653491d2014-05-13 16:53:29 -0700239// Verifies that ThreadSanitizer understands that an uncontended mutex
240// establishes a happens-before relationship.
241TEST_F(MutexTest, ThreadSanitizerUncontended) {
242 int counter = 0;
243 AdderThread threads[2]{
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800244 {&counter, &test_mutex_, chrono::milliseconds(0),
245 chrono::milliseconds(0)},
246 {&counter, &test_mutex_, chrono::milliseconds(200),
247 chrono::milliseconds(0)}, };
Brian Silverman653491d2014-05-13 16:53:29 -0700248 for (auto &c : threads) {
249 c.Start();
250 }
251 for (auto &c : threads) {
252 c.WaitUntilDone();
253 }
254 EXPECT_EQ(2, counter);
255}
256
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400257namespace {
258
259class LockerThread : public util::Thread {
260 public:
261 LockerThread(Mutex *mutex, bool lock, bool unlock)
262 : mutex_(mutex), lock_(lock), unlock_(unlock) {}
263
264 private:
265 virtual void Run() override {
266 if (lock_) ASSERT_FALSE(mutex_->Lock());
267 if (unlock_) mutex_->Unlock();
268 }
269
270 Mutex *const mutex_;
271 const bool lock_, unlock_;
272};
273
274} // namespace
275
276// Makes sure that we don't SIGSEGV or something with multiple threads.
277TEST_F(MutexTest, MultiThreadedLock) {
278 LockerThread t(&test_mutex_, true, true);
279 t.Start();
280 ASSERT_FALSE(test_mutex_.Lock());
281 test_mutex_.Unlock();
282 t.Join();
283}
284
Brian Silvermandc1eb272014-08-19 14:25:59 -0400285TEST_F(MutexLockerTest, Basic) {
286 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400287 aos::MutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400288 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400289 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400290 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400291
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400292 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400293}
294
Brian Silverman71c55c52014-08-19 14:31:59 -0400295// Tests that MutexLocker behaves correctly when the previous owner dies.
296TEST_F(MutexLockerDeathTest, OwnerDied) {
297 testing::TestSharedMemory my_shm;
298 Mutex *mutex =
299 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
300 new (mutex) Mutex();
301
302 util::FunctionThread::RunInOtherThread([&]() {
303 ASSERT_FALSE(mutex->Lock());
304 });
305 EXPECT_DEATH(
306 {
307 logging::AddImplementation(new util::DeathTestLogImplementation());
308 MutexLocker locker(mutex);
309 },
310 ".*previous owner of mutex [^ ]+ died.*");
311
312 mutex->~Mutex();
313}
314
Brian Silvermandc1eb272014-08-19 14:25:59 -0400315TEST_F(IPCMutexLockerTest, Basic) {
316 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400317 aos::IPCMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400318 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400319 EXPECT_FALSE(locker.owner_died());
320 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400321 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400322
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400323 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400324}
325
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400326// Tests what happens when the caller doesn't check if the previous owner died
327// with an IPCMutexLocker.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400328TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400329 EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex_); },
Brian Silvermandc1eb272014-08-19 14:25:59 -0400330 "nobody checked if the previous owner of mutex [^ ]+ died.*");
331}
332
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400333TEST_F(IPCRecursiveMutexLockerTest, Basic) {
334 {
335 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400336 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400337 EXPECT_FALSE(locker.owner_died());
338 }
339 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
340
341 test_mutex_.Unlock();
342}
343
344// Tests actually locking a mutex recursively with IPCRecursiveMutexLocker.
345TEST_F(IPCRecursiveMutexLockerTest, RecursiveLock) {
346 {
347 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400348 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400349 {
350 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
Daniel Petti88a15662015-04-12 17:42:22 -0400351 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400352 EXPECT_FALSE(locker.owner_died());
353 }
Daniel Petti88a15662015-04-12 17:42:22 -0400354 EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400355 EXPECT_FALSE(locker.owner_died());
356 }
357 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
358
359 test_mutex_.Unlock();
360}
361
Brian Silverman71c55c52014-08-19 14:31:59 -0400362// Tests that IPCMutexLocker behaves correctly when the previous owner dies.
363TEST_F(IPCMutexLockerTest, OwnerDied) {
364 testing::TestSharedMemory my_shm;
365 Mutex *mutex =
366 static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
367 new (mutex) Mutex();
368
369 util::FunctionThread::RunInOtherThread([&]() {
370 ASSERT_FALSE(mutex->Lock());
371 });
372 {
373 aos::IPCMutexLocker locker(mutex);
374 EXPECT_EQ(Mutex::State::kLockFailed, mutex->TryLock());
375 EXPECT_TRUE(locker.owner_died());
376 }
377 EXPECT_EQ(Mutex::State::kLocked, mutex->TryLock());
378
379 mutex->Unlock();
380 mutex->~Mutex();
381}
382
Brian Silverman653491d2014-05-13 16:53:29 -0700383} // namespace testing
384} // namespace aos