• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace rtc {
16 
CriticalSection()17 CriticalSection::CriticalSection() {
18 #if defined(WEBRTC_WIN)
19   InitializeCriticalSection(&crit_);
20 #else
21   pthread_mutexattr_t mutex_attribute;
22   pthread_mutexattr_init(&mutex_attribute);
23   pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
24   pthread_mutex_init(&mutex_, &mutex_attribute);
25   pthread_mutexattr_destroy(&mutex_attribute);
26   CS_DEBUG_CODE(thread_ = 0);
27   CS_DEBUG_CODE(recursion_count_ = 0);
28 #endif
29 }
30 
~CriticalSection()31 CriticalSection::~CriticalSection() {
32 #if defined(WEBRTC_WIN)
33   DeleteCriticalSection(&crit_);
34 #else
35   pthread_mutex_destroy(&mutex_);
36 #endif
37 }
38 
Enter()39 void CriticalSection::Enter() EXCLUSIVE_LOCK_FUNCTION() {
40 #if defined(WEBRTC_WIN)
41   EnterCriticalSection(&crit_);
42 #else
43   pthread_mutex_lock(&mutex_);
44 #if CS_DEBUG_CHECKS
45   if (!recursion_count_) {
46     RTC_DCHECK(!thread_);
47     thread_ = pthread_self();
48   } else {
49     RTC_DCHECK(CurrentThreadIsOwner());
50   }
51   ++recursion_count_;
52 #endif
53 #endif
54 }
55 
TryEnter()56 bool CriticalSection::TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
57 #if defined(WEBRTC_WIN)
58   return TryEnterCriticalSection(&crit_) != FALSE;
59 #else
60   if (pthread_mutex_trylock(&mutex_) != 0)
61     return false;
62 #if CS_DEBUG_CHECKS
63   if (!recursion_count_) {
64     RTC_DCHECK(!thread_);
65     thread_ = pthread_self();
66   } else {
67     RTC_DCHECK(CurrentThreadIsOwner());
68   }
69   ++recursion_count_;
70 #endif
71   return true;
72 #endif
73 }
Leave()74 void CriticalSection::Leave() UNLOCK_FUNCTION() {
75   RTC_DCHECK(CurrentThreadIsOwner());
76 #if defined(WEBRTC_WIN)
77   LeaveCriticalSection(&crit_);
78 #else
79 #if CS_DEBUG_CHECKS
80   --recursion_count_;
81   RTC_DCHECK(recursion_count_ >= 0);
82   if (!recursion_count_)
83     thread_ = 0;
84 #endif
85   pthread_mutex_unlock(&mutex_);
86 #endif
87 }
88 
CurrentThreadIsOwner() const89 bool CriticalSection::CurrentThreadIsOwner() const {
90 #if defined(WEBRTC_WIN)
91   // OwningThread has type HANDLE but actually contains the Thread ID:
92   // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de
93   // Converting through size_t avoids the VS 2015 warning C4312: conversion from
94   // 'type1' to 'type2' of greater size
95   return crit_.OwningThread ==
96          reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
97 #else
98 #if CS_DEBUG_CHECKS
99   return pthread_equal(thread_, pthread_self());
100 #else
101   return true;
102 #endif  // CS_DEBUG_CHECKS
103 #endif
104 }
105 
IsLocked() const106 bool CriticalSection::IsLocked() const {
107 #if defined(WEBRTC_WIN)
108   return crit_.LockCount != -1;
109 #else
110 #if CS_DEBUG_CHECKS
111   return thread_ != 0;
112 #else
113   return true;
114 #endif
115 #endif
116 }
117 
CritScope(CriticalSection * cs)118 CritScope::CritScope(CriticalSection* cs) : cs_(cs) { cs_->Enter(); }
~CritScope()119 CritScope::~CritScope() { cs_->Leave(); }
120 
TryCritScope(CriticalSection * cs)121 TryCritScope::TryCritScope(CriticalSection* cs)
122     : cs_(cs), locked_(cs->TryEnter()) {
123   CS_DEBUG_CODE(lock_was_called_ = false);
124 }
125 
~TryCritScope()126 TryCritScope::~TryCritScope() {
127   CS_DEBUG_CODE(RTC_DCHECK(lock_was_called_));
128   if (locked_)
129     cs_->Leave();
130 }
131 
locked() const132 bool TryCritScope::locked() const {
133   CS_DEBUG_CODE(lock_was_called_ = true);
134   return locked_;
135 }
136 
Lock()137 void GlobalLockPod::Lock() {
138 #if !defined(WEBRTC_WIN)
139   const struct timespec ts_null = {0};
140 #endif
141 
142   while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) {
143 #if defined(WEBRTC_WIN)
144     ::Sleep(0);
145 #else
146     nanosleep(&ts_null, nullptr);
147 #endif
148   }
149 }
150 
Unlock()151 void GlobalLockPod::Unlock() {
152   int old_value = AtomicOps::CompareAndSwap(&lock_acquired, 1, 0);
153   RTC_DCHECK_EQ(1, old_value) << "Unlock called without calling Lock first";
154 }
155 
GlobalLock()156 GlobalLock::GlobalLock() {
157   lock_acquired = 0;
158 }
159 
GlobalLockScope(GlobalLockPod * lock)160 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock)
161     : lock_(lock) {
162   lock_->Lock();
163 }
164 
~GlobalLockScope()165 GlobalLockScope::~GlobalLockScope() {
166   lock_->Unlock();
167 }
168 
169 }  // namespace rtc
170