1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_SYNCHRONIZATION_READ_WRITE_LOCK_H_ 6 #define BASE_SYNCHRONIZATION_READ_WRITE_LOCK_H_ 7 8 #include "base/base_export.h" 9 #include "base/macros.h" 10 #include "build/build_config.h" 11 12 #if defined(OS_NACL) 13 #include "base/synchronization/lock.h" 14 #endif 15 16 #if defined(OS_WIN) 17 #include <windows.h> 18 #elif defined(OS_POSIX) 19 #include <pthread.h> 20 #else 21 # error No reader-writer lock defined for this platform. 22 #endif 23 24 namespace base { 25 namespace subtle { 26 27 // An OS-independent wrapper around reader-writer locks. There's no magic here. 28 // 29 // You are strongly encouraged to use base::Lock instead of this, unless you 30 // can demonstrate contention and show that this would lead to an improvement. 31 // This lock does not make any guarantees of fairness, which can lead to writer 32 // starvation under certain access patterns. You should carefully consider your 33 // writer access patterns before using this lock. 34 class BASE_EXPORT ReadWriteLock { 35 public: 36 ReadWriteLock(); 37 ~ReadWriteLock(); 38 39 // Reader lock functions. 40 void ReadAcquire(); 41 void ReadRelease(); 42 43 // Writer lock functions. 44 void WriteAcquire(); 45 void WriteRelease(); 46 47 private: 48 #if defined(OS_WIN) 49 using NativeHandle = SRWLOCK; 50 #elif defined(OS_NACL) 51 using NativeHandle = Lock; 52 #elif defined(OS_POSIX) 53 using NativeHandle = pthread_rwlock_t; 54 #endif 55 56 NativeHandle native_handle_; 57 58 #if defined(OS_NACL) 59 // Even though NaCl has a pthread_rwlock implementation, the build rules don't 60 // make it universally available. So instead, implement a slower and trivial 61 // reader-writer lock using a regular mutex. 62 // TODO(amistry): Remove this and use the posix implementation when it's 63 // available in all build configurations. 64 uint32_t readers_ = 0; 65 // base::Lock does checking to ensure the lock is acquired and released on the 66 // same thread. This is not the case for this lock, so use pthread mutexes 67 // directly here. 68 pthread_mutex_t writer_lock_ = PTHREAD_MUTEX_INITIALIZER; 69 #endif 70 71 DISALLOW_COPY_AND_ASSIGN(ReadWriteLock); 72 }; 73 74 class AutoReadLock { 75 public: AutoReadLock(ReadWriteLock & lock)76 explicit AutoReadLock(ReadWriteLock& lock) : lock_(lock) { 77 lock_.ReadAcquire(); 78 } ~AutoReadLock()79 ~AutoReadLock() { 80 lock_.ReadRelease(); 81 } 82 83 private: 84 ReadWriteLock& lock_; 85 DISALLOW_COPY_AND_ASSIGN(AutoReadLock); 86 }; 87 88 class AutoWriteLock { 89 public: AutoWriteLock(ReadWriteLock & lock)90 explicit AutoWriteLock(ReadWriteLock& lock) : lock_(lock) { 91 lock_.WriteAcquire(); 92 } ~AutoWriteLock()93 ~AutoWriteLock() { 94 lock_.WriteRelease(); 95 } 96 97 private: 98 ReadWriteLock& lock_; 99 DISALLOW_COPY_AND_ASSIGN(AutoWriteLock); 100 }; 101 102 } // namespace subtle 103 } // namespace base 104 105 #endif // BASE_SYNCHRONIZATION_READ_WRITE_LOCK_H_ 106