Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #ifndef TALK_BASE_CRITICALSECTION_H__
     29 #define TALK_BASE_CRITICALSECTION_H__
     30 
     31 #include "talk/base/constructormagic.h"
     32 
     33 #ifdef WIN32
     34 #include "talk/base/win32.h"
     35 #endif
     36 
     37 #ifdef POSIX
     38 #include <pthread.h>
     39 #endif
     40 
     41 #ifdef _DEBUG
     42 #define CS_TRACK_OWNER 1
     43 #endif  // _DEBUG
     44 
     45 #if CS_TRACK_OWNER
     46 #define TRACK_OWNER(x) x
     47 #else  // !CS_TRACK_OWNER
     48 #define TRACK_OWNER(x)
     49 #endif  // !CS_TRACK_OWNER
     50 
     51 namespace talk_base {
     52 
     53 #ifdef WIN32
     54 class CriticalSection {
     55  public:
     56   CriticalSection() {
     57     InitializeCriticalSection(&crit_);
     58     // Windows docs say 0 is not a valid thread id
     59     TRACK_OWNER(thread_ = 0);
     60   }
     61   ~CriticalSection() {
     62     DeleteCriticalSection(&crit_);
     63   }
     64   void Enter() {
     65     EnterCriticalSection(&crit_);
     66     TRACK_OWNER(thread_ = GetCurrentThreadId());
     67   }
     68   bool TryEnter() {
     69     if (TryEnterCriticalSection(&crit_) != FALSE) {
     70       TRACK_OWNER(thread_ = GetCurrentThreadId());
     71       return true;
     72     }
     73     return false;
     74   }
     75   void Leave() {
     76     TRACK_OWNER(thread_ = 0);
     77     LeaveCriticalSection(&crit_);
     78   }
     79 
     80 #if CS_TRACK_OWNER
     81   bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
     82 #endif  // CS_TRACK_OWNER
     83 
     84  private:
     85   CRITICAL_SECTION crit_;
     86   TRACK_OWNER(DWORD thread_);  // The section's owning thread id
     87 };
     88 #endif // WIN32
     89 
     90 #ifdef POSIX
     91 class CriticalSection {
     92  public:
     93   CriticalSection() {
     94     pthread_mutexattr_t mutex_attribute;
     95     pthread_mutexattr_init(&mutex_attribute);
     96     pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
     97     pthread_mutex_init(&mutex_, &mutex_attribute);
     98     pthread_mutexattr_destroy(&mutex_attribute);
     99     TRACK_OWNER(thread_ = 0);
    100   }
    101   ~CriticalSection() {
    102     pthread_mutex_destroy(&mutex_);
    103   }
    104   void Enter() {
    105     pthread_mutex_lock(&mutex_);
    106     TRACK_OWNER(thread_ = pthread_self());
    107   }
    108   bool TryEnter() {
    109     if (pthread_mutex_trylock(&mutex_) == 0) {
    110       TRACK_OWNER(thread_ = pthread_self());
    111       return true;
    112     }
    113     return false;
    114   }
    115   void Leave() {
    116     TRACK_OWNER(thread_ = 0);
    117     pthread_mutex_unlock(&mutex_);
    118   }
    119 
    120 #if CS_TRACK_OWNER
    121   bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
    122 #endif  // CS_TRACK_OWNER
    123 
    124  private:
    125   pthread_mutex_t mutex_;
    126   TRACK_OWNER(pthread_t thread_);
    127 };
    128 #endif // POSIX
    129 
    130 // CritScope, for serializing execution through a scope.
    131 class CritScope {
    132  public:
    133   explicit CritScope(CriticalSection *pcrit) {
    134     pcrit_ = pcrit;
    135     pcrit_->Enter();
    136   }
    137   ~CritScope() {
    138     pcrit_->Leave();
    139   }
    140  private:
    141   CriticalSection *pcrit_;
    142   DISALLOW_COPY_AND_ASSIGN(CritScope);
    143 };
    144 
    145 // Tries to lock a critical section on construction via
    146 // CriticalSection::TryEnter, and unlocks on destruction if the
    147 // lock was taken. Never blocks.
    148 //
    149 // IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
    150 // subsequent code. Users *must* check locked() to determine if the
    151 // lock was taken. If you're not calling locked(), you're doing it wrong!
    152 class TryCritScope {
    153  public:
    154   explicit TryCritScope(CriticalSection *pcrit) {
    155     pcrit_ = pcrit;
    156     locked_ = pcrit_->TryEnter();
    157   }
    158   ~TryCritScope() {
    159     if (locked_) {
    160       pcrit_->Leave();
    161     }
    162   }
    163   bool locked() const {
    164     return locked_;
    165   }
    166  private:
    167   CriticalSection *pcrit_;
    168   bool locked_;
    169   DISALLOW_COPY_AND_ASSIGN(TryCritScope);
    170 };
    171 
    172 // TODO: Move this to atomicops.h, which can't be done easily because of
    173 // complex compile rules.
    174 class AtomicOps {
    175  public:
    176 #ifdef WIN32
    177   // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
    178   static int Increment(int* i) {
    179     return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
    180   }
    181   static int Decrement(int* i) {
    182     return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
    183   }
    184 #else
    185   static int Increment(int* i) {
    186     return __sync_add_and_fetch(i, 1);
    187   }
    188   static int Decrement(int* i) {
    189     return __sync_sub_and_fetch(i, 1);
    190   }
    191 #endif
    192 };
    193 
    194 } // namespace talk_base
    195 
    196 #endif // TALK_BASE_CRITICALSECTION_H__
    197