OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/base/criticalsection.h" | 11 #include "webrtc/base/criticalsection.h" |
12 | 12 |
13 #include "webrtc/base/checks.h" | 13 #include "webrtc/base/checks.h" |
14 | 14 |
15 namespace rtc { | 15 namespace rtc { |
16 | 16 |
17 CriticalSection::CriticalSection() { | 17 CriticalSection::CriticalSection() { |
18 #if defined(WEBRTC_WIN) | 18 #if defined(WEBRTC_WIN) |
19 InitializeCriticalSection(&crit_); | 19 InitializeCriticalSection(&crit_); |
20 #else | 20 #else |
21 #if defined(WEBRTC_MAC) | |
22 lock_queue_ = 0; | |
23 owning_thread_ = 0; | |
24 recursion_ = 0; | |
25 semaphore_ = dispatch_semaphore_create(0); | |
26 RTC_DCHECK(semaphore_); | |
torbjorng (webrtc)
2016/01/20 15:46:43
DCHECK? Shouldn't we barf in all builds if this ca
tommi
2016/01/21 15:04:21
I'll just remove this check. It's almost akin to
| |
27 #else | |
21 pthread_mutexattr_t mutex_attribute; | 28 pthread_mutexattr_t mutex_attribute; |
22 pthread_mutexattr_init(&mutex_attribute); | 29 pthread_mutexattr_init(&mutex_attribute); |
23 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); | 30 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); |
24 pthread_mutex_init(&mutex_, &mutex_attribute); | 31 pthread_mutex_init(&mutex_, &mutex_attribute); |
25 pthread_mutexattr_destroy(&mutex_attribute); | 32 pthread_mutexattr_destroy(&mutex_attribute); |
33 #endif | |
26 CS_DEBUG_CODE(thread_ = 0); | 34 CS_DEBUG_CODE(thread_ = 0); |
27 CS_DEBUG_CODE(recursion_count_ = 0); | 35 CS_DEBUG_CODE(recursion_count_ = 0); |
28 #endif | 36 #endif |
29 } | 37 } |
30 | 38 |
31 CriticalSection::~CriticalSection() { | 39 CriticalSection::~CriticalSection() { |
32 #if defined(WEBRTC_WIN) | 40 #if defined(WEBRTC_WIN) |
33 DeleteCriticalSection(&crit_); | 41 DeleteCriticalSection(&crit_); |
34 #else | 42 #else |
43 #if defined(WEBRTC_MAC) | |
44 dispatch_release(semaphore_); | |
45 #else | |
35 pthread_mutex_destroy(&mutex_); | 46 pthread_mutex_destroy(&mutex_); |
36 #endif | 47 #endif |
48 #endif | |
37 } | 49 } |
38 | 50 |
39 void CriticalSection::Enter() EXCLUSIVE_LOCK_FUNCTION() { | 51 void CriticalSection::Enter() EXCLUSIVE_LOCK_FUNCTION() { |
40 #if defined(WEBRTC_WIN) | 52 #if defined(WEBRTC_WIN) |
41 EnterCriticalSection(&crit_); | 53 EnterCriticalSection(&crit_); |
42 #else | 54 #else |
55 #if defined(WEBRTC_MAC) | |
56 int spin = 2000; | |
57 do { | |
58 if (TryEnter()) | |
torbjorng (webrtc)
2016/01/20 15:46:43
TryEnter seems to perform a CompareAndSwap uncondi
tommi
2016/01/21 15:04:21
I rewrote the loop to not call TryEnter() but inst
| |
59 return; | |
60 sched_yield(); | |
61 } while (--spin); | |
62 | |
63 if (AtomicOps::Increment(&lock_queue_) > 0) { | |
64 // Owning thread cannot be the current thread since TryEnter() would | |
65 // have succeeded. | |
66 RTC_DCHECK(owning_thread_ != pthread_self()); | |
67 // Wait for the lock to become available. | |
68 dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER); | |
69 RTC_DCHECK(owning_thread_ == 0); | |
70 RTC_DCHECK(!recursion_); | |
71 owning_thread_ = pthread_self(); | |
72 } | |
73 | |
74 RTC_DCHECK(owning_thread_ == pthread_self()); | |
75 ++recursion_; | |
76 | |
77 #else | |
43 pthread_mutex_lock(&mutex_); | 78 pthread_mutex_lock(&mutex_); |
79 #endif | |
80 | |
44 #if CS_DEBUG_CHECKS | 81 #if CS_DEBUG_CHECKS |
45 if (!recursion_count_) { | 82 if (!recursion_count_) { |
46 RTC_DCHECK(!thread_); | 83 RTC_DCHECK(!thread_); |
47 thread_ = pthread_self(); | 84 thread_ = pthread_self(); |
48 } else { | 85 } else { |
49 RTC_DCHECK(CurrentThreadIsOwner()); | 86 RTC_DCHECK(CurrentThreadIsOwner()); |
50 } | 87 } |
51 ++recursion_count_; | 88 ++recursion_count_; |
52 #endif | 89 #endif |
53 #endif | 90 #endif |
54 } | 91 } |
55 | 92 |
56 bool CriticalSection::TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) { | 93 bool CriticalSection::TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) { |
57 #if defined(WEBRTC_WIN) | 94 #if defined(WEBRTC_WIN) |
58 return TryEnterCriticalSection(&crit_) != FALSE; | 95 return TryEnterCriticalSection(&crit_) != FALSE; |
59 #else | 96 #else |
97 #if defined(WEBRTC_MAC) | |
98 if (owning_thread_ != pthread_self()) { | |
99 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0) | |
100 return false; | |
101 owning_thread_ = pthread_self(); | |
102 RTC_DCHECK(!recursion_); | |
103 } else { | |
104 AtomicOps::Increment(&lock_queue_); | |
105 } | |
106 ++recursion_; | |
107 #else | |
60 if (pthread_mutex_trylock(&mutex_) != 0) | 108 if (pthread_mutex_trylock(&mutex_) != 0) |
61 return false; | 109 return false; |
110 #endif | |
62 #if CS_DEBUG_CHECKS | 111 #if CS_DEBUG_CHECKS |
63 if (!recursion_count_) { | 112 if (!recursion_count_) { |
64 RTC_DCHECK(!thread_); | 113 RTC_DCHECK(!thread_); |
65 thread_ = pthread_self(); | 114 thread_ = pthread_self(); |
66 } else { | 115 } else { |
67 RTC_DCHECK(CurrentThreadIsOwner()); | 116 RTC_DCHECK(CurrentThreadIsOwner()); |
68 } | 117 } |
69 ++recursion_count_; | 118 ++recursion_count_; |
70 #endif | 119 #endif |
71 return true; | 120 return true; |
72 #endif | 121 #endif |
73 } | 122 } |
74 void CriticalSection::Leave() UNLOCK_FUNCTION() { | 123 void CriticalSection::Leave() UNLOCK_FUNCTION() { |
75 RTC_DCHECK(CurrentThreadIsOwner()); | 124 RTC_DCHECK(CurrentThreadIsOwner()); |
76 #if defined(WEBRTC_WIN) | 125 #if defined(WEBRTC_WIN) |
77 LeaveCriticalSection(&crit_); | 126 LeaveCriticalSection(&crit_); |
78 #else | 127 #else |
79 #if CS_DEBUG_CHECKS | 128 #if CS_DEBUG_CHECKS |
80 --recursion_count_; | 129 --recursion_count_; |
81 RTC_DCHECK(recursion_count_ >= 0); | 130 RTC_DCHECK(recursion_count_ >= 0); |
82 if (!recursion_count_) | 131 if (!recursion_count_) |
83 thread_ = 0; | 132 thread_ = 0; |
84 #endif | 133 #endif |
134 #if defined(WEBRTC_MAC) | |
135 RTC_DCHECK_EQ(owning_thread_, pthread_self()); | |
136 RTC_DCHECK_GE(recursion_, 0); | |
137 --recursion_; | |
138 if (!recursion_) | |
139 owning_thread_ = 0; | |
140 | |
141 if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_) | |
142 dispatch_semaphore_signal(semaphore_); | |
143 #else | |
85 pthread_mutex_unlock(&mutex_); | 144 pthread_mutex_unlock(&mutex_); |
86 #endif | 145 #endif |
146 #endif | |
87 } | 147 } |
88 | 148 |
89 bool CriticalSection::CurrentThreadIsOwner() const { | 149 bool CriticalSection::CurrentThreadIsOwner() const { |
90 #if defined(WEBRTC_WIN) | 150 #if defined(WEBRTC_WIN) |
91 // OwningThread has type HANDLE but actually contains the Thread ID: | 151 // 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 | 152 // 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 | 153 // Converting through size_t avoids the VS 2015 warning C4312: conversion from |
94 // 'type1' to 'type2' of greater size | 154 // 'type1' to 'type2' of greater size |
95 return crit_.OwningThread == | 155 return crit_.OwningThread == |
96 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); | 156 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
128 if (locked_) | 188 if (locked_) |
129 cs_->Leave(); | 189 cs_->Leave(); |
130 } | 190 } |
131 | 191 |
132 bool TryCritScope::locked() const { | 192 bool TryCritScope::locked() const { |
133 CS_DEBUG_CODE(lock_was_called_ = true); | 193 CS_DEBUG_CODE(lock_was_called_ = true); |
134 return locked_; | 194 return locked_; |
135 } | 195 } |
136 | 196 |
137 void GlobalLockPod::Lock() { | 197 void GlobalLockPod::Lock() { |
138 #if !defined(WEBRTC_WIN) | 198 #if !defined(WEBRTC_WIN) && !defined(WEBRTC_MAC) |
139 const struct timespec ts_null = {0}; | 199 const struct timespec ts_null = {0}; |
140 #endif | 200 #endif |
141 | 201 |
142 while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) { | 202 while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) { |
143 #if defined(WEBRTC_WIN) | 203 #if defined(WEBRTC_WIN) |
144 ::Sleep(0); | 204 ::Sleep(0); |
205 #elif defined(WEBRTC_MAC) | |
206 sched_yield(); | |
145 #else | 207 #else |
146 nanosleep(&ts_null, nullptr); | 208 nanosleep(&ts_null, nullptr); |
147 #endif | 209 #endif |
148 } | 210 } |
149 } | 211 } |
150 | 212 |
151 void GlobalLockPod::Unlock() { | 213 void GlobalLockPod::Unlock() { |
152 int old_value = AtomicOps::CompareAndSwap(&lock_acquired, 1, 0); | 214 int old_value = AtomicOps::CompareAndSwap(&lock_acquired, 1, 0); |
153 RTC_DCHECK_EQ(1, old_value) << "Unlock called without calling Lock first"; | 215 RTC_DCHECK_EQ(1, old_value) << "Unlock called without calling Lock first"; |
154 } | 216 } |
155 | 217 |
156 GlobalLock::GlobalLock() { | 218 GlobalLock::GlobalLock() { |
157 lock_acquired = 0; | 219 lock_acquired = 0; |
158 } | 220 } |
159 | 221 |
160 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) | 222 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) |
161 : lock_(lock) { | 223 : lock_(lock) { |
162 lock_->Lock(); | 224 lock_->Lock(); |
163 } | 225 } |
164 | 226 |
165 GlobalLockScope::~GlobalLockScope() { | 227 GlobalLockScope::~GlobalLockScope() { |
166 lock_->Unlock(); | 228 lock_->Unlock(); |
167 } | 229 } |
168 | 230 |
169 } // namespace rtc | 231 } // namespace rtc |
OLD | NEW |