LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/base - criticalsection.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 8 71 11.3 %
Date: 2017-07-14 16:53:18 Functions: 1 16 6.2 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "webrtc/base/platform_thread.h"
      15             : 
      16             : // TODO(tommi): Split this file up to per-platform implementation files.
      17             : 
      18             : namespace rtc {
      19             : 
      20           3 : CriticalSection::CriticalSection() {
      21             : #if defined(WEBRTC_WIN)
      22             :   InitializeCriticalSection(&crit_);
      23             : #else
      24             : #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
      25             :   lock_queue_ = 0;
      26             :   owning_thread_ = 0;
      27             :   recursion_ = 0;
      28             :   semaphore_ = dispatch_semaphore_create(0);
      29             : #else
      30             :   pthread_mutexattr_t mutex_attribute;
      31           3 :   pthread_mutexattr_init(&mutex_attribute);
      32           3 :   pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
      33           3 :   pthread_mutex_init(&mutex_, &mutex_attribute);
      34           3 :   pthread_mutexattr_destroy(&mutex_attribute);
      35             : #endif
      36           3 :   CS_DEBUG_CODE(thread_ = 0);
      37           3 :   CS_DEBUG_CODE(recursion_count_ = 0);
      38             : #endif
      39           3 : }
      40             : 
      41           0 : CriticalSection::~CriticalSection() {
      42             : #if defined(WEBRTC_WIN)
      43             :   DeleteCriticalSection(&crit_);
      44             : #else
      45             : #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
      46             :   dispatch_release(semaphore_);
      47             : #else
      48           0 :   pthread_mutex_destroy(&mutex_);
      49             : #endif
      50             : #endif
      51           0 : }
      52             : 
      53           0 : void CriticalSection::Enter() const EXCLUSIVE_LOCK_FUNCTION() {
      54             : #if defined(WEBRTC_WIN)
      55             :   EnterCriticalSection(&crit_);
      56             : #else
      57             : #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
      58             :   int spin = 3000;
      59             :   PlatformThreadRef self = CurrentThreadRef();
      60             :   bool have_lock = false;
      61             :   do {
      62             :     // Instead of calling TryEnter() in this loop, we do two interlocked
      63             :     // operations, first a read-only one in order to avoid affecting the lock
      64             :     // cache-line while spinning, in case another thread is using the lock.
      65             :     if (!IsThreadRefEqual(owning_thread_, self)) {
      66             :       if (AtomicOps::AcquireLoad(&lock_queue_) == 0) {
      67             :         if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) {
      68             :           have_lock = true;
      69             :           break;
      70             :         }
      71             :       }
      72             :     } else {
      73             :       AtomicOps::Increment(&lock_queue_);
      74             :       have_lock = true;
      75             :       break;
      76             :     }
      77             : 
      78             :     sched_yield();
      79             :   } while (--spin);
      80             : 
      81             :   if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) {
      82             :     // Owning thread cannot be the current thread since TryEnter() would
      83             :     // have succeeded.
      84             :     RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self));
      85             :     // Wait for the lock to become available.
      86             :     dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
      87             :     RTC_DCHECK(owning_thread_ == 0);
      88             :     RTC_DCHECK(!recursion_);
      89             :   }
      90             : 
      91             :   owning_thread_ = self;
      92             :   ++recursion_;
      93             : 
      94             : #else
      95           0 :   pthread_mutex_lock(&mutex_);
      96             : #endif
      97             : 
      98             : #if CS_DEBUG_CHECKS
      99           0 :   if (!recursion_count_) {
     100           0 :     RTC_DCHECK(!thread_);
     101           0 :     thread_ = CurrentThreadRef();
     102             :   } else {
     103           0 :     RTC_DCHECK(CurrentThreadIsOwner());
     104             :   }
     105           0 :   ++recursion_count_;
     106             : #endif
     107             : #endif
     108           0 : }
     109             : 
     110           0 : bool CriticalSection::TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true) {
     111             : #if defined(WEBRTC_WIN)
     112             :   return TryEnterCriticalSection(&crit_) != FALSE;
     113             : #else
     114             : #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
     115             :   if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) {
     116             :     if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0)
     117             :       return false;
     118             :     owning_thread_ = CurrentThreadRef();
     119             :     RTC_DCHECK(!recursion_);
     120             :   } else {
     121             :     AtomicOps::Increment(&lock_queue_);
     122             :   }
     123             :   ++recursion_;
     124             : #else
     125           0 :   if (pthread_mutex_trylock(&mutex_) != 0)
     126           0 :     return false;
     127             : #endif
     128             : #if CS_DEBUG_CHECKS
     129           0 :   if (!recursion_count_) {
     130           0 :     RTC_DCHECK(!thread_);
     131           0 :     thread_ = CurrentThreadRef();
     132             :   } else {
     133           0 :     RTC_DCHECK(CurrentThreadIsOwner());
     134             :   }
     135           0 :   ++recursion_count_;
     136             : #endif
     137           0 :   return true;
     138             : #endif
     139             : }
     140           0 : void CriticalSection::Leave() const UNLOCK_FUNCTION() {
     141           0 :   RTC_DCHECK(CurrentThreadIsOwner());
     142             : #if defined(WEBRTC_WIN)
     143             :   LeaveCriticalSection(&crit_);
     144             : #else
     145             : #if CS_DEBUG_CHECKS
     146           0 :   --recursion_count_;
     147           0 :   RTC_DCHECK(recursion_count_ >= 0);
     148           0 :   if (!recursion_count_)
     149           0 :     thread_ = 0;
     150             : #endif
     151             : #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
     152             :   RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef()));
     153             :   RTC_DCHECK_GE(recursion_, 0);
     154             :   --recursion_;
     155             :   if (!recursion_)
     156             :     owning_thread_ = 0;
     157             : 
     158             :   if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_)
     159             :     dispatch_semaphore_signal(semaphore_);
     160             : #else
     161           0 :   pthread_mutex_unlock(&mutex_);
     162             : #endif
     163             : #endif
     164           0 : }
     165             : 
     166           0 : bool CriticalSection::CurrentThreadIsOwner() const {
     167             : #if defined(WEBRTC_WIN)
     168             :   // OwningThread has type HANDLE but actually contains the Thread ID:
     169             :   // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de
     170             :   // Converting through size_t avoids the VS 2015 warning C4312: conversion from
     171             :   // 'type1' to 'type2' of greater size
     172             :   return crit_.OwningThread ==
     173             :          reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
     174             : #else
     175             : #if CS_DEBUG_CHECKS
     176           0 :   return IsThreadRefEqual(thread_, CurrentThreadRef());
     177             : #else
     178             :   return true;
     179             : #endif  // CS_DEBUG_CHECKS
     180             : #endif
     181             : }
     182             : 
     183           0 : CritScope::CritScope(const CriticalSection* cs) : cs_(cs) { cs_->Enter(); }
     184           0 : CritScope::~CritScope() { cs_->Leave(); }
     185             : 
     186           0 : TryCritScope::TryCritScope(const CriticalSection* cs)
     187           0 :     : cs_(cs), locked_(cs->TryEnter()) {
     188           0 :   CS_DEBUG_CODE(lock_was_called_ = false);
     189           0 : }
     190             : 
     191           0 : TryCritScope::~TryCritScope() {
     192           0 :   CS_DEBUG_CODE(RTC_DCHECK(lock_was_called_));
     193           0 :   if (locked_)
     194           0 :     cs_->Leave();
     195           0 : }
     196             : 
     197           0 : bool TryCritScope::locked() const {
     198           0 :   CS_DEBUG_CODE(lock_was_called_ = true);
     199           0 :   return locked_;
     200             : }
     201             : 
     202           0 : void GlobalLockPod::Lock() {
     203             : #if !defined(WEBRTC_WIN) && (!defined(WEBRTC_MAC) || USE_NATIVE_MUTEX_ON_MAC)
     204           0 :   const struct timespec ts_null = {0};
     205             : #endif
     206             : 
     207           0 :   while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) {
     208             : #if defined(WEBRTC_WIN)
     209             :     ::Sleep(0);
     210             : #elif defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
     211             :     sched_yield();
     212             : #else
     213           0 :     nanosleep(&ts_null, nullptr);
     214             : #endif
     215             :   }
     216           0 : }
     217             : 
     218           0 : void GlobalLockPod::Unlock() {
     219           0 :   int old_value = AtomicOps::CompareAndSwap(&lock_acquired, 1, 0);
     220           0 :   RTC_DCHECK_EQ(1, old_value) << "Unlock called without calling Lock first";
     221           0 : }
     222             : 
     223           0 : GlobalLock::GlobalLock() {
     224           0 :   lock_acquired = 0;
     225           0 : }
     226             : 
     227           0 : GlobalLockScope::GlobalLockScope(GlobalLockPod* lock)
     228           0 :     : lock_(lock) {
     229           0 :   lock_->Lock();
     230           0 : }
     231             : 
     232           0 : GlobalLockScope::~GlobalLockScope() {
     233           0 :   lock_->Unlock();
     234           0 : }
     235             : 
     236             : }  // namespace rtc

Generated by: LCOV version 1.13