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 #include "webrtc/base/platform_thread.h" |
14 | 15 |
15 // TODO(tommi): Split this file up to per-platform implementation files. | 16 // TODO(tommi): Split this file up to per-platform implementation files. |
16 | 17 |
17 namespace rtc { | 18 namespace rtc { |
18 | 19 |
19 CriticalSection::CriticalSection() { | 20 CriticalSection::CriticalSection() { |
20 #if defined(WEBRTC_WIN) | 21 #if defined(WEBRTC_WIN) |
21 InitializeCriticalSection(&crit_); | 22 InitializeCriticalSection(&crit_); |
22 #else | 23 #else |
23 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 24 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
(...skipping 24 matching lines...) Expand all Loading... |
48 #endif | 49 #endif |
49 #endif | 50 #endif |
50 } | 51 } |
51 | 52 |
52 void CriticalSection::Enter() const EXCLUSIVE_LOCK_FUNCTION() { | 53 void CriticalSection::Enter() const EXCLUSIVE_LOCK_FUNCTION() { |
53 #if defined(WEBRTC_WIN) | 54 #if defined(WEBRTC_WIN) |
54 EnterCriticalSection(&crit_); | 55 EnterCriticalSection(&crit_); |
55 #else | 56 #else |
56 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 57 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
57 int spin = 3000; | 58 int spin = 3000; |
58 pthread_t self = pthread_self(); | 59 PlatformThreadRef self = CurrentThreadRef(); |
59 bool have_lock = false; | 60 bool have_lock = false; |
60 do { | 61 do { |
61 // Instead of calling TryEnter() in this loop, we do two interlocked | 62 // Instead of calling TryEnter() in this loop, we do two interlocked |
62 // operations, first a read-only one in order to avoid affecting the lock | 63 // operations, first a read-only one in order to avoid affecting the lock |
63 // cache-line while spinning, in case another thread is using the lock. | 64 // cache-line while spinning, in case another thread is using the lock. |
64 if (owning_thread_ != self) { | 65 if (!IsThreadRefEqual(owning_thread_, self)) { |
65 if (AtomicOps::AcquireLoad(&lock_queue_) == 0) { | 66 if (AtomicOps::AcquireLoad(&lock_queue_) == 0) { |
66 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) { | 67 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) { |
67 have_lock = true; | 68 have_lock = true; |
68 break; | 69 break; |
69 } | 70 } |
70 } | 71 } |
71 } else { | 72 } else { |
72 AtomicOps::Increment(&lock_queue_); | 73 AtomicOps::Increment(&lock_queue_); |
73 have_lock = true; | 74 have_lock = true; |
74 break; | 75 break; |
75 } | 76 } |
76 | 77 |
77 sched_yield(); | 78 sched_yield(); |
78 } while (--spin); | 79 } while (--spin); |
79 | 80 |
80 if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) { | 81 if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) { |
81 // Owning thread cannot be the current thread since TryEnter() would | 82 // Owning thread cannot be the current thread since TryEnter() would |
82 // have succeeded. | 83 // have succeeded. |
83 RTC_DCHECK(owning_thread_ != self); | 84 RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self)); |
84 // Wait for the lock to become available. | 85 // Wait for the lock to become available. |
85 dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER); | 86 dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER); |
86 RTC_DCHECK(owning_thread_ == 0); | 87 RTC_DCHECK(owning_thread_ == 0); |
87 RTC_DCHECK(!recursion_); | 88 RTC_DCHECK(!recursion_); |
88 } | 89 } |
89 | 90 |
90 owning_thread_ = self; | 91 owning_thread_ = self; |
91 ++recursion_; | 92 ++recursion_; |
92 | 93 |
93 #else | 94 #else |
94 pthread_mutex_lock(&mutex_); | 95 pthread_mutex_lock(&mutex_); |
95 #endif | 96 #endif |
96 | 97 |
97 #if CS_DEBUG_CHECKS | 98 #if CS_DEBUG_CHECKS |
98 if (!recursion_count_) { | 99 if (!recursion_count_) { |
99 RTC_DCHECK(!thread_); | 100 RTC_DCHECK(!thread_); |
100 thread_ = pthread_self(); | 101 thread_ = CurrentThreadRef(); |
101 } else { | 102 } else { |
102 RTC_DCHECK(CurrentThreadIsOwner()); | 103 RTC_DCHECK(CurrentThreadIsOwner()); |
103 } | 104 } |
104 ++recursion_count_; | 105 ++recursion_count_; |
105 #endif | 106 #endif |
106 #endif | 107 #endif |
107 } | 108 } |
108 | 109 |
109 bool CriticalSection::TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true) { | 110 bool CriticalSection::TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true) { |
110 #if defined(WEBRTC_WIN) | 111 #if defined(WEBRTC_WIN) |
111 return TryEnterCriticalSection(&crit_) != FALSE; | 112 return TryEnterCriticalSection(&crit_) != FALSE; |
112 #else | 113 #else |
113 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 114 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
114 if (owning_thread_ != pthread_self()) { | 115 if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) { |
115 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0) | 116 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0) |
116 return false; | 117 return false; |
117 owning_thread_ = pthread_self(); | 118 owning_thread_ = CurrentThreadRef(); |
118 RTC_DCHECK(!recursion_); | 119 RTC_DCHECK(!recursion_); |
119 } else { | 120 } else { |
120 AtomicOps::Increment(&lock_queue_); | 121 AtomicOps::Increment(&lock_queue_); |
121 } | 122 } |
122 ++recursion_; | 123 ++recursion_; |
123 #else | 124 #else |
124 if (pthread_mutex_trylock(&mutex_) != 0) | 125 if (pthread_mutex_trylock(&mutex_) != 0) |
125 return false; | 126 return false; |
126 #endif | 127 #endif |
127 #if CS_DEBUG_CHECKS | 128 #if CS_DEBUG_CHECKS |
128 if (!recursion_count_) { | 129 if (!recursion_count_) { |
129 RTC_DCHECK(!thread_); | 130 RTC_DCHECK(!thread_); |
130 thread_ = pthread_self(); | 131 thread_ = CurrentThreadRef(); |
131 } else { | 132 } else { |
132 RTC_DCHECK(CurrentThreadIsOwner()); | 133 RTC_DCHECK(CurrentThreadIsOwner()); |
133 } | 134 } |
134 ++recursion_count_; | 135 ++recursion_count_; |
135 #endif | 136 #endif |
136 return true; | 137 return true; |
137 #endif | 138 #endif |
138 } | 139 } |
139 void CriticalSection::Leave() const UNLOCK_FUNCTION() { | 140 void CriticalSection::Leave() const UNLOCK_FUNCTION() { |
140 RTC_DCHECK(CurrentThreadIsOwner()); | 141 RTC_DCHECK(CurrentThreadIsOwner()); |
141 #if defined(WEBRTC_WIN) | 142 #if defined(WEBRTC_WIN) |
142 LeaveCriticalSection(&crit_); | 143 LeaveCriticalSection(&crit_); |
143 #else | 144 #else |
144 #if CS_DEBUG_CHECKS | 145 #if CS_DEBUG_CHECKS |
145 --recursion_count_; | 146 --recursion_count_; |
146 RTC_DCHECK(recursion_count_ >= 0); | 147 RTC_DCHECK(recursion_count_ >= 0); |
147 if (!recursion_count_) | 148 if (!recursion_count_) |
148 thread_ = 0; | 149 thread_ = 0; |
149 #endif | 150 #endif |
150 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC | 151 #if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC |
151 RTC_DCHECK_EQ(owning_thread_, pthread_self()); | 152 RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef())); |
152 RTC_DCHECK_GE(recursion_, 0); | 153 RTC_DCHECK_GE(recursion_, 0); |
153 --recursion_; | 154 --recursion_; |
154 if (!recursion_) | 155 if (!recursion_) |
155 owning_thread_ = 0; | 156 owning_thread_ = 0; |
156 | 157 |
157 if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_) | 158 if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_) |
158 dispatch_semaphore_signal(semaphore_); | 159 dispatch_semaphore_signal(semaphore_); |
159 #else | 160 #else |
160 pthread_mutex_unlock(&mutex_); | 161 pthread_mutex_unlock(&mutex_); |
161 #endif | 162 #endif |
162 #endif | 163 #endif |
163 } | 164 } |
164 | 165 |
165 bool CriticalSection::CurrentThreadIsOwner() const { | 166 bool CriticalSection::CurrentThreadIsOwner() const { |
166 #if defined(WEBRTC_WIN) | 167 #if defined(WEBRTC_WIN) |
167 // OwningThread has type HANDLE but actually contains the Thread ID: | 168 // OwningThread has type HANDLE but actually contains the Thread ID: |
168 // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-
of-critical-section-of-type-handle-when-it-is-de | 169 // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-
of-critical-section-of-type-handle-when-it-is-de |
169 // Converting through size_t avoids the VS 2015 warning C4312: conversion from | 170 // Converting through size_t avoids the VS 2015 warning C4312: conversion from |
170 // 'type1' to 'type2' of greater size | 171 // 'type1' to 'type2' of greater size |
171 return crit_.OwningThread == | 172 return crit_.OwningThread == |
172 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); | 173 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); |
173 #else | 174 #else |
174 #if CS_DEBUG_CHECKS | 175 #if CS_DEBUG_CHECKS |
175 return pthread_equal(thread_, pthread_self()); | 176 return IsThreadRefEqual(thread_, CurrentThreadRef()); |
176 #else | 177 #else |
177 return true; | 178 return true; |
178 #endif // CS_DEBUG_CHECKS | 179 #endif // CS_DEBUG_CHECKS |
179 #endif | 180 #endif |
180 } | 181 } |
181 | 182 |
182 bool CriticalSection::IsLocked() const { | 183 bool CriticalSection::IsLocked() const { |
183 #if defined(WEBRTC_WIN) | 184 #if defined(WEBRTC_WIN) |
184 return crit_.LockCount != -1; | 185 return crit_.LockCount != -1; |
185 #else | 186 #else |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) | 239 GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) |
239 : lock_(lock) { | 240 : lock_(lock) { |
240 lock_->Lock(); | 241 lock_->Lock(); |
241 } | 242 } |
242 | 243 |
243 GlobalLockScope::~GlobalLockScope() { | 244 GlobalLockScope::~GlobalLockScope() { |
244 lock_->Unlock(); | 245 lock_->Unlock(); |
245 } | 246 } |
246 | 247 |
247 } // namespace rtc | 248 } // namespace rtc |
OLD | NEW |