blob: f55d15d9c5390e5c6b373bd5afd664157ac1a2f2 [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
7#include "gtest/gtest.h"
8
9#include "aos/linux_code/ipc_lib/aos_sync.h"
10#include "aos/common/die.h"
11#include "aos/common/util/death_test_log_implementation.h"
12#include "aos/common/util/thread.h"
13#include "aos/common/time.h"
14
15namespace aos {
16namespace testing {
17
18class MutexTest : public ::testing::Test {
19 public:
20 Mutex test_mutex;
21
22 protected:
23 void SetUp() override {
24 SetDieTestMode(true);
25 }
26};
27
28typedef MutexTest MutexDeathTest;
29
30TEST_F(MutexTest, TryLock) {
31 EXPECT_TRUE(test_mutex.TryLock());
32 EXPECT_FALSE(test_mutex.TryLock());
33}
34
35TEST_F(MutexTest, Lock) {
36 test_mutex.Lock();
37 EXPECT_FALSE(test_mutex.TryLock());
38}
39
40TEST_F(MutexTest, Unlock) {
41 test_mutex.Lock();
42 EXPECT_FALSE(test_mutex.TryLock());
43 test_mutex.Unlock();
44 EXPECT_TRUE(test_mutex.TryLock());
45}
46
47// Sees what happens with multiple unlocks.
48TEST_F(MutexDeathTest, RepeatUnlock) {
49 test_mutex.Lock();
50 test_mutex.Unlock();
51 EXPECT_DEATH(
52 {
53 logging::AddImplementation(new util::DeathTestLogImplementation());
54 test_mutex.Unlock();
55 },
56 ".*multiple unlock.*");
57}
58
59// Sees what happens if you unlock without ever locking (or unlocking) it.
60TEST_F(MutexDeathTest, NeverLock) {
61 EXPECT_DEATH(
62 {
63 logging::AddImplementation(new util::DeathTestLogImplementation());
64 test_mutex.Unlock();
65 },
66 ".*multiple unlock.*");
67}
68
69TEST_F(MutexTest, MutexLocker) {
70 {
71 aos::MutexLocker locker(&test_mutex);
72 EXPECT_FALSE(test_mutex.TryLock());
73 }
74 EXPECT_TRUE(test_mutex.TryLock());
75}
76
77TEST_F(MutexTest, MutexUnlocker) {
78 test_mutex.Lock();
79 {
80 aos::MutexUnlocker unlocker(&test_mutex);
81 // If this fails, then something weird is going on and the next line might
82 // hang, so fail immediately.
83 ASSERT_TRUE(test_mutex.TryLock());
84 test_mutex.Unlock();
85 }
86 EXPECT_FALSE(test_mutex.TryLock());
87}
88
89namespace {
90
91class AdderThread : public ::aos::util::Thread {
92 public:
93 AdderThread(int *counter, Mutex *mutex, ::aos::time::Time sleep_before_time,
94 ::aos::time::Time sleep_after_time)
95 : counter_(counter),
96 mutex_(mutex),
97 sleep_before_time_(sleep_before_time),
98 sleep_after_time_(sleep_after_time) {}
99 virtual void Run() override {
100 ::aos::time::SleepFor(sleep_before_time_);
101 MutexLocker locker(mutex_);
102 ++(*counter_);
103 ::aos::time::SleepFor(sleep_after_time_);
104 }
105
106 private:
107 int *const counter_;
108 Mutex *const mutex_;
109 const ::aos::time::Time sleep_before_time_, sleep_after_time_;
110};
111
112} // namespace
113
114// Verifies that ThreadSanitizer understands that a contended mutex establishes
115// a happens-before relationship.
116TEST_F(MutexTest, ThreadSanitizerContended) {
117 int counter = 0;
118 AdderThread threads[2]{
119 {&counter, &test_mutex, ::aos::time::Time::InSeconds(1),
120 ::aos::time::Time::InSeconds(0)},
121 {&counter, &test_mutex, ::aos::time::Time::InSeconds(0),
122 ::aos::time::Time::InSeconds(0)}, };
123 for (auto &c : threads) {
124 c.Start();
125 }
126 for (auto &c : threads) {
127 c.WaitUntilDone();
128 }
129 EXPECT_EQ(2, counter);
130}
131
132// Verifies that ThreadSanitizer understands that an uncontended mutex
133// establishes a happens-before relationship.
134TEST_F(MutexTest, ThreadSanitizerUncontended) {
135 int counter = 0;
136 AdderThread threads[2]{
137 {&counter, &test_mutex, ::aos::time::Time::InSeconds(1),
138 ::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
150} // namespace testing
151} // namespace aos