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.h"
18
19#include "common_test.h"
20
21namespace art {
22
23class MutexTest : public CommonTest {};
24
25struct MutexTester {
26  static void AssertDepth(Mutex& mu, uint32_t expected_depth) {
27    ASSERT_EQ(expected_depth, mu.GetDepth());
28
29    // This test is single-threaded, so we also know _who_ should hold the lock.
30    if (expected_depth == 0) {
31      mu.AssertNotHeld(Thread::Current());
32    } else {
33      mu.AssertHeld(Thread::Current());
34    }
35  }
36};
37
38TEST_F(MutexTest, LockUnlock) {
39  Mutex mu("test mutex");
40  MutexTester::AssertDepth(mu, 0U);
41  mu.Lock(Thread::Current());
42  MutexTester::AssertDepth(mu, 1U);
43  mu.Unlock(Thread::Current());
44  MutexTester::AssertDepth(mu, 0U);
45}
46
47// GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
48static void TryLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
49  Mutex mu("test mutex");
50  MutexTester::AssertDepth(mu, 0U);
51  ASSERT_TRUE(mu.TryLock(Thread::Current()));
52  MutexTester::AssertDepth(mu, 1U);
53  mu.Unlock(Thread::Current());
54  MutexTester::AssertDepth(mu, 0U);
55}
56
57TEST_F(MutexTest, TryLockUnlock) {
58  TryLockUnlockTest();
59}
60
61// GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
62static void RecursiveLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
63  Mutex mu("test mutex", kDefaultMutexLevel, true);
64  MutexTester::AssertDepth(mu, 0U);
65  mu.Lock(Thread::Current());
66  MutexTester::AssertDepth(mu, 1U);
67  mu.Lock(Thread::Current());
68  MutexTester::AssertDepth(mu, 2U);
69  mu.Unlock(Thread::Current());
70  MutexTester::AssertDepth(mu, 1U);
71  mu.Unlock(Thread::Current());
72  MutexTester::AssertDepth(mu, 0U);
73}
74
75TEST_F(MutexTest, RecursiveLockUnlock) {
76  RecursiveLockUnlockTest();
77}
78
79// GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
80static void RecursiveTryLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
81  Mutex mu("test mutex", kDefaultMutexLevel, true);
82  MutexTester::AssertDepth(mu, 0U);
83  ASSERT_TRUE(mu.TryLock(Thread::Current()));
84  MutexTester::AssertDepth(mu, 1U);
85  ASSERT_TRUE(mu.TryLock(Thread::Current()));
86  MutexTester::AssertDepth(mu, 2U);
87  mu.Unlock(Thread::Current());
88  MutexTester::AssertDepth(mu, 1U);
89  mu.Unlock(Thread::Current());
90  MutexTester::AssertDepth(mu, 0U);
91}
92
93TEST_F(MutexTest, RecursiveTryLockUnlock) {
94  RecursiveTryLockUnlockTest();
95}
96
97
98struct RecursiveLockWait {
99  explicit RecursiveLockWait()
100      : mu("test mutex", kDefaultMutexLevel, true), cv("test condition variable", mu) {
101  }
102
103  static void* Callback(void* arg) {
104    RecursiveLockWait* state = reinterpret_cast<RecursiveLockWait*>(arg);
105    state->mu.Lock(Thread::Current());
106    state->cv.Signal(Thread::Current());
107    state->mu.Unlock(Thread::Current());
108    return NULL;
109  }
110
111  Mutex mu;
112  ConditionVariable cv;
113};
114
115// GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
116static void RecursiveLockWaitTest() NO_THREAD_SAFETY_ANALYSIS {
117  RecursiveLockWait state;
118  state.mu.Lock(Thread::Current());
119  state.mu.Lock(Thread::Current());
120
121  pthread_t pthread;
122  int pthread_create_result = pthread_create(&pthread, NULL, RecursiveLockWait::Callback, &state);
123  ASSERT_EQ(0, pthread_create_result);
124
125  state.cv.Wait(Thread::Current());
126
127  state.mu.Unlock(Thread::Current());
128  state.mu.Unlock(Thread::Current());
129  EXPECT_EQ(pthread_join(pthread, NULL), 0);
130}
131
132// This ensures we don't hang when waiting on a recursively locked mutex,
133// which is not supported with bare pthread_mutex_t.
134TEST_F(MutexTest, RecursiveLockWait) {
135  RecursiveLockWaitTest();
136}
137
138TEST_F(MutexTest, SharedLockUnlock) {
139  ReaderWriterMutex mu("test rwmutex");
140  mu.AssertNotHeld(Thread::Current());
141  mu.AssertNotExclusiveHeld(Thread::Current());
142  mu.SharedLock(Thread::Current());
143  mu.AssertSharedHeld(Thread::Current());
144  mu.AssertNotExclusiveHeld(Thread::Current());
145  mu.SharedUnlock(Thread::Current());
146  mu.AssertNotHeld(Thread::Current());
147}
148
149TEST_F(MutexTest, ExclusiveLockUnlock) {
150  ReaderWriterMutex mu("test rwmutex");
151  mu.AssertNotHeld(Thread::Current());
152  mu.ExclusiveLock(Thread::Current());
153  mu.AssertSharedHeld(Thread::Current());
154  mu.AssertExclusiveHeld(Thread::Current());
155  mu.ExclusiveUnlock(Thread::Current());
156  mu.AssertNotHeld(Thread::Current());
157}
158
159// GCC has trouble with our mutex tests, so we have to turn off thread safety analysis.
160static void SharedTryLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
161  ReaderWriterMutex mu("test rwmutex");
162  mu.AssertNotHeld(Thread::Current());
163  ASSERT_TRUE(mu.SharedTryLock(Thread::Current()));
164  mu.AssertSharedHeld(Thread::Current());
165  mu.SharedUnlock(Thread::Current());
166  mu.AssertNotHeld(Thread::Current());
167}
168
169TEST_F(MutexTest, SharedTryLockUnlock) {
170  SharedTryLockUnlockTest();
171}
172
173}  // namespace art
174