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 22namespace panda::test { 23 24class MutexTest : public testing::Test {}; 25 26constexpr size_t N = 10; 27constexpr size_t WRITE_LOCK_SLEEP_TIME = 50; 28constexpr size_t READ_LOCK_SLEEP_TIME = 1000; 29 30struct ThreadRWLockArgs { 31 os::memory::RWLock *rwlock; 32 size_t *index; 33}; 34 35struct ThreadMutexArgs { 36 os::memory::Mutex *lock; 37 size_t *index; 38}; 39 40static 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 51static 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 61static 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 79static 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 91static 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 100HWTEST_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 127HWTEST_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 156HWTEST_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 175HWTEST_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