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