1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <pthread.h>
17
18 #include "gtest/gtest.h"
19 #include "os/mutex.h"
20 #include "os/thread.h"
21
22 namespace panda::test {
23
24 class MutexTest : public testing::Test {};
25
26 constexpr size_t N = 10;
27 constexpr size_t WRITE_LOCK_SLEEP_TIME = 50;
28 constexpr size_t READ_LOCK_SLEEP_TIME = 1000;
29
30 struct ThreadRWLockArgs {
31 os::memory::RWLock *rwlock;
32 size_t *index;
33 };
34
35 struct ThreadMutexArgs {
36 os::memory::Mutex *lock;
37 size_t *index;
38 };
39
TestThread1(void *input)40 static void *TestThread1(void *input)
41 {
42 ASSERT(input != nullptr);
43 ThreadRWLockArgs *arg = reinterpret_cast<ThreadRWLockArgs *>(input);
44 arg->rwlock->WriteLock();
45 (*(arg->index))++;
46 os::thread::NativeSleep(WRITE_LOCK_SLEEP_TIME);
47 arg->rwlock->Unlock();
48 return nullptr;
49 }
50
TestThread2(void *input)51 static void *TestThread2(void *input)
52 {
53 ASSERT(input != nullptr);
54 ThreadRWLockArgs *arg = reinterpret_cast<ThreadRWLockArgs *>(input);
55 arg->rwlock->ReadLock();
56 os::thread::NativeSleep(READ_LOCK_SLEEP_TIME);
57 arg->rwlock->Unlock();
58 return nullptr;
59 }
60
TestThread3(void *input)61 static void *TestThread3(void *input)
62 {
63 ASSERT(input != nullptr);
64 ThreadRWLockArgs *arg = reinterpret_cast<ThreadRWLockArgs *>(input);
65 bool res = arg->rwlock->TryReadLock();
66 if (res) {
67 (*(arg->index))++;
68 arg->rwlock->Unlock();
69 }
70
71 res = arg->rwlock->TryWriteLock();
72 if (res) {
73 (*(arg->index))++;
74 arg->rwlock->Unlock();
75 }
76 return nullptr;
77 }
78
TestThread4(void *input)79 static void *TestThread4(void *input)
80 {
81 ASSERT(input != nullptr);
82 ThreadMutexArgs *arg = reinterpret_cast<ThreadMutexArgs *>(input);
83 bool res = arg->lock->TryLockWithSpinning();
84 if (res) {
85 (*(arg->index))++;
86 arg->lock->Unlock();
87 }
88 return nullptr;
89 }
90
TestThread5(void *input)91 static void *TestThread5(void *input)
92 {
93 ASSERT(input != nullptr);
94 ThreadRWLockArgs *arg = reinterpret_cast<ThreadRWLockArgs *>(input);
95 arg->rwlock->WriteLock();
96 arg->rwlock->Unlock();
97 return nullptr;
98 }
99
HWTEST_F(MutexTest, RWLockTest, testing::ext::TestSize.Level0)100 HWTEST_F(MutexTest, RWLockTest, testing::ext::TestSize.Level0)
101 {
102 size_t res;
103 auto *rwlock = new os::memory::RWLock();
104 ThreadRWLockArgs arg = {rwlock, &res};
105
106 pthread_t t[N + N];
107
108 for (size_t i = 0; i < N; i++) {
109 pthread_create(&t[i], nullptr, TestThread1, reinterpret_cast<void *>(&arg));
110 }
111 for (size_t i = 0; i < N; i++) {
112 pthread_create(&t[i + N], nullptr, TestThread2, reinterpret_cast<void *>(&arg));
113 }
114
115 for (size_t i = 0; i < N; i++) {
116 pthread_join(t[i], nullptr);
117 pthread_join(t[i + N], nullptr);
118 }
119
120 rwlock->WriteLock();
121 rwlock->Unlock();
122
123 ASSERT_EQ(res, N);
124 delete rwlock;
125 }
126
HWTEST_F(MutexTest, TryLockTest, testing::ext::TestSize.Level0)127 HWTEST_F(MutexTest, TryLockTest, testing::ext::TestSize.Level0)
128 {
129 auto *rwlock = new os::memory::RWLock();
130 size_t res = 0;
131 ThreadRWLockArgs arg = {rwlock, &res};
132
133 pthread_t t1;
134 rwlock->WriteLock();
135 pthread_create(&t1, nullptr, TestThread3, reinterpret_cast<void *>(&arg));
136 pthread_join(t1, nullptr);
137 rwlock->Unlock();
138 ASSERT_EQ(res, 0U);
139
140 pthread_t t2;
141 rwlock->ReadLock();
142 res = 0;
143 pthread_create(&t2, nullptr, TestThread3, reinterpret_cast<void *>(&arg));
144 pthread_join(t2, nullptr);
145 rwlock->Unlock();
146 ASSERT_EQ(res, 1U);
147
148 pthread_t t3;
149 res = 0;
150 pthread_create(&t3, nullptr, TestThread3, reinterpret_cast<void *>(&arg));
151 pthread_join(t3, nullptr);
152 ASSERT_EQ(res, 2U);
153 delete rwlock;
154 }
155
HWTEST_F(MutexTest, TryLockWithSpiningTest, testing::ext::TestSize.Level0)156 HWTEST_F(MutexTest, TryLockWithSpiningTest, testing::ext::TestSize.Level0)
157 {
158 auto *lock = new os::memory::Mutex();
159 bool res = lock->TryLockWithSpinning();
160 ASSERT_TRUE(res);
161
162 size_t index = 0;
163 ThreadMutexArgs arg = {lock, &index};
164 pthread_t t;
165 pthread_create(&t, nullptr, TestThread4, reinterpret_cast<void *>(&arg));
166 pthread_join(t, nullptr);
167 ASSERT_EQ(index, 0U);
168
169 if (res) {
170 lock->Unlock();
171 }
172 delete lock;
173 }
174
HWTEST_F(MutexTest, LockForOtherTest, testing::ext::TestSize.Level0)175 HWTEST_F(MutexTest, LockForOtherTest, testing::ext::TestSize.Level0)
176 {
177 auto *rwlock = new os::memory::RWLock();
178 ThreadRWLockArgs arg = {rwlock, nullptr};
179 rwlock->WriteLock();
180 auto *lock = new os::memory::Mutex();
181 pthread_t t;
182 pthread_create(&t, nullptr, TestThread5, reinterpret_cast<void *>(&arg));
183 lock->LockForOther(t);
184 bool res = lock->TryLock();
185 if (res) {
186 lock->Unlock();
187 }
188 lock->UnlockForOther(t);
189 rwlock->Unlock();
190 ASSERT_FALSE(res);
191 pthread_join(t, nullptr);
192 delete lock;
193 }
194
195 } // namespace panda
196