1 // Copyright (C) 2014 The Android Open Source Project 2 // 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 #pragma once 16 17 #include "android/base/Compiler.h" 18 19 #ifdef _WIN32 20 #define WIN32_LEAN_AND_MEAN 1 21 #include <windows.h> 22 #else 23 #include <pthread.h> 24 #endif 25 26 #include <assert.h> 27 28 #define AEMU_DEBUG 0 29 30 #if AEMU_DEBUG 31 #define AEMU_IF_DEBUG(x) x 32 #else 33 #define AEMU_IF_DEBUG(x) 34 #endif 35 36 namespace android { 37 namespace base { 38 namespace guest { 39 40 class AutoLock; 41 class AutoWriteLock; 42 class AutoReadLock; 43 44 // A wrapper class for mutexes only suitable for using in static context, 45 // where it's OK to leak the underlying system object. Use Lock for scoped or 46 // member locks. 47 class StaticLock { 48 public: 49 using AutoLock = android::base::guest::AutoLock; 50 51 constexpr StaticLock() = default; 52 53 // Acquire the lock. lock()54 void lock() { 55 #ifdef _WIN32 56 ::AcquireSRWLockExclusive(&mLock); 57 #else 58 ::pthread_mutex_lock(&mLock); 59 #endif 60 AEMU_IF_DEBUG(mIsLocked = true;) 61 } 62 tryLock()63 bool tryLock() { 64 bool ret = false; 65 #ifdef _WIN32 66 ret = ::TryAcquireSRWLockExclusive(&mLock); 67 #else 68 ret = ::pthread_mutex_trylock(&mLock) == 0; 69 #endif 70 AEMU_IF_DEBUG(mIsLocked = ret;) 71 return ret; 72 } 73 AEMU_IF_DEBUG(bool isLocked ()const{ return mIsLocked; })74 AEMU_IF_DEBUG(bool isLocked() const { return mIsLocked; }) 75 76 // Release the lock. 77 void unlock() { 78 AEMU_IF_DEBUG(mIsLocked = false;) 79 #ifdef _WIN32 80 ::ReleaseSRWLockExclusive(&mLock); 81 #else 82 ::pthread_mutex_unlock(&mLock); 83 #endif 84 } 85 86 protected: 87 friend class ConditionVariable; 88 89 #ifdef _WIN32 90 // Benchmarks show that on Windows SRWLOCK performs a little bit better than 91 // CRITICAL_SECTION for uncontended mode and much better in case of 92 // contention. 93 SRWLOCK mLock = SRWLOCK_INIT; 94 #else 95 pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER; 96 #endif 97 // Both POSIX threads and WinAPI don't allow move (undefined behavior). 98 DISALLOW_COPY_ASSIGN_AND_MOVE(StaticLock); 99 100 AEMU_IF_DEBUG(bool mIsLocked = false;) 101 }; 102 103 // Simple wrapper class for mutexes used in non-static context. 104 class Lock : public StaticLock { 105 public: 106 using StaticLock::AutoLock; 107 108 constexpr Lock() = default; 109 #ifndef _WIN32 110 // The only difference is that POSIX requires a deallocation function call 111 // for its mutexes. ~Lock()112 ~Lock() { ::pthread_mutex_destroy(&mLock); } 113 #endif 114 }; 115 116 class ReadWriteLock { 117 public: 118 using AutoWriteLock = android::base::guest::AutoWriteLock; 119 using AutoReadLock = android::base::guest::AutoReadLock; 120 121 #ifdef _WIN32 122 constexpr ReadWriteLock() = default; 123 ~ReadWriteLock() = default; lockRead()124 void lockRead() { ::AcquireSRWLockShared(&mLock); } unlockRead()125 void unlockRead() { ::ReleaseSRWLockShared(&mLock); } lockWrite()126 void lockWrite() { ::AcquireSRWLockExclusive(&mLock); } unlockWrite()127 void unlockWrite() { ::ReleaseSRWLockExclusive(&mLock); } 128 129 private: 130 SRWLOCK mLock = SRWLOCK_INIT; 131 #else // !_WIN32 ReadWriteLock()132 ReadWriteLock() { ::pthread_rwlock_init(&mLock, NULL); } ~ReadWriteLock()133 ~ReadWriteLock() { ::pthread_rwlock_destroy(&mLock); } lockRead()134 void lockRead() { ::pthread_rwlock_rdlock(&mLock); } unlockRead()135 void unlockRead() { ::pthread_rwlock_unlock(&mLock); } lockWrite()136 void lockWrite() { ::pthread_rwlock_wrlock(&mLock); } unlockWrite()137 void unlockWrite() { ::pthread_rwlock_unlock(&mLock); } 138 139 private: 140 pthread_rwlock_t mLock; 141 #endif // !_WIN32 142 143 friend class ConditionVariable; 144 DISALLOW_COPY_ASSIGN_AND_MOVE(ReadWriteLock); 145 }; 146 147 // Helper class to lock / unlock a mutex automatically on scope 148 // entry and exit. 149 // NB: not thread-safe (as opposed to the Lock class) 150 class AutoLock { 151 public: AutoLock(StaticLock & lock)152 AutoLock(StaticLock& lock) : mLock(lock) { mLock.lock(); } 153 AutoLock(AutoLock && other)154 AutoLock(AutoLock&& other) : mLock(other.mLock), mLocked(other.mLocked) { 155 other.mLocked = false; 156 } 157 lock()158 void lock() { 159 assert(!mLocked); 160 mLock.lock(); 161 mLocked = true; 162 } 163 unlock()164 void unlock() { 165 assert(mLocked); 166 mLock.unlock(); 167 mLocked = false; 168 } 169 isLocked()170 bool isLocked() const { return mLocked; } 171 ~AutoLock()172 ~AutoLock() { 173 if (mLocked) { 174 mLock.unlock(); 175 } 176 } 177 178 private: 179 StaticLock& mLock; 180 bool mLocked = true; 181 182 friend class ConditionVariable; 183 // Don't allow move because this class has a non-movable object. 184 DISALLOW_COPY_AND_ASSIGN(AutoLock); 185 }; 186 187 class AutoWriteLock { 188 public: AutoWriteLock(ReadWriteLock & lock)189 AutoWriteLock(ReadWriteLock& lock) : mLock(lock) { mLock.lockWrite(); } 190 lockWrite()191 void lockWrite() { 192 assert(!mWriteLocked); 193 mLock.lockWrite(); 194 mWriteLocked = true; 195 } 196 unlockWrite()197 void unlockWrite() { 198 assert(mWriteLocked); 199 mLock.unlockWrite(); 200 mWriteLocked = false; 201 } 202 ~AutoWriteLock()203 ~AutoWriteLock() { 204 if (mWriteLocked) { 205 mLock.unlockWrite(); 206 } 207 } 208 209 private: 210 ReadWriteLock& mLock; 211 bool mWriteLocked = true; 212 // This class has a non-movable object. 213 DISALLOW_COPY_ASSIGN_AND_MOVE(AutoWriteLock); 214 }; 215 216 class AutoReadLock { 217 public: AutoReadLock(ReadWriteLock & lock)218 AutoReadLock(ReadWriteLock& lock) : mLock(lock) { mLock.lockRead(); } 219 lockRead()220 void lockRead() { 221 assert(!mReadLocked); 222 mLock.lockRead(); 223 mReadLocked = true; 224 } 225 unlockRead()226 void unlockRead() { 227 assert(mReadLocked); 228 mLock.unlockRead(); 229 mReadLocked = false; 230 } 231 ~AutoReadLock()232 ~AutoReadLock() { 233 if (mReadLocked) { 234 mLock.unlockRead(); 235 } 236 } 237 238 private: 239 ReadWriteLock& mLock; 240 bool mReadLocked = true; 241 // This class has a non-movable object. 242 DISALLOW_COPY_ASSIGN_AND_MOVE(AutoReadLock); 243 }; 244 245 } // namespace guest 246 } // namespace base 247 } // namespace android 248