1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "mutex-inl.h"
18
19 #include "common_runtime_test.h"
20 #include "thread-current-inl.h"
21
22 namespace art HIDDEN {
23
24 class MutexTest : public CommonRuntimeTest {
25 protected:
MutexTest()26 MutexTest() {
27 use_boot_image_ = true; // Make the Runtime creation cheaper.
28 }
29 };
30
31 struct MutexTester {
AssertDepthart::MutexTester32 static void AssertDepth(Mutex& mu, uint32_t expected_depth) {
33 ASSERT_EQ(expected_depth, mu.GetDepth());
34
35 // This test is single-threaded, so we also know _who_ should hold the lock.
36 if (expected_depth == 0) {
37 mu.AssertNotHeld(Thread::Current());
38 } else {
39 mu.AssertHeld(Thread::Current());
40 }
41 }
42 };
43
TEST_F(MutexTest,LockUnlock)44 TEST_F(MutexTest, LockUnlock) {
45 // TODO: Remove `Mutex` dependency on `Runtime` or at least make sure it works
46 // without a `Runtime` with reasonable defaults (and without dumping stack for timeout).
47 ASSERT_TRUE(Runtime::Current() != nullptr);
48 Mutex mu("test mutex");
49 MutexTester::AssertDepth(mu, 0U);
50 mu.Lock(Thread::Current());
51 MutexTester::AssertDepth(mu, 1U);
52 mu.Unlock(Thread::Current());
53 MutexTester::AssertDepth(mu, 0U);
54 }
55
56 // GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
TryLockUnlockTest()57 static void TryLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
58 Mutex mu("test mutex");
59 MutexTester::AssertDepth(mu, 0U);
60 ASSERT_TRUE(mu.TryLock(Thread::Current()));
61 MutexTester::AssertDepth(mu, 1U);
62 mu.Unlock(Thread::Current());
63 MutexTester::AssertDepth(mu, 0U);
64 }
65
TEST_F(MutexTest,TryLockUnlock)66 TEST_F(MutexTest, TryLockUnlock) {
67 TryLockUnlockTest();
68 }
69
70 // GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
RecursiveLockUnlockTest()71 static void RecursiveLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
72 Mutex mu("test mutex", kDefaultMutexLevel, true);
73 MutexTester::AssertDepth(mu, 0U);
74 mu.Lock(Thread::Current());
75 MutexTester::AssertDepth(mu, 1U);
76 mu.Lock(Thread::Current());
77 MutexTester::AssertDepth(mu, 2U);
78 mu.Unlock(Thread::Current());
79 MutexTester::AssertDepth(mu, 1U);
80 mu.Unlock(Thread::Current());
81 MutexTester::AssertDepth(mu, 0U);
82 }
83
TEST_F(MutexTest,RecursiveLockUnlock)84 TEST_F(MutexTest, RecursiveLockUnlock) {
85 RecursiveLockUnlockTest();
86 }
87
88 // GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
RecursiveTryLockUnlockTest()89 static void RecursiveTryLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
90 Mutex mu("test mutex", kDefaultMutexLevel, true);
91 MutexTester::AssertDepth(mu, 0U);
92 ASSERT_TRUE(mu.TryLock(Thread::Current()));
93 MutexTester::AssertDepth(mu, 1U);
94 ASSERT_TRUE(mu.TryLock(Thread::Current()));
95 MutexTester::AssertDepth(mu, 2U);
96 mu.Unlock(Thread::Current());
97 MutexTester::AssertDepth(mu, 1U);
98 mu.Unlock(Thread::Current());
99 MutexTester::AssertDepth(mu, 0U);
100 }
101
TEST_F(MutexTest,RecursiveTryLockUnlock)102 TEST_F(MutexTest, RecursiveTryLockUnlock) {
103 RecursiveTryLockUnlockTest();
104 }
105
106
107 struct RecursiveLockWait {
RecursiveLockWaitart::RecursiveLockWait108 RecursiveLockWait()
109 : mu("test mutex", kDefaultMutexLevel, true), cv("test condition variable", mu) {
110 }
111
112 Mutex mu;
113 ConditionVariable cv;
114 };
115
RecursiveLockWaitCallback(void * arg)116 static void* RecursiveLockWaitCallback(void* arg) {
117 RecursiveLockWait* state = reinterpret_cast<RecursiveLockWait*>(arg);
118 state->mu.Lock(Thread::Current());
119 state->cv.Signal(Thread::Current());
120 state->mu.Unlock(Thread::Current());
121 return nullptr;
122 }
123
124 // GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
RecursiveLockWaitTest()125 static void RecursiveLockWaitTest() NO_THREAD_SAFETY_ANALYSIS {
126 RecursiveLockWait state;
127 state.mu.Lock(Thread::Current());
128 state.mu.Lock(Thread::Current());
129
130 pthread_t pthread;
131 int pthread_create_result = pthread_create(&pthread, nullptr, RecursiveLockWaitCallback, &state);
132 ASSERT_EQ(0, pthread_create_result);
133
134 state.cv.Wait(Thread::Current());
135
136 state.mu.Unlock(Thread::Current());
137 state.mu.Unlock(Thread::Current());
138 EXPECT_EQ(pthread_join(pthread, nullptr), 0);
139 }
140
141 // This ensures we don't hang when waiting on a recursively locked mutex,
142 // which is not supported with bare pthread_mutex_t.
TEST_F(MutexTest,RecursiveLockWait)143 TEST_F(MutexTest, RecursiveLockWait) {
144 RecursiveLockWaitTest();
145 }
146
TEST_F(MutexTest,SharedLockUnlock)147 TEST_F(MutexTest, SharedLockUnlock) {
148 ReaderWriterMutex mu("test rwmutex");
149 mu.AssertNotHeld(Thread::Current());
150 mu.AssertNotExclusiveHeld(Thread::Current());
151 mu.SharedLock(Thread::Current());
152 mu.AssertSharedHeld(Thread::Current());
153 mu.AssertNotExclusiveHeld(Thread::Current());
154 mu.SharedUnlock(Thread::Current());
155 mu.AssertNotHeld(Thread::Current());
156 }
157
TEST_F(MutexTest,ExclusiveLockUnlock)158 TEST_F(MutexTest, ExclusiveLockUnlock) {
159 ReaderWriterMutex mu("test rwmutex");
160 mu.AssertNotHeld(Thread::Current());
161 mu.ExclusiveLock(Thread::Current());
162 mu.AssertSharedHeld(Thread::Current());
163 mu.AssertExclusiveHeld(Thread::Current());
164 mu.ExclusiveUnlock(Thread::Current());
165 mu.AssertNotHeld(Thread::Current());
166 }
167
168 // GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
SharedTryLockUnlockTest()169 static void SharedTryLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
170 ReaderWriterMutex mu("test rwmutex");
171 mu.AssertNotHeld(Thread::Current());
172 ASSERT_TRUE(mu.SharedTryLock(Thread::Current()));
173 mu.AssertSharedHeld(Thread::Current());
174 mu.SharedUnlock(Thread::Current());
175 mu.AssertNotHeld(Thread::Current());
176 }
177
TEST_F(MutexTest,SharedTryLockUnlock)178 TEST_F(MutexTest, SharedTryLockUnlock) {
179 SharedTryLockUnlockTest();
180 }
181
182 } // namespace art
183