| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/base/criticalsection.h" | 11 #include "webrtc/base/criticalsection.h" |
| 12 | 12 |
| 13 #include "webrtc/base/checks.h" | 13 #include "webrtc/base/checks.h" |
| 14 #include "webrtc/base/platform_thread.h" |
| 14 | 15 |
| 15 // TODO(tommi): Split this file up to per-platform implementation files. | 16 // TODO(tommi): Split this file up to per-platform implementation files. |
| 16 | 17 |
| 17 namespace rtc { | 18 namespace rtc { |
| 18 | 19 |
| 19 CriticalSection::CriticalSection() { | 20 CriticalSection::CriticalSection() { |
| 20 #if defined(WEBRTC_WIN) | 21 #if defined(WEBRTC_WIN) |
| 21 InitializeCriticalSection(&crit_); | 22 InitializeCriticalSection(&crit_); |
| 22 #else | 23 #else |
| 23 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 24 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| (...skipping 24 matching lines...) Expand all Loading... |
| 48 #endif | 49 #endif |
| 49 #endif | 50 #endif |
| 50 } | 51 } |
| 51 | 52 |
| 52 void CriticalSection::Enter() const EXCLUSIVE_LOCK_FUNCTION() { | 53 void CriticalSection::Enter() const EXCLUSIVE_LOCK_FUNCTION() { |
| 53 #if defined(WEBRTC_WIN) | 54 #if defined(WEBRTC_WIN) |
| 54 EnterCriticalSection(&crit_); | 55 EnterCriticalSection(&crit_); |
| 55 #else | 56 #else |
| 56 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 57 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| 57 int spin = 3000; | 58 int spin = 3000; |
| 58 pthread_t self = pthread_self(); | 59 PlatformThreadRef self = CurrentThreadRef(); |
| 59 bool have_lock = false; | 60 bool have_lock = false; |
| 60 do { | 61 do { |
| 61 // Instead of calling TryEnter() in this loop, we do two interlocked | 62 // Instead of calling TryEnter() in this loop, we do two interlocked |
| 62 // operations, first a read-only one in order to avoid affecting the lock | 63 // operations, first a read-only one in order to avoid affecting the lock |
| 63 // cache-line while spinning, in case another thread is using the lock. | 64 // cache-line while spinning, in case another thread is using the lock. |
| 64 if (owning_thread_ != self) { | 65 if (!IsThreadRefEqual(owning_thread_, self)) { |
| 65 if (AtomicOps::AcquireLoad(&lock_queue_) == 0) { | 66 if (AtomicOps::AcquireLoad(&lock_queue_) == 0) { |
| 66 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) { | 67 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) { |
| 67 have_lock = true; | 68 have_lock = true; |
| 68 break; | 69 break; |
| 69 } | 70 } |
| 70 } | 71 } |
| 71 } else { | 72 } else { |
| 72 AtomicOps::Increment(&lock_queue_); | 73 AtomicOps::Increment(&lock_queue_); |
| 73 have_lock = true; | 74 have_lock = true; |
| 74 break; | 75 break; |
| 75 } | 76 } |
| 76 | 77 |
| 77 sched_yield(); | 78 sched_yield(); |
| 78 } while (--spin); | 79 } while (--spin); |
| 79 | 80 |
| 80 if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) { | 81 if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) { |
| 81 // Owning thread cannot be the current thread since TryEnter() would | 82 // Owning thread cannot be the current thread since TryEnter() would |
| 82 // have succeeded. | 83 // have succeeded. |
| 83 RTC_DCHECK(owning_thread_ != self); | 84 RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self)); |
| 84 // Wait for the lock to become available. | 85 // Wait for the lock to become available. |
| 85 dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER); | 86 dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER); |
| 86 RTC_DCHECK(owning_thread_ == 0); | 87 RTC_DCHECK(owning_thread_ == 0); |
| 87 RTC_DCHECK(!recursion_); | 88 RTC_DCHECK(!recursion_); |
| 88 } | 89 } |
| 89 | 90 |
| 90 owning_thread_ = self; | 91 owning_thread_ = self; |
| 91 ++recursion_; | 92 ++recursion_; |
| 92 | 93 |
| 93 #else | 94 #else |
| 94 pthread_mutex_lock(&mutex_); | 95 pthread_mutex_lock(&mutex_); |
| 95 #endif | 96 #endif |
| 96 | 97 |
| 97 #if CS_DEBUG_CHECKS | 98 #if CS_DEBUG_CHECKS |
| 98 if (!recursion_count_) { | 99 if (!recursion_count_) { |
| 99 RTC_DCHECK(!thread_); | 100 RTC_DCHECK(!thread_); |
| 100 thread_ = pthread_self(); | 101 thread_ = CurrentThreadRef(); |
| 101 } else { | 102 } else { |
| 102 RTC_DCHECK(CurrentThreadIsOwner()); | 103 RTC_DCHECK(CurrentThreadIsOwner()); |
| 103 } | 104 } |
| 104 ++recursion_count_; | 105 ++recursion_count_; |
| 105 #endif | 106 #endif |
| 106 #endif | 107 #endif |
| 107 } | 108 } |
| 108 | 109 |
| 109 bool CriticalSection::TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true) { | 110 bool CriticalSection::TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true) { |
| 110 #if defined(WEBRTC_WIN) | 111 #if defined(WEBRTC_WIN) |
| 111 return TryEnterCriticalSection(&crit_) != FALSE; | 112 return TryEnterCriticalSection(&crit_) != FALSE; |
| 112 #else | 113 #else |
| 113 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 114 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| 114 if (owning_thread_ != pthread_self()) { | 115 if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) { |
| 115 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0) | 116 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0) |
| 116 return false; | 117 return false; |
| 117 owning_thread_ = pthread_self(); | 118 owning_thread_ = CurrentThreadRef(); |
| 118 RTC_DCHECK(!recursion_); | 119 RTC_DCHECK(!recursion_); |
| 119 } else { | 120 } else { |
| 120 AtomicOps::Increment(&lock_queue_); | 121 AtomicOps::Increment(&lock_queue_); |
| 121 } | 122 } |
| 122 ++recursion_; | 123 ++recursion_; |
| 123 #else | 124 #else |
| 124 if (pthread_mutex_trylock(&mutex_) != 0) | 125 if (pthread_mutex_trylock(&mutex_) != 0) |
| 125 return false; | 126 return false; |
| 126 #endif | 127 #endif |
| 127 #if CS_DEBUG_CHECKS | 128 #if CS_DEBUG_CHECKS |
| 128 if (!recursion_count_) { | 129 if (!recursion_count_) { |
| 129 RTC_DCHECK(!thread_); | 130 RTC_DCHECK(!thread_); |
| 130 thread_ = pthread_self(); | 131 thread_ = CurrentThreadRef(); |
| 131 } else { | 132 } else { |
| 132 RTC_DCHECK(CurrentThreadIsOwner()); | 133 RTC_DCHECK(CurrentThreadIsOwner()); |
| 133 } | 134 } |
| 134 ++recursion_count_; | 135 ++recursion_count_; |
| 135 #endif | 136 #endif |
| 136 return true; | 137 return true; |
| 137 #endif | 138 #endif |
| 138 } | 139 } |
| 139 void CriticalSection::Leave() const UNLOCK_FUNCTION() { | 140 void CriticalSection::Leave() const UNLOCK_FUNCTION() { |
| 140 RTC_DCHECK(CurrentThreadIsOwner()); | 141 RTC_DCHECK(CurrentThreadIsOwner()); |
| 141 #if defined(WEBRTC_WIN) | 142 #if defined(WEBRTC_WIN) |
| 142 LeaveCriticalSection(&crit_); | 143 LeaveCriticalSection(&crit_); |
| 143 #else | 144 #else |
| 144 #if CS_DEBUG_CHECKS | 145 #if CS_DEBUG_CHECKS |
| 145 --recursion_count_; | 146 --recursion_count_; |
| 146 RTC_DCHECK(recursion_count_ >= 0); | 147 RTC_DCHECK(recursion_count_ >= 0); |
| 147 if (!recursion_count_) | 148 if (!recursion_count_) |
| 148 thread_ = 0; | 149 thread_ = 0; |
| 149 #endif | 150 #endif |
| 150 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 151 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| 151 RTC_DCHECK_EQ(owning_thread_, pthread_self()); | 152 RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef())); |
| 152 RTC_DCHECK_GE(recursion_, 0); | 153 RTC_DCHECK_GE(recursion_, 0); |
| 153 --recursion_; | 154 --recursion_; |
| 154 if (!recursion_) | 155 if (!recursion_) |
| 155 owning_thread_ = 0; | 156 owning_thread_ = 0; |
| 156 | 157 |
| 157 if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_) | 158 if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_) |
| 158 dispatch_semaphore_signal(semaphore_); | 159 dispatch_semaphore_signal(semaphore_); |
| 159 #else | 160 #else |
| 160 pthread_mutex_unlock(&mutex_); | 161 pthread_mutex_unlock(&mutex_); |
| 161 #endif | 162 #endif |
| 162 #endif | 163 #endif |
| 163 } | 164 } |
| 164 | 165 |
| 165 bool CriticalSection::CurrentThreadIsOwner() const { | 166 bool CriticalSection::CurrentThreadIsOwner() const { |
| 166 #if defined(WEBRTC_WIN) | 167 #if defined(WEBRTC_WIN) |
| 167 // OwningThread has type HANDLE but actually contains the Thread ID: | 168 // OwningThread has type HANDLE but actually contains the Thread ID: |
| 168 // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-
of-critical-section-of-type-handle-when-it-is-de | 169 // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-
of-critical-section-of-type-handle-when-it-is-de |
| 169 // Converting through size_t avoids the VS 2015 warning C4312: conversion from | 170 // Converting through size_t avoids the VS 2015 warning C4312: conversion from |
| 170 // 'type1' to 'type2' of greater size | 171 // 'type1' to 'type2' of greater size |
| 171 return crit_.OwningThread == | 172 return crit_.OwningThread == |
| 172 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); | 173 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); |
| 173 #else | 174 #else |
| 174 #if CS_DEBUG_CHECKS | 175 #if CS_DEBUG_CHECKS |
| 175 return pthread_equal(thread_, pthread_self()); | 176 return IsThreadRefEqual(thread_, CurrentThreadRef()); |
| 176 #else | 177 #else |
| 177 return true; | 178 return true; |
| 178 #endif // CS_DEBUG_CHECKS | 179 #endif // CS_DEBUG_CHECKS |
| 179 #endif | 180 #endif |
| 180 } | 181 } |
| 181 | 182 |
| 182 bool CriticalSection::IsLocked() const { | 183 bool CriticalSection::IsLocked() const { |
| 183 #if defined(WEBRTC_WIN) | 184 #if defined(WEBRTC_WIN) |
| 184 return crit_.LockCount != -1; | 185 return crit_.LockCount != -1; |
| 185 #else | 186 #else |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) | 239 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) |
| 239 : lock_(lock) { | 240 : lock_(lock) { |
| 240 lock_->Lock(); | 241 lock_->Lock(); |
| 241 } | 242 } |
| 242 | 243 |
| 243 GlobalLockScope::~GlobalLockScope() { | 244 GlobalLockScope::~GlobalLockScope() { |
| 244 lock_->Unlock(); | 245 lock_->Unlock(); |
| 245 } | 246 } |
| 246 | 247 |
| 247 } // namespace rtc | 248 } // namespace rtc |
| OLD | NEW |