blob: 75323c87da8fc598294deaedebc48ad785c816e4 [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 Silvermandc1eb272014-08-19 14:25:59 -040016#include "aos/common/queue_testutils.h"
17#include "aos/linux_code/ipc_lib/core_lib.h"
Brian Silverman653491d2014-05-13 16:53:29 -070018
19namespace aos {
20namespace testing {
21
22class MutexTest : public ::testing::Test {
23 public:
Brian Silverman1dfe48b2014-09-06 16:13:02 -040024 Mutex test_mutex_;
Brian Silverman653491d2014-05-13 16:53:29 -070025
26 protected:
27 void SetUp() override {
Brian Silvermandc1eb272014-08-19 14:25:59 -040028 ::aos::common::testing::EnableTestLogging();
Brian Silverman653491d2014-05-13 16:53:29 -070029 SetDieTestMode(true);
30 }
31};
32
33typedef MutexTest MutexDeathTest;
Brian Silvermandc1eb272014-08-19 14:25:59 -040034typedef MutexTest MutexLockerTest;
35typedef MutexTest MutexLockerDeathTest;
36typedef MutexTest IPCMutexLockerTest;
37typedef MutexTest IPCMutexLockerDeathTest;
Brian Silverman1dfe48b2014-09-06 16:13:02 -040038typedef MutexTest IPCRecursiveMutexLockerTest;
Brian Silverman653491d2014-05-13 16:53:29 -070039
40TEST_F(MutexTest, TryLock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040041 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
42 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040043
Brian Silverman1dfe48b2014-09-06 16:13:02 -040044 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070045}
46
47TEST_F(MutexTest, Lock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040048 ASSERT_FALSE(test_mutex_.Lock());
49 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040050
Brian Silverman1dfe48b2014-09-06 16:13:02 -040051 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070052}
53
54TEST_F(MutexTest, Unlock) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -040055 ASSERT_FALSE(test_mutex_.Lock());
56 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
57 test_mutex_.Unlock();
58 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040059
Brian Silverman1dfe48b2014-09-06 16:13:02 -040060 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070061}
62
63// Sees what happens with multiple unlocks.
64TEST_F(MutexDeathTest, RepeatUnlock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070065 logging::Init();
Brian Silverman1dfe48b2014-09-06 16:13:02 -040066 ASSERT_FALSE(test_mutex_.Lock());
67 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070068 EXPECT_DEATH(
69 {
70 logging::AddImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040071 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070072 },
73 ".*multiple unlock.*");
74}
75
76// Sees what happens if you unlock without ever locking (or unlocking) it.
77TEST_F(MutexDeathTest, NeverLock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070078 logging::Init();
Brian Silverman653491d2014-05-13 16:53:29 -070079 EXPECT_DEATH(
80 {
81 logging::AddImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040082 test_mutex_.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070083 },
84 ".*multiple unlock.*");
85}
86
Brian Silvermandc1eb272014-08-19 14:25:59 -040087// Sees what happens with multiple locks.
88TEST_F(MutexDeathTest, RepeatLock) {
89 EXPECT_DEATH(
90 {
91 logging::AddImplementation(new util::DeathTestLogImplementation());
Brian Silverman1dfe48b2014-09-06 16:13:02 -040092 ASSERT_FALSE(test_mutex_.Lock());
93 ASSERT_FALSE(test_mutex_.Lock());
Brian Silvermandc1eb272014-08-19 14:25:59 -040094 },
95 ".*multiple lock.*");
Brian Silverman653491d2014-05-13 16:53:29 -070096}
97
Brian Silvermandc1eb272014-08-19 14:25:59 -040098TEST_F(MutexDeathTest, DestroyLocked) {
99 EXPECT_DEATH(
100 {
101 logging::AddImplementation(new util::DeathTestLogImplementation());
102 Mutex new_mutex;
103 ASSERT_FALSE(new_mutex.Lock());
104 },
105 ".*destroying locked mutex.*");
Brian Silverman653491d2014-05-13 16:53:29 -0700106}
107
108namespace {
109
110class AdderThread : public ::aos::util::Thread {
111 public:
112 AdderThread(int *counter, Mutex *mutex, ::aos::time::Time sleep_before_time,
113 ::aos::time::Time sleep_after_time)
114 : counter_(counter),
115 mutex_(mutex),
116 sleep_before_time_(sleep_before_time),
117 sleep_after_time_(sleep_after_time) {}
118 virtual void Run() override {
119 ::aos::time::SleepFor(sleep_before_time_);
120 MutexLocker locker(mutex_);
121 ++(*counter_);
122 ::aos::time::SleepFor(sleep_after_time_);
123 }
124
125 private:
126 int *const counter_;
127 Mutex *const mutex_;
128 const ::aos::time::Time sleep_before_time_, sleep_after_time_;
129};
130
131} // namespace
132
133// Verifies that ThreadSanitizer understands that a contended mutex establishes
134// a happens-before relationship.
135TEST_F(MutexTest, ThreadSanitizerContended) {
136 int counter = 0;
137 AdderThread threads[2]{
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400138 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0.2),
Brian Silverman653491d2014-05-13 16:53:29 -0700139 ::aos::time::Time::InSeconds(0)},
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400140 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0),
Brian Silverman653491d2014-05-13 16:53:29 -0700141 ::aos::time::Time::InSeconds(0)}, };
142 for (auto &c : threads) {
143 c.Start();
144 }
145 for (auto &c : threads) {
146 c.WaitUntilDone();
147 }
148 EXPECT_EQ(2, counter);
149}
150
Brian Silverman119b3b12015-03-29 17:26:05 -0400151// Verifiers that ThreadSanitizer understands how a mutex works.
152// For some reason this used to fail when the other tests didn't...
153TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
154 int counter = 0;
155 ::std::thread thread([&counter, this]() {
156 for (int i = 0; i < 1000; ++i) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400157 MutexLocker locker(&test_mutex_);
Brian Silverman119b3b12015-03-29 17:26:05 -0400158 ++counter;
159 }
160 });
161 for (int i = 0; i < 1000; ++i) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400162 MutexLocker locker(&test_mutex_);
Brian Silverman119b3b12015-03-29 17:26:05 -0400163 --counter;
164 }
165 thread.join();
166 EXPECT_EQ(0, counter);
167}
168
Brian Silverman653491d2014-05-13 16:53:29 -0700169// Verifies that ThreadSanitizer understands that an uncontended mutex
170// establishes a happens-before relationship.
171TEST_F(MutexTest, ThreadSanitizerUncontended) {
172 int counter = 0;
173 AdderThread threads[2]{
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400174 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0.2),
Brian Silverman653491d2014-05-13 16:53:29 -0700175 ::aos::time::Time::InSeconds(0)},
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400176 {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0),
Brian Silverman653491d2014-05-13 16:53:29 -0700177 ::aos::time::Time::InSeconds(0)}, };
178 for (auto &c : threads) {
179 c.Start();
180 }
181 for (auto &c : threads) {
182 c.WaitUntilDone();
183 }
184 EXPECT_EQ(2, counter);
185}
186
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400187namespace {
188
189class LockerThread : public util::Thread {
190 public:
191 LockerThread(Mutex *mutex, bool lock, bool unlock)
192 : mutex_(mutex), lock_(lock), unlock_(unlock) {}
193
194 private:
195 virtual void Run() override {
196 if (lock_) ASSERT_FALSE(mutex_->Lock());
197 if (unlock_) mutex_->Unlock();
198 }
199
200 Mutex *const mutex_;
201 const bool lock_, unlock_;
202};
203
204} // namespace
205
206// Makes sure that we don't SIGSEGV or something with multiple threads.
207TEST_F(MutexTest, MultiThreadedLock) {
208 LockerThread t(&test_mutex_, true, true);
209 t.Start();
210 ASSERT_FALSE(test_mutex_.Lock());
211 test_mutex_.Unlock();
212 t.Join();
213}
214
Brian Silvermandc1eb272014-08-19 14:25:59 -0400215TEST_F(MutexLockerTest, Basic) {
216 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400217 aos::MutexLocker locker(&test_mutex_);
218 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400219 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400220 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400221
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400222 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400223}
224
225TEST_F(IPCMutexLockerTest, Basic) {
226 {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400227 aos::IPCMutexLocker locker(&test_mutex_);
228 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400229 EXPECT_FALSE(locker.owner_died());
230 }
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400231 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
Brian Silvermandc1eb272014-08-19 14:25:59 -0400232
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400233 test_mutex_.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -0400234}
235
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400236// Tests what happens when the caller doesn't check if the previous owner died
237// with an IPCMutexLocker.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400238TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400239 EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex_); },
Brian Silvermandc1eb272014-08-19 14:25:59 -0400240 "nobody checked if the previous owner of mutex [^ ]+ died.*");
241}
242
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400243TEST_F(IPCRecursiveMutexLockerTest, Basic) {
244 {
245 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
246 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
247 EXPECT_FALSE(locker.owner_died());
248 }
249 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
250
251 test_mutex_.Unlock();
252}
253
254// Tests actually locking a mutex recursively with IPCRecursiveMutexLocker.
255TEST_F(IPCRecursiveMutexLockerTest, RecursiveLock) {
256 {
257 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
258 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
259 {
260 aos::IPCRecursiveMutexLocker locker(&test_mutex_);
261 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
262 EXPECT_FALSE(locker.owner_died());
263 }
264 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex_.TryLock());
265 EXPECT_FALSE(locker.owner_died());
266 }
267 EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
268
269 test_mutex_.Unlock();
270}
271
Brian Silverman653491d2014-05-13 16:53:29 -0700272} // namespace testing
273} // namespace aos