blob: 068b9aa80893ff066caf726919b963bf44175ef8 [file] [log] [blame]
Jiayang Liubef8d2d2015-03-26 21:38:461/*
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
Markus Handell3cb525b2020-07-16 14:16:0911#include "rtc_base/deprecated/recursive_critical_section.h"
Jiayang Liubef8d2d2015-03-26 21:38:4612
Yves Gerey988cc082018-10-23 10:03:0113#include <time.h>
14
Steve Anton10542f22019-01-11 17:11:0015#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3116#include "rtc_base/checks.h"
Tommi1f3f3c22018-02-17 10:46:1417#include "rtc_base/platform_thread_types.h"
Markus Handellf70fbc82020-06-03 22:41:2018#include "rtc_base/synchronization/yield.h"
Niels Möllera12c42a2018-07-25 14:05:4819#include "rtc_base/system/unused.h"
Jiayang Liubef8d2d2015-03-26 21:38:4620
Mirko Bonadei84ce3c02019-07-03 12:45:5421#if RTC_DCHECK_IS_ON
22#define RTC_CS_DEBUG_CODE(x) x
23#else // !RTC_DCHECK_IS_ON
24#define RTC_CS_DEBUG_CODE(x)
25#endif // !RTC_DCHECK_IS_ON
26
Jiayang Liubef8d2d2015-03-26 21:38:4627namespace rtc {
28
Markus Handell3cb525b2020-07-16 14:16:0929RecursiveCriticalSection::RecursiveCriticalSection() {
Tommi494f2092015-04-27 15:39:2330#if defined(WEBRTC_WIN)
31 InitializeCriticalSection(&crit_);
eladalond6e94662017-06-28 14:31:3032#elif defined(WEBRTC_POSIX)
Mirko Bonadeia0eefc12019-07-08 12:11:0233#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
tommied281e92016-01-22 07:47:2534 lock_queue_ = 0;
35 owning_thread_ = 0;
36 recursion_ = 0;
37 semaphore_ = dispatch_semaphore_create(0);
Yves Gerey665174f2018-06-19 13:03:0538#else
Tommi494f2092015-04-27 15:39:2339 pthread_mutexattr_t mutex_attribute;
40 pthread_mutexattr_init(&mutex_attribute);
41 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
Oskar Sundbom13471a42019-03-01 15:11:4942#if defined(WEBRTC_MAC)
43 pthread_mutexattr_setpolicy_np(&mutex_attribute,
Markus Handell4a4f1622020-06-05 09:21:1044 _PTHREAD_MUTEX_POLICY_FIRSTFIT);
Oskar Sundbom13471a42019-03-01 15:11:4945#endif
Tommi494f2092015-04-27 15:39:2346 pthread_mutex_init(&mutex_, &mutex_attribute);
47 pthread_mutexattr_destroy(&mutex_attribute);
Yves Gerey665174f2018-06-19 13:03:0548#endif
Mirko Bonadei84ce3c02019-07-03 12:45:5449 RTC_CS_DEBUG_CODE(thread_ = 0);
50 RTC_CS_DEBUG_CODE(recursion_count_ = 0);
eladalond6e94662017-06-28 14:31:3051 RTC_UNUSED(thread_);
52 RTC_UNUSED(recursion_count_);
53#else
Yves Gerey665174f2018-06-19 13:03:0554#error Unsupported platform.
Tommi494f2092015-04-27 15:39:2355#endif
56}
57
Markus Handell3cb525b2020-07-16 14:16:0958RecursiveCriticalSection::~RecursiveCriticalSection() {
Tommi494f2092015-04-27 15:39:2359#if defined(WEBRTC_WIN)
60 DeleteCriticalSection(&crit_);
eladalond6e94662017-06-28 14:31:3061#elif defined(WEBRTC_POSIX)
Mirko Bonadeia0eefc12019-07-08 12:11:0262#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
tommied281e92016-01-22 07:47:2563 dispatch_release(semaphore_);
eladalond6e94662017-06-28 14:31:3064#else
Yves Gerey665174f2018-06-19 13:03:0565 pthread_mutex_destroy(&mutex_);
66#endif
67#else
68#error Unsupported platform.
tommied281e92016-01-22 07:47:2569#endif
Tommi494f2092015-04-27 15:39:2370}
71
Markus Handell3cb525b2020-07-16 14:16:0972void RecursiveCriticalSection::Enter() const RTC_EXCLUSIVE_LOCK_FUNCTION() {
Tommi494f2092015-04-27 15:39:2373#if defined(WEBRTC_WIN)
74 EnterCriticalSection(&crit_);
eladalond6e94662017-06-28 14:31:3075#elif defined(WEBRTC_POSIX)
Mirko Bonadeia0eefc12019-07-08 12:11:0276#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
tommied281e92016-01-22 07:47:2577 int spin = 3000;
tommi7406b962016-01-22 13:13:3378 PlatformThreadRef self = CurrentThreadRef();
tommied281e92016-01-22 07:47:2579 bool have_lock = false;
80 do {
81 // Instead of calling TryEnter() in this loop, we do two interlocked
82 // operations, first a read-only one in order to avoid affecting the lock
83 // cache-line while spinning, in case another thread is using the lock.
tommi7406b962016-01-22 13:13:3384 if (!IsThreadRefEqual(owning_thread_, self)) {
tommied281e92016-01-22 07:47:2585 if (AtomicOps::AcquireLoad(&lock_queue_) == 0) {
86 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) {
87 have_lock = true;
88 break;
89 }
90 }
91 } else {
92 AtomicOps::Increment(&lock_queue_);
93 have_lock = true;
94 break;
95 }
96
97 sched_yield();
98 } while (--spin);
99
100 if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) {
101 // Owning thread cannot be the current thread since TryEnter() would
102 // have succeeded.
tommi7406b962016-01-22 13:13:33103 RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self));
tommied281e92016-01-22 07:47:25104 // Wait for the lock to become available.
105 dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
106 RTC_DCHECK(owning_thread_ == 0);
107 RTC_DCHECK(!recursion_);
108 }
109
110 owning_thread_ = self;
111 ++recursion_;
112
Yves Gerey665174f2018-06-19 13:03:05113#else
Tommi494f2092015-04-27 15:39:23114 pthread_mutex_lock(&mutex_);
Yves Gerey665174f2018-06-19 13:03:05115#endif
tommied281e92016-01-22 07:47:25116
Mirko Bonadei84ce3c02019-07-03 12:45:54117#if RTC_DCHECK_IS_ON
Tommi494f2092015-04-27 15:39:23118 if (!recursion_count_) {
henrikg91d6ede2015-09-17 07:24:34119 RTC_DCHECK(!thread_);
tommi7406b962016-01-22 13:13:33120 thread_ = CurrentThreadRef();
Tommi494f2092015-04-27 15:39:23121 } else {
henrikg91d6ede2015-09-17 07:24:34122 RTC_DCHECK(CurrentThreadIsOwner());
Tommi494f2092015-04-27 15:39:23123 }
124 ++recursion_count_;
Yves Gerey665174f2018-06-19 13:03:05125#endif
eladalond6e94662017-06-28 14:31:30126#else
Yves Gerey665174f2018-06-19 13:03:05127#error Unsupported platform.
Tommi494f2092015-04-27 15:39:23128#endif
129}
130
Markus Handell3cb525b2020-07-16 14:16:09131bool RecursiveCriticalSection::TryEnter() const
132 RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
Tommi494f2092015-04-27 15:39:23133#if defined(WEBRTC_WIN)
134 return TryEnterCriticalSection(&crit_) != FALSE;
eladalond6e94662017-06-28 14:31:30135#elif defined(WEBRTC_POSIX)
Mirko Bonadeia0eefc12019-07-08 12:11:02136#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
tommi7406b962016-01-22 13:13:33137 if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) {
tommied281e92016-01-22 07:47:25138 if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0)
139 return false;
tommi7406b962016-01-22 13:13:33140 owning_thread_ = CurrentThreadRef();
tommied281e92016-01-22 07:47:25141 RTC_DCHECK(!recursion_);
142 } else {
143 AtomicOps::Increment(&lock_queue_);
144 }
145 ++recursion_;
Yves Gerey665174f2018-06-19 13:03:05146#else
Tommi494f2092015-04-27 15:39:23147 if (pthread_mutex_trylock(&mutex_) != 0)
148 return false;
Yves Gerey665174f2018-06-19 13:03:05149#endif
Mirko Bonadei84ce3c02019-07-03 12:45:54150#if RTC_DCHECK_IS_ON
Tommi494f2092015-04-27 15:39:23151 if (!recursion_count_) {
henrikg91d6ede2015-09-17 07:24:34152 RTC_DCHECK(!thread_);
tommi7406b962016-01-22 13:13:33153 thread_ = CurrentThreadRef();
Tommi494f2092015-04-27 15:39:23154 } else {
henrikg91d6ede2015-09-17 07:24:34155 RTC_DCHECK(CurrentThreadIsOwner());
Tommi494f2092015-04-27 15:39:23156 }
157 ++recursion_count_;
Yves Gerey665174f2018-06-19 13:03:05158#endif
Tommi494f2092015-04-27 15:39:23159 return true;
eladalond6e94662017-06-28 14:31:30160#else
Yves Gerey665174f2018-06-19 13:03:05161#error Unsupported platform.
Tommi494f2092015-04-27 15:39:23162#endif
163}
eladalond6e94662017-06-28 14:31:30164
Markus Handell3cb525b2020-07-16 14:16:09165void RecursiveCriticalSection::Leave() const RTC_UNLOCK_FUNCTION() {
henrikg91d6ede2015-09-17 07:24:34166 RTC_DCHECK(CurrentThreadIsOwner());
Tommi494f2092015-04-27 15:39:23167#if defined(WEBRTC_WIN)
168 LeaveCriticalSection(&crit_);
eladalond6e94662017-06-28 14:31:30169#elif defined(WEBRTC_POSIX)
Mirko Bonadei84ce3c02019-07-03 12:45:54170#if RTC_DCHECK_IS_ON
Tommi494f2092015-04-27 15:39:23171 --recursion_count_;
henrikg91d6ede2015-09-17 07:24:34172 RTC_DCHECK(recursion_count_ >= 0);
Tommi494f2092015-04-27 15:39:23173 if (!recursion_count_)
174 thread_ = 0;
Yves Gerey665174f2018-06-19 13:03:05175#endif
Mirko Bonadeia0eefc12019-07-08 12:11:02176#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
tommi7406b962016-01-22 13:13:33177 RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef()));
tommied281e92016-01-22 07:47:25178 RTC_DCHECK_GE(recursion_, 0);
179 --recursion_;
180 if (!recursion_)
181 owning_thread_ = 0;
182
183 if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_)
184 dispatch_semaphore_signal(semaphore_);
eladalond6e94662017-06-28 14:31:30185#else
Yves Gerey665174f2018-06-19 13:03:05186 pthread_mutex_unlock(&mutex_);
187#endif
188#else
189#error Unsupported platform.
tommied281e92016-01-22 07:47:25190#endif
Tommi494f2092015-04-27 15:39:23191}
192
Markus Handell3cb525b2020-07-16 14:16:09193bool RecursiveCriticalSection::CurrentThreadIsOwner() const {
Tommi494f2092015-04-27 15:39:23194#if defined(WEBRTC_WIN)
brucedawsona10492f2015-10-06 20:34:30195 // OwningThread has type HANDLE but actually contains the Thread ID:
196 // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de
197 // Converting through size_t avoids the VS 2015 warning C4312: conversion from
198 // 'type1' to 'type2' of greater size
199 return crit_.OwningThread ==
200 reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
eladalond6e94662017-06-28 14:31:30201#elif defined(WEBRTC_POSIX)
Mirko Bonadei84ce3c02019-07-03 12:45:54202#if RTC_DCHECK_IS_ON
tommi7406b962016-01-22 13:13:33203 return IsThreadRefEqual(thread_, CurrentThreadRef());
eladalond6e94662017-06-28 14:31:30204#else
Yves Gerey665174f2018-06-19 13:03:05205 return true;
Mirko Bonadei84ce3c02019-07-03 12:45:54206#endif // RTC_DCHECK_IS_ON
Yves Gerey665174f2018-06-19 13:03:05207#else
208#error Unsupported platform.
Tommi494f2092015-04-27 15:39:23209#endif
210}
211
Markus Handell3cb525b2020-07-16 14:16:09212CritScope::CritScope(const RecursiveCriticalSection* cs) : cs_(cs) {
Yves Gerey665174f2018-06-19 13:03:05213 cs_->Enter();
214}
215CritScope::~CritScope() {
216 cs_->Leave();
217}
Tommi494f2092015-04-27 15:39:23218
Jiayang Liubef8d2d2015-03-26 21:38:46219} // namespace rtc