1 /* 2 * Copyright 2015 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 #include "webrtc/base/criticalsection.h" 12 13 #include "webrtc/base/checks.h" 14 15 namespace rtc { 16 17 CriticalSection::CriticalSection() { 18 #if defined(WEBRTC_WIN) 19 InitializeCriticalSection(&crit_); 20 #else 21 pthread_mutexattr_t mutex_attribute; 22 pthread_mutexattr_init(&mutex_attribute); 23 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); 24 pthread_mutex_init(&mutex_, &mutex_attribute); 25 pthread_mutexattr_destroy(&mutex_attribute); 26 CS_DEBUG_CODE(thread_ = 0); 27 CS_DEBUG_CODE(recursion_count_ = 0); 28 #endif 29 } 30 31 CriticalSection::~CriticalSection() { 32 #if defined(WEBRTC_WIN) 33 DeleteCriticalSection(&crit_); 34 #else 35 pthread_mutex_destroy(&mutex_); 36 #endif 37 } 38 39 void CriticalSection::Enter() EXCLUSIVE_LOCK_FUNCTION() { 40 #if defined(WEBRTC_WIN) 41 EnterCriticalSection(&crit_); 42 #else 43 pthread_mutex_lock(&mutex_); 44 #if CS_DEBUG_CHECKS 45 if (!recursion_count_) { 46 RTC_DCHECK(!thread_); 47 thread_ = pthread_self(); 48 } else { 49 RTC_DCHECK(CurrentThreadIsOwner()); 50 } 51 ++recursion_count_; 52 #endif 53 #endif 54 } 55 56 bool CriticalSection::TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) { 57 #if defined(WEBRTC_WIN) 58 return TryEnterCriticalSection(&crit_) != FALSE; 59 #else 60 if (pthread_mutex_trylock(&mutex_) != 0) 61 return false; 62 #if CS_DEBUG_CHECKS 63 if (!recursion_count_) { 64 RTC_DCHECK(!thread_); 65 thread_ = pthread_self(); 66 } else { 67 RTC_DCHECK(CurrentThreadIsOwner()); 68 } 69 ++recursion_count_; 70 #endif 71 return true; 72 #endif 73 } 74 void CriticalSection::Leave() UNLOCK_FUNCTION() { 75 RTC_DCHECK(CurrentThreadIsOwner()); 76 #if defined(WEBRTC_WIN) 77 LeaveCriticalSection(&crit_); 78 #else 79 #if CS_DEBUG_CHECKS 80 --recursion_count_; 81 RTC_DCHECK(recursion_count_ >= 0); 82 if (!recursion_count_) 83 thread_ = 0; 84 #endif 85 pthread_mutex_unlock(&mutex_); 86 #endif 87 } 88 89 bool CriticalSection::CurrentThreadIsOwner() const { 90 #if defined(WEBRTC_WIN) 91 // OwningThread has type HANDLE but actually contains the Thread ID: 92 // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de 93 // Converting through size_t avoids the VS 2015 warning C4312: conversion from 94 // 'type1' to 'type2' of greater size 95 return crit_.OwningThread == 96 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); 97 #else 98 #if CS_DEBUG_CHECKS 99 return pthread_equal(thread_, pthread_self()); 100 #else 101 return true; 102 #endif // CS_DEBUG_CHECKS 103 #endif 104 } 105 106 bool CriticalSection::IsLocked() const { 107 #if defined(WEBRTC_WIN) 108 return crit_.LockCount != -1; 109 #else 110 #if CS_DEBUG_CHECKS 111 return thread_ != 0; 112 #else 113 return true; 114 #endif 115 #endif 116 } 117 118 CritScope::CritScope(CriticalSection* cs) : cs_(cs) { cs_->Enter(); } 119 CritScope::~CritScope() { cs_->Leave(); } 120 121 TryCritScope::TryCritScope(CriticalSection* cs) 122 : cs_(cs), locked_(cs->TryEnter()) { 123 CS_DEBUG_CODE(lock_was_called_ = false); 124 } 125 126 TryCritScope::~TryCritScope() { 127 CS_DEBUG_CODE(RTC_DCHECK(lock_was_called_)); 128 if (locked_) 129 cs_->Leave(); 130 } 131 132 bool TryCritScope::locked() const { 133 CS_DEBUG_CODE(lock_was_called_ = true); 134 return locked_; 135 } 136 137 void GlobalLockPod::Lock() { 138 #if !defined(WEBRTC_WIN) 139 const struct timespec ts_null = {0, 0}; 140 #endif 141 142 while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) { 143 #if defined(WEBRTC_WIN) 144 ::Sleep(0); 145 #else 146 nanosleep(&ts_null, nullptr); 147 #endif 148 } 149 } 150 151 void GlobalLockPod::Unlock() { 152 int old_value = AtomicOps::CompareAndSwap(&lock_acquired, 1, 0); 153 RTC_DCHECK_EQ(1, old_value) << "Unlock called without calling Lock first"; 154 } 155 156 GlobalLock::GlobalLock() { 157 lock_acquired = 0; 158 } 159 160 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) 161 : lock_(lock) { 162 lock_->Lock(); 163 } 164 165 GlobalLockScope::~GlobalLockScope() { 166 lock_->Unlock(); 167 } 168 169 } // namespace rtc 170