blob: 56f77725bce639912bb5dd62e568fc938a381dbc [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:
24 Mutex test_mutex;
25
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 Silverman653491d2014-05-13 16:53:29 -070038
39TEST_F(MutexTest, TryLock) {
Brian Silvermandc1eb272014-08-19 14:25:59 -040040 EXPECT_EQ(Mutex::State::kLocked, test_mutex.TryLock());
41 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex.TryLock());
42
43 test_mutex.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070044}
45
46TEST_F(MutexTest, Lock) {
Brian Silvermandc1eb272014-08-19 14:25:59 -040047 ASSERT_FALSE(test_mutex.Lock());
48 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex.TryLock());
49
50 test_mutex.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070051}
52
53TEST_F(MutexTest, Unlock) {
Brian Silvermandc1eb272014-08-19 14:25:59 -040054 ASSERT_FALSE(test_mutex.Lock());
55 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex.TryLock());
Brian Silverman653491d2014-05-13 16:53:29 -070056 test_mutex.Unlock();
Brian Silvermandc1eb272014-08-19 14:25:59 -040057 EXPECT_EQ(Mutex::State::kLocked, test_mutex.TryLock());
58
59 test_mutex.Unlock();
Brian Silverman653491d2014-05-13 16:53:29 -070060}
61
62// Sees what happens with multiple unlocks.
63TEST_F(MutexDeathTest, RepeatUnlock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070064 logging::Init();
Brian Silvermandc1eb272014-08-19 14:25:59 -040065 ASSERT_FALSE(test_mutex.Lock());
Brian Silverman653491d2014-05-13 16:53:29 -070066 test_mutex.Unlock();
67 EXPECT_DEATH(
68 {
69 logging::AddImplementation(new util::DeathTestLogImplementation());
70 test_mutex.Unlock();
71 },
72 ".*multiple unlock.*");
73}
74
75// Sees what happens if you unlock without ever locking (or unlocking) it.
76TEST_F(MutexDeathTest, NeverLock) {
Brian Silverman5c201e22014-06-12 22:40:28 -070077 logging::Init();
Brian Silverman653491d2014-05-13 16:53:29 -070078 EXPECT_DEATH(
79 {
80 logging::AddImplementation(new util::DeathTestLogImplementation());
81 test_mutex.Unlock();
82 },
83 ".*multiple unlock.*");
84}
85
Brian Silvermandc1eb272014-08-19 14:25:59 -040086// Sees what happens with multiple locks.
87TEST_F(MutexDeathTest, RepeatLock) {
88 EXPECT_DEATH(
89 {
90 logging::AddImplementation(new util::DeathTestLogImplementation());
91 ASSERT_FALSE(test_mutex.Lock());
92 ASSERT_FALSE(test_mutex.Lock());
93 },
94 ".*multiple lock.*");
Brian Silverman653491d2014-05-13 16:53:29 -070095}
96
Brian Silvermandc1eb272014-08-19 14:25:59 -040097TEST_F(MutexDeathTest, DestroyLocked) {
98 EXPECT_DEATH(
99 {
100 logging::AddImplementation(new util::DeathTestLogImplementation());
101 Mutex new_mutex;
102 ASSERT_FALSE(new_mutex.Lock());
103 },
104 ".*destroying locked mutex.*");
Brian Silverman653491d2014-05-13 16:53:29 -0700105}
106
107namespace {
108
109class AdderThread : public ::aos::util::Thread {
110 public:
111 AdderThread(int *counter, Mutex *mutex, ::aos::time::Time sleep_before_time,
112 ::aos::time::Time sleep_after_time)
113 : counter_(counter),
114 mutex_(mutex),
115 sleep_before_time_(sleep_before_time),
116 sleep_after_time_(sleep_after_time) {}
117 virtual void Run() override {
118 ::aos::time::SleepFor(sleep_before_time_);
119 MutexLocker locker(mutex_);
120 ++(*counter_);
121 ::aos::time::SleepFor(sleep_after_time_);
122 }
123
124 private:
125 int *const counter_;
126 Mutex *const mutex_;
127 const ::aos::time::Time sleep_before_time_, sleep_after_time_;
128};
129
130} // namespace
131
132// Verifies that ThreadSanitizer understands that a contended mutex establishes
133// a happens-before relationship.
134TEST_F(MutexTest, ThreadSanitizerContended) {
135 int counter = 0;
136 AdderThread threads[2]{
Brian Silvermandc1eb272014-08-19 14:25:59 -0400137 {&counter, &test_mutex, ::aos::time::Time::InSeconds(0.2),
Brian Silverman653491d2014-05-13 16:53:29 -0700138 ::aos::time::Time::InSeconds(0)},
139 {&counter, &test_mutex, ::aos::time::Time::InSeconds(0),
140 ::aos::time::Time::InSeconds(0)}, };
141 for (auto &c : threads) {
142 c.Start();
143 }
144 for (auto &c : threads) {
145 c.WaitUntilDone();
146 }
147 EXPECT_EQ(2, counter);
148}
149
Brian Silverman119b3b12015-03-29 17:26:05 -0400150// Verifiers that ThreadSanitizer understands how a mutex works.
151// For some reason this used to fail when the other tests didn't...
152TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
153 int counter = 0;
154 ::std::thread thread([&counter, this]() {
155 for (int i = 0; i < 1000; ++i) {
156 MutexLocker locker(&test_mutex);
157 ++counter;
158 }
159 });
160 for (int i = 0; i < 1000; ++i) {
161 MutexLocker locker(&test_mutex);
162 --counter;
163 }
164 thread.join();
165 EXPECT_EQ(0, counter);
166}
167
Brian Silverman653491d2014-05-13 16:53:29 -0700168// Verifies that ThreadSanitizer understands that an uncontended mutex
169// establishes a happens-before relationship.
170TEST_F(MutexTest, ThreadSanitizerUncontended) {
171 int counter = 0;
172 AdderThread threads[2]{
Brian Silvermandc1eb272014-08-19 14:25:59 -0400173 {&counter, &test_mutex, ::aos::time::Time::InSeconds(0.2),
Brian Silverman653491d2014-05-13 16:53:29 -0700174 ::aos::time::Time::InSeconds(0)},
175 {&counter, &test_mutex, ::aos::time::Time::InSeconds(0),
176 ::aos::time::Time::InSeconds(0)}, };
177 for (auto &c : threads) {
178 c.Start();
179 }
180 for (auto &c : threads) {
181 c.WaitUntilDone();
182 }
183 EXPECT_EQ(2, counter);
184}
185
Brian Silvermandc1eb272014-08-19 14:25:59 -0400186TEST_F(MutexLockerTest, Basic) {
187 {
188 aos::MutexLocker locker(&test_mutex);
189 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex.TryLock());
190 }
191 EXPECT_EQ(Mutex::State::kLocked, test_mutex.TryLock());
192
193 test_mutex.Unlock();
194}
195
196TEST_F(IPCMutexLockerTest, Basic) {
197 {
198 aos::IPCMutexLocker locker(&test_mutex);
199 EXPECT_EQ(Mutex::State::kUnlocked, test_mutex.TryLock());
200 EXPECT_FALSE(locker.owner_died());
201 }
202 EXPECT_EQ(Mutex::State::kLocked, test_mutex.TryLock());
203
204 test_mutex.Unlock();
205}
206
207TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
208 EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex); },
209 "nobody checked if the previous owner of mutex [^ ]+ died.*");
210}
211
Brian Silverman653491d2014-05-13 16:53:29 -0700212} // namespace testing
213} // namespace aos