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