Chromium Code Reviews| Index: webrtc/base/criticalsection.cc |
| diff --git a/webrtc/base/criticalsection.cc b/webrtc/base/criticalsection.cc |
| index 2c6b100a7dfdfa4c92e179f54f58ba2eea54e40c..d3f42f4a9fe90e532ef31e1523936bba12324a04 100644 |
| --- a/webrtc/base/criticalsection.cc |
| +++ b/webrtc/base/criticalsection.cc |
| @@ -12,17 +12,26 @@ |
| #include "webrtc/base/checks.h" |
| +// TODO(tommi): Split this file up to per-platform implementation files. |
| + |
| namespace rtc { |
| CriticalSection::CriticalSection() { |
| #if defined(WEBRTC_WIN) |
| InitializeCriticalSection(&crit_); |
| #else |
| +#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| + lock_queue_ = 0; |
| + owning_thread_ = 0; |
| + recursion_ = 0; |
| + semaphore_ = dispatch_semaphore_create(0); |
| +#else |
| pthread_mutexattr_t mutex_attribute; |
| pthread_mutexattr_init(&mutex_attribute); |
| pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); |
| pthread_mutex_init(&mutex_, &mutex_attribute); |
| pthread_mutexattr_destroy(&mutex_attribute); |
| +#endif |
| CS_DEBUG_CODE(thread_ = 0); |
| CS_DEBUG_CODE(recursion_count_ = 0); |
| #endif |
| @@ -32,15 +41,59 @@ CriticalSection::~CriticalSection() { |
| #if defined(WEBRTC_WIN) |
| DeleteCriticalSection(&crit_); |
| #else |
| +#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| + dispatch_release(semaphore_); |
| +#else |
| pthread_mutex_destroy(&mutex_); |
| #endif |
| +#endif |
| } |
| void CriticalSection::Enter() const EXCLUSIVE_LOCK_FUNCTION() { |
| #if defined(WEBRTC_WIN) |
| EnterCriticalSection(&crit_); |
| #else |
| +#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| + int spin = 3000; |
| + pthread_t self = pthread_self(); |
| + bool have_lock = false; |
| + do { |
| + // Instead of calling TryEnter() in this loop, we do two interlocked |
| + // operations, first a read-only one in order to avoid affecting the lock |
| + // cache-line while spinning, in case another thread is using the lock. |
| + if (owning_thread_ != self) { |
|
joachim
2016/01/22 08:35:38
Maybe change this to use "pthread_equal" to compar
tommi
2016/01/22 08:51:59
Ah, thanks. I had meant to use PlatformThreadRef a
|
| + if (AtomicOps::AcquireLoad(&lock_queue_) == 0) { |
| + if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) { |
| + have_lock = true; |
| + break; |
| + } |
| + } |
| + } else { |
| + AtomicOps::Increment(&lock_queue_); |
| + have_lock = true; |
| + break; |
| + } |
| + |
| + sched_yield(); |
| + } while (--spin); |
| + |
| + if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) { |
| + // Owning thread cannot be the current thread since TryEnter() would |
| + // have succeeded. |
| + RTC_DCHECK(owning_thread_ != self); |
|
joachim
2016/01/22 08:35:38
Same here.
|
| + // Wait for the lock to become available. |
| + dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER); |
| + RTC_DCHECK(owning_thread_ == 0); |
| + RTC_DCHECK(!recursion_); |
| + } |
| + |
| + owning_thread_ = self; |
| + ++recursion_; |
| + |
| +#else |
| pthread_mutex_lock(&mutex_); |
| +#endif |
| + |
| #if CS_DEBUG_CHECKS |
| if (!recursion_count_) { |
| RTC_DCHECK(!thread_); |
| @@ -57,8 +110,20 @@ bool CriticalSection::TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true) { |
| #if defined(WEBRTC_WIN) |
| return TryEnterCriticalSection(&crit_) != FALSE; |
| #else |
| +#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| + if (owning_thread_ != pthread_self()) { |
|
joachim
2016/01/22 08:35:38
And here.
|
| + if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0) |
| + return false; |
| + owning_thread_ = pthread_self(); |
| + RTC_DCHECK(!recursion_); |
| + } else { |
| + AtomicOps::Increment(&lock_queue_); |
| + } |
| + ++recursion_; |
| +#else |
| if (pthread_mutex_trylock(&mutex_) != 0) |
| return false; |
| +#endif |
| #if CS_DEBUG_CHECKS |
| if (!recursion_count_) { |
| RTC_DCHECK(!thread_); |
| @@ -82,8 +147,19 @@ void CriticalSection::Leave() const UNLOCK_FUNCTION() { |
| if (!recursion_count_) |
| thread_ = 0; |
| #endif |
| +#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| + RTC_DCHECK_EQ(owning_thread_, pthread_self()); |
| + RTC_DCHECK_GE(recursion_, 0); |
| + --recursion_; |
| + if (!recursion_) |
| + owning_thread_ = 0; |
| + |
| + if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_) |
| + dispatch_semaphore_signal(semaphore_); |
| +#else |
| pthread_mutex_unlock(&mutex_); |
| #endif |
| +#endif |
| } |
| bool CriticalSection::CurrentThreadIsOwner() const { |
| @@ -135,13 +211,15 @@ bool TryCritScope::locked() const { |
| } |
| void GlobalLockPod::Lock() { |
| -#if !defined(WEBRTC_WIN) |
| +#if !defined(WEBRTC_WIN) && (!defined(WEBRTC_MAC) || USE_NATIVE_MUTEX_ON_MAC) |
| const struct timespec ts_null = {0}; |
| #endif |
| while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) { |
| #if defined(WEBRTC_WIN) |
| ::Sleep(0); |
| +#elif defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
| + sched_yield(); |
| #else |
| nanosleep(&ts_null, nullptr); |
| #endif |