• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CriticalSection()39   CriticalSection() {
40     InitializeCriticalSection(&crit_);
41     // Windows docs say 0 is not a valid thread id
42     TRACK_OWNER(thread_ = 0);
43   }
~CriticalSection()44   ~CriticalSection() {
45     DeleteCriticalSection(&crit_);
46   }
Enter()47   void Enter() {
48     EnterCriticalSection(&crit_);
49     TRACK_OWNER(thread_ = GetCurrentThreadId());
50   }
TryEnter()51   bool TryEnter() {
52     if (TryEnterCriticalSection(&crit_) != FALSE) {
53       TRACK_OWNER(thread_ = GetCurrentThreadId());
54       return true;
55     }
56     return false;
57   }
Leave()58   void Leave() {
59     TRACK_OWNER(thread_ = 0);
60     LeaveCriticalSection(&crit_);
61   }
62 
63 #if CS_TRACK_OWNER
CurrentThreadIsOwner()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:
CriticalSection()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   }
~CriticalSection()84   ~CriticalSection() {
85     pthread_mutex_destroy(&mutex_);
86   }
Enter()87   void Enter() {
88     pthread_mutex_lock(&mutex_);
89     TRACK_OWNER(thread_ = pthread_self());
90   }
TryEnter()91   bool TryEnter() {
92     if (pthread_mutex_trylock(&mutex_) == 0) {
93       TRACK_OWNER(thread_ = pthread_self());
94       return true;
95     }
96     return false;
97   }
Leave()98   void Leave() {
99     TRACK_OWNER(thread_ = 0);
100     pthread_mutex_unlock(&mutex_);
101   }
102 
103 #if CS_TRACK_OWNER
CurrentThreadIsOwner()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:
CritScope(CriticalSection * pcrit)116   explicit CritScope(CriticalSection *pcrit) {
117     pcrit_ = pcrit;
118     pcrit_->Enter();
119   }
~CritScope()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:
TryCritScope(CriticalSection * pcrit)137   explicit TryCritScope(CriticalSection *pcrit) {
138     pcrit_ = pcrit;
139     locked_ = pcrit_->TryEnter();
140   }
~TryCritScope()141   ~TryCritScope() {
142     if (locked_) {
143       pcrit_->Leave();
144     }
145   }
locked()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.
Increment(int * i)161   static int Increment(int* i) {
162     return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
163   }
Decrement(int * i)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