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