1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef WEBRTC_BASE_CRITICALSECTION_H__ 12 #define WEBRTC_BASE_CRITICALSECTION_H__ 13 14 #include "webrtc/base/constructormagic.h" 15 #include "webrtc/base/thread_annotations.h" 16 17 #if defined(WEBRTC_WIN) 18 #include "webrtc/base/win32.h" 19 #endif 20 21 #if defined(WEBRTC_POSIX) 22 #include <pthread.h> 23 #endif 24 25 #ifdef _DEBUG 26 #define CS_TRACK_OWNER 1 27 #endif // _DEBUG 28 29 #if CS_TRACK_OWNER 30 #define TRACK_OWNER(x) x 31 #else // !CS_TRACK_OWNER 32 #define TRACK_OWNER(x) 33 #endif // !CS_TRACK_OWNER 34 35 namespace rtc { 36 37 #if defined(WEBRTC_WIN) 38 class LOCKABLE CriticalSection { 39 public: CriticalSection()40 CriticalSection() { 41 InitializeCriticalSection(&crit_); 42 // Windows docs say 0 is not a valid thread id 43 TRACK_OWNER(thread_ = 0); 44 } ~CriticalSection()45 ~CriticalSection() { 46 DeleteCriticalSection(&crit_); 47 } Enter()48 void Enter() EXCLUSIVE_LOCK_FUNCTION() { 49 EnterCriticalSection(&crit_); 50 TRACK_OWNER(thread_ = GetCurrentThreadId()); 51 } TryEnter()52 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) { 53 if (TryEnterCriticalSection(&crit_) != FALSE) { 54 TRACK_OWNER(thread_ = GetCurrentThreadId()); 55 return true; 56 } 57 return false; 58 } Leave()59 void Leave() UNLOCK_FUNCTION() { 60 TRACK_OWNER(thread_ = 0); 61 LeaveCriticalSection(&crit_); 62 } 63 64 #if CS_TRACK_OWNER CurrentThreadIsOwner()65 bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); } 66 #endif // CS_TRACK_OWNER 67 68 private: 69 CRITICAL_SECTION crit_; 70 TRACK_OWNER(DWORD thread_); // The section's owning thread id 71 }; 72 #endif // WEBRTC_WIN 73 74 #if defined(WEBRTC_POSIX) 75 class LOCKABLE CriticalSection { 76 public: CriticalSection()77 CriticalSection() { 78 pthread_mutexattr_t mutex_attribute; 79 pthread_mutexattr_init(&mutex_attribute); 80 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); 81 pthread_mutex_init(&mutex_, &mutex_attribute); 82 pthread_mutexattr_destroy(&mutex_attribute); 83 TRACK_OWNER(thread_ = 0); 84 } ~CriticalSection()85 ~CriticalSection() { 86 pthread_mutex_destroy(&mutex_); 87 } Enter()88 void Enter() EXCLUSIVE_LOCK_FUNCTION() { 89 pthread_mutex_lock(&mutex_); 90 TRACK_OWNER(thread_ = pthread_self()); 91 } TryEnter()92 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) { 93 if (pthread_mutex_trylock(&mutex_) == 0) { 94 TRACK_OWNER(thread_ = pthread_self()); 95 return true; 96 } 97 return false; 98 } Leave()99 void Leave() UNLOCK_FUNCTION() { 100 TRACK_OWNER(thread_ = 0); 101 pthread_mutex_unlock(&mutex_); 102 } 103 104 #if CS_TRACK_OWNER CurrentThreadIsOwner()105 bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); } 106 #endif // CS_TRACK_OWNER 107 108 private: 109 pthread_mutex_t mutex_; 110 TRACK_OWNER(pthread_t thread_); 111 }; 112 #endif // WEBRTC_POSIX 113 114 // CritScope, for serializing execution through a scope. 115 class SCOPED_LOCKABLE CritScope { 116 public: CritScope(CriticalSection * pcrit)117 explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) { 118 pcrit_ = pcrit; 119 pcrit_->Enter(); 120 } UNLOCK_FUNCTION()121 ~CritScope() UNLOCK_FUNCTION() { 122 pcrit_->Leave(); 123 } 124 private: 125 CriticalSection *pcrit_; 126 DISALLOW_COPY_AND_ASSIGN(CritScope); 127 }; 128 129 // Tries to lock a critical section on construction via 130 // CriticalSection::TryEnter, and unlocks on destruction if the 131 // lock was taken. Never blocks. 132 // 133 // IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in 134 // subsequent code. Users *must* check locked() to determine if the 135 // lock was taken. If you're not calling locked(), you're doing it wrong! 136 class TryCritScope { 137 public: TryCritScope(CriticalSection * pcrit)138 explicit TryCritScope(CriticalSection *pcrit) { 139 pcrit_ = pcrit; 140 locked_ = pcrit_->TryEnter(); 141 } ~TryCritScope()142 ~TryCritScope() { 143 if (locked_) { 144 pcrit_->Leave(); 145 } 146 } locked()147 bool locked() const { 148 return locked_; 149 } 150 private: 151 CriticalSection *pcrit_; 152 bool locked_; 153 DISALLOW_COPY_AND_ASSIGN(TryCritScope); 154 }; 155 156 // TODO: Move this to atomicops.h, which can't be done easily because of 157 // complex compile rules. 158 class AtomicOps { 159 public: 160 #if defined(WEBRTC_WIN) 161 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64. Increment(int * i)162 static int Increment(int* i) { 163 return ::InterlockedIncrement(reinterpret_cast<LONG*>(i)); 164 } Decrement(int * i)165 static int Decrement(int* i) { 166 return ::InterlockedDecrement(reinterpret_cast<LONG*>(i)); 167 } 168 #else 169 static int Increment(int* i) { 170 return __sync_add_and_fetch(i, 1); 171 } 172 static int Decrement(int* i) { 173 return __sync_sub_and_fetch(i, 1); 174 } 175 #endif 176 }; 177 178 } // namespace rtc 179 180 #endif // WEBRTC_BASE_CRITICALSECTION_H__ 181