Chromium Code Reviews

Side by Side Diff: webrtc/base/criticalsection.cc

Issue 2877023002: Move webrtc/{base => rtc_base} (Closed)
Patch Set: Fix invalid merge Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
(Empty)
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 #include "webrtc/base/platform_thread.h"
15
16 // TODO(tommi): Split this file up to per-platform implementation files.
17
18 namespace rtc {
19
20 CriticalSection::CriticalSection() {
21 #if defined(WEBRTC_WIN)
22 InitializeCriticalSection(&crit_);
23 #else
24 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
25 lock_queue_ = 0;
26 owning_thread_ = 0;
27 recursion_ = 0;
28 semaphore_ = dispatch_semaphore_create(0);
29 #else
30 pthread_mutexattr_t mutex_attribute;
31 pthread_mutexattr_init(&mutex_attribute);
32 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
33 pthread_mutex_init(&mutex_, &mutex_attribute);
34 pthread_mutexattr_destroy(&mutex_attribute);
35 #endif
36 CS_DEBUG_CODE(thread_ = 0);
37 CS_DEBUG_CODE(recursion_count_ = 0);
38 #endif
39 }
40
41 CriticalSection::~CriticalSection() {
42 #if defined(WEBRTC_WIN)
43 DeleteCriticalSection(&crit_);
44 #else
45 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
46 dispatch_release(semaphore_);
47 #else
48 pthread_mutex_destroy(&mutex_);
49 #endif
50 #endif
51 }
52
53 void CriticalSection::Enter() const EXCLUSIVE_LOCK_FUNCTION() {
54 #if defined(WEBRTC_WIN)
55 EnterCriticalSection(&crit_);
56 #else
57 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
58 int spin = 3000;
59 PlatformThreadRef self = CurrentThreadRef();
60 bool have_lock = false;
61 do {
62 // Instead of calling TryEnter() in this loop, we do two interlocked
63 // operations, first a read-only one in order to avoid affecting the lock
64 // cache-line while spinning, in case another thread is using the lock.
65 if (!IsThreadRefEqual(owning_thread_, self)) {
66 if (AtomicOps::AcquireLoad(&lock_queue_) == 0) {
67 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) {
68 have_lock = true;
69 break;
70 }
71 }
72 } else {
73 AtomicOps::Increment(&lock_queue_);
74 have_lock = true;
75 break;
76 }
77
78 sched_yield();
79 } while (--spin);
80
81 if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) {
82 // Owning thread cannot be the current thread since TryEnter() would
83 // have succeeded.
84 RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self));
85 // Wait for the lock to become available.
86 dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
87 RTC_DCHECK(owning_thread_ == 0);
88 RTC_DCHECK(!recursion_);
89 }
90
91 owning_thread_ = self;
92 ++recursion_;
93
94 #else
95 pthread_mutex_lock(&mutex_);
96 #endif
97
98 #if CS_DEBUG_CHECKS
99 if (!recursion_count_) {
100 RTC_DCHECK(!thread_);
101 thread_ = CurrentThreadRef();
102 } else {
103 RTC_DCHECK(CurrentThreadIsOwner());
104 }
105 ++recursion_count_;
106 #endif
107 #endif
108 }
109
110 bool CriticalSection::TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true) {
111 #if defined(WEBRTC_WIN)
112 return TryEnterCriticalSection(&crit_) != FALSE;
113 #else
114 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
115 if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) {
116 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0)
117 return false;
118 owning_thread_ = CurrentThreadRef();
119 RTC_DCHECK(!recursion_);
120 } else {
121 AtomicOps::Increment(&lock_queue_);
122 }
123 ++recursion_;
124 #else
125 if (pthread_mutex_trylock(&mutex_) != 0)
126 return false;
127 #endif
128 #if CS_DEBUG_CHECKS
129 if (!recursion_count_) {
130 RTC_DCHECK(!thread_);
131 thread_ = CurrentThreadRef();
132 } else {
133 RTC_DCHECK(CurrentThreadIsOwner());
134 }
135 ++recursion_count_;
136 #endif
137 return true;
138 #endif
139 }
140 void CriticalSection::Leave() const UNLOCK_FUNCTION() {
141 RTC_DCHECK(CurrentThreadIsOwner());
142 #if defined(WEBRTC_WIN)
143 LeaveCriticalSection(&crit_);
144 #else
145 #if CS_DEBUG_CHECKS
146 --recursion_count_;
147 RTC_DCHECK(recursion_count_ >= 0);
148 if (!recursion_count_)
149 thread_ = 0;
150 #endif
151 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
152 RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef()));
153 RTC_DCHECK_GE(recursion_, 0);
154 --recursion_;
155 if (!recursion_)
156 owning_thread_ = 0;
157
158 if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_)
159 dispatch_semaphore_signal(semaphore_);
160 #else
161 pthread_mutex_unlock(&mutex_);
162 #endif
163 #endif
164 }
165
166 bool CriticalSection::CurrentThreadIsOwner() const {
167 #if defined(WEBRTC_WIN)
168 // OwningThread has type HANDLE but actually contains the Thread ID:
169 // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member- of-critical-section-of-type-handle-when-it-is-de
170 // Converting through size_t avoids the VS 2015 warning C4312: conversion from
171 // 'type1' to 'type2' of greater size
172 return crit_.OwningThread ==
173 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
174 #else
175 #if CS_DEBUG_CHECKS
176 return IsThreadRefEqual(thread_, CurrentThreadRef());
177 #else
178 return true;
179 #endif // CS_DEBUG_CHECKS
180 #endif
181 }
182
183 CritScope::CritScope(const CriticalSection* cs) : cs_(cs) { cs_->Enter(); }
184 CritScope::~CritScope() { cs_->Leave(); }
185
186 TryCritScope::TryCritScope(const CriticalSection* cs)
187 : cs_(cs), locked_(cs->TryEnter()) {
188 CS_DEBUG_CODE(lock_was_called_ = false);
189 }
190
191 TryCritScope::~TryCritScope() {
192 CS_DEBUG_CODE(RTC_DCHECK(lock_was_called_));
193 if (locked_)
194 cs_->Leave();
195 }
196
197 bool TryCritScope::locked() const {
198 CS_DEBUG_CODE(lock_was_called_ = true);
199 return locked_;
200 }
201
202 void GlobalLockPod::Lock() {
203 #if !defined(WEBRTC_WIN) && (!defined(WEBRTC_MAC) || USE_NATIVE_MUTEX_ON_MAC)
204 const struct timespec ts_null = {0};
205 #endif
206
207 while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) {
208 #if defined(WEBRTC_WIN)
209 ::Sleep(0);
210 #elif defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
211 sched_yield();
212 #else
213 nanosleep(&ts_null, nullptr);
214 #endif
215 }
216 }
217
218 void GlobalLockPod::Unlock() {
219 int old_value = AtomicOps::CompareAndSwap(&lock_acquired, 1, 0);
220 RTC_DCHECK_EQ(1, old_value) << "Unlock called without calling Lock first";
221 }
222
223 GlobalLock::GlobalLock() {
224 lock_acquired = 0;
225 }
226
227 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock)
228 : lock_(lock) {
229 lock_->Lock();
230 }
231
232 GlobalLockScope::~GlobalLockScope() {
233 lock_->Unlock();
234 }
235
236 } // namespace rtc
OLDNEW

Powered by Google App Engine