summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/deprecated
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/rtc_base/deprecated')
-rw-r--r--third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc218
-rw-r--r--third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h107
-rw-r--r--third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc288
3 files changed, 613 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc
new file mode 100644
index 0000000000..540819888e
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2015 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/deprecated/recursive_critical_section.h"
+
+#include <time.h>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/synchronization/yield.h"
+#include "rtc_base/system/unused.h"
+
+#if RTC_DCHECK_IS_ON
+#define RTC_CS_DEBUG_CODE(x) x
+#else // !RTC_DCHECK_IS_ON
+#define RTC_CS_DEBUG_CODE(x)
+#endif // !RTC_DCHECK_IS_ON
+
+namespace rtc {
+
+RecursiveCriticalSection::RecursiveCriticalSection() {
+#if defined(WEBRTC_WIN)
+ InitializeCriticalSection(&crit_);
+#elif defined(WEBRTC_POSIX)
+#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
+ lock_queue_ = 0;
+ owning_thread_ = 0;
+ recursion_ = 0;
+ semaphore_ = dispatch_semaphore_create(0);
+#else
+ pthread_mutexattr_t mutex_attribute;
+ pthread_mutexattr_init(&mutex_attribute);
+ pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
+#if defined(WEBRTC_MAC)
+ pthread_mutexattr_setpolicy_np(&mutex_attribute,
+ _PTHREAD_MUTEX_POLICY_FIRSTFIT);
+#endif
+ pthread_mutex_init(&mutex_, &mutex_attribute);
+ pthread_mutexattr_destroy(&mutex_attribute);
+#endif
+ RTC_CS_DEBUG_CODE(thread_ = 0);
+ RTC_CS_DEBUG_CODE(recursion_count_ = 0);
+ RTC_UNUSED(thread_);
+ RTC_UNUSED(recursion_count_);
+#else
+#error Unsupported platform.
+#endif
+}
+
+RecursiveCriticalSection::~RecursiveCriticalSection() {
+#if defined(WEBRTC_WIN)
+ DeleteCriticalSection(&crit_);
+#elif defined(WEBRTC_POSIX)
+#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
+ dispatch_release(semaphore_);
+#else
+ pthread_mutex_destroy(&mutex_);
+#endif
+#else
+#error Unsupported platform.
+#endif
+}
+
+void RecursiveCriticalSection::Enter() const RTC_EXCLUSIVE_LOCK_FUNCTION() {
+#if defined(WEBRTC_WIN)
+ EnterCriticalSection(&crit_);
+#elif defined(WEBRTC_POSIX)
+#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
+ int spin = 3000;
+ PlatformThreadRef self = CurrentThreadRef();
+ bool have_lock = false;
+ do {
+ // Instead of calling TryEnter() in this loop, we do two interlocked
+ // operations, first a read-only one in order to avoid affecting the lock
+ // cache-line while spinning, in case another thread is using the lock.
+ if (!IsThreadRefEqual(owning_thread_, self)) {
+ if (AtomicOps::AcquireLoad(&lock_queue_) == 0) {
+ if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) {
+ have_lock = true;
+ break;
+ }
+ }
+ } else {
+ AtomicOps::Increment(&lock_queue_);
+ have_lock = true;
+ break;
+ }
+
+ sched_yield();
+ } while (--spin);
+
+ if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) {
+ // Owning thread cannot be the current thread since TryEnter() would
+ // have succeeded.
+ RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self));
+ // Wait for the lock to become available.
+ dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
+ RTC_DCHECK(owning_thread_ == 0);
+ RTC_DCHECK(!recursion_);
+ }
+
+ owning_thread_ = self;
+ ++recursion_;
+
+#else
+ pthread_mutex_lock(&mutex_);
+#endif
+
+#if RTC_DCHECK_IS_ON
+ if (!recursion_count_) {
+ RTC_DCHECK(!thread_);
+ thread_ = CurrentThreadRef();
+ } else {
+ RTC_DCHECK(CurrentThreadIsOwner());
+ }
+ ++recursion_count_;
+#endif
+#else
+#error Unsupported platform.
+#endif
+}
+
+bool RecursiveCriticalSection::TryEnter() const
+ RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+#if defined(WEBRTC_WIN)
+ return TryEnterCriticalSection(&crit_) != FALSE;
+#elif defined(WEBRTC_POSIX)
+#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
+ if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) {
+ if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0)
+ return false;
+ owning_thread_ = CurrentThreadRef();
+ RTC_DCHECK(!recursion_);
+ } else {
+ AtomicOps::Increment(&lock_queue_);
+ }
+ ++recursion_;
+#else
+ if (pthread_mutex_trylock(&mutex_) != 0)
+ return false;
+#endif
+#if RTC_DCHECK_IS_ON
+ if (!recursion_count_) {
+ RTC_DCHECK(!thread_);
+ thread_ = CurrentThreadRef();
+ } else {
+ RTC_DCHECK(CurrentThreadIsOwner());
+ }
+ ++recursion_count_;
+#endif
+ return true;
+#else
+#error Unsupported platform.
+#endif
+}
+
+void RecursiveCriticalSection::Leave() const RTC_UNLOCK_FUNCTION() {
+ RTC_DCHECK(CurrentThreadIsOwner());
+#if defined(WEBRTC_WIN)
+ LeaveCriticalSection(&crit_);
+#elif defined(WEBRTC_POSIX)
+#if RTC_DCHECK_IS_ON
+ --recursion_count_;
+ RTC_DCHECK(recursion_count_ >= 0);
+ if (!recursion_count_)
+ thread_ = 0;
+#endif
+#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
+ RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef()));
+ RTC_DCHECK_GE(recursion_, 0);
+ --recursion_;
+ if (!recursion_)
+ owning_thread_ = 0;
+
+ if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_)
+ dispatch_semaphore_signal(semaphore_);
+#else
+ pthread_mutex_unlock(&mutex_);
+#endif
+#else
+#error Unsupported platform.
+#endif
+}
+
+bool RecursiveCriticalSection::CurrentThreadIsOwner() const {
+#if defined(WEBRTC_WIN)
+ // OwningThread has type HANDLE but actually contains the Thread ID:
+ // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de
+ // Converting through size_t avoids the VS 2015 warning C4312: conversion from
+ // 'type1' to 'type2' of greater size
+ return crit_.OwningThread ==
+ reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
+#elif defined(WEBRTC_POSIX)
+#if RTC_DCHECK_IS_ON
+ return IsThreadRefEqual(thread_, CurrentThreadRef());
+#else
+ return true;
+#endif // RTC_DCHECK_IS_ON
+#else
+#error Unsupported platform.
+#endif
+}
+
+CritScope::CritScope(const RecursiveCriticalSection* cs) : cs_(cs) {
+ cs_->Enter();
+}
+CritScope::~CritScope() {
+ cs_->Leave();
+}
+
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h
new file mode 100644
index 0000000000..da1e92b9b0
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_
+#define RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_
+
+#include <atomic>
+
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/thread_annotations.h"
+
+#if defined(WEBRTC_WIN)
+// clang-format off
+// clang formating would change include order.
+
+// Include winsock2.h before including <windows.h> to maintain consistency with
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
+#include <winsock2.h>
+#include <windows.h>
+#include <sal.h> // must come after windows headers.
+// clang-format on
+#endif // defined(WEBRTC_WIN)
+
+#if defined(WEBRTC_POSIX)
+#include <pthread.h>
+#endif
+
+// See notes in the 'Performance' unit test for the effects of this flag.
+#define RTC_USE_NATIVE_MUTEX_ON_MAC 1
+
+#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
+#include <dispatch/dispatch.h>
+#endif
+
+namespace rtc {
+
+// NOTE: This class is deprecated. Please use webrtc::Mutex instead!
+// Search using https://www.google.com/?q=recursive+lock+considered+harmful
+// to find the reasons.
+//
+// Locking methods (Enter, TryEnter, Leave)are const to permit protecting
+// members inside a const context without requiring mutable
+// RecursiveCriticalSections everywhere. RecursiveCriticalSection is
+// reentrant lock.
+class RTC_LOCKABLE RecursiveCriticalSection {
+ public:
+ RecursiveCriticalSection();
+ ~RecursiveCriticalSection();
+
+ void Enter() const RTC_EXCLUSIVE_LOCK_FUNCTION();
+ bool TryEnter() const RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ void Leave() const RTC_UNLOCK_FUNCTION();
+
+ private:
+ // Use only for RTC_DCHECKing.
+ bool CurrentThreadIsOwner() const;
+
+#if defined(WEBRTC_WIN)
+ mutable CRITICAL_SECTION crit_;
+#elif defined(WEBRTC_POSIX)
+#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC
+ // Number of times the lock has been locked + number of threads waiting.
+ // TODO(tommi): We could use this number and subtract the recursion count
+ // to find places where we have multiple threads contending on the same lock.
+ mutable std::atomic<int> lock_queue_;
+ // `recursion_` represents the recursion count + 1 for the thread that owns
+ // the lock. Only modified by the thread that owns the lock.
+ mutable int recursion_;
+ // Used to signal a single waiting thread when the lock becomes available.
+ mutable dispatch_semaphore_t semaphore_;
+ // The thread that currently holds the lock. Required to handle recursion.
+ mutable PlatformThreadRef owning_thread_;
+#else
+ mutable pthread_mutex_t mutex_;
+#endif
+ mutable PlatformThreadRef thread_; // Only used by RTC_DCHECKs.
+ mutable int recursion_count_; // Only used by RTC_DCHECKs.
+#else // !defined(WEBRTC_WIN) && !defined(WEBRTC_POSIX)
+#error Unsupported platform.
+#endif
+};
+
+// CritScope, for serializing execution through a scope.
+class RTC_SCOPED_LOCKABLE CritScope {
+ public:
+ explicit CritScope(const RecursiveCriticalSection* cs)
+ RTC_EXCLUSIVE_LOCK_FUNCTION(cs);
+ ~CritScope() RTC_UNLOCK_FUNCTION();
+
+ CritScope(const CritScope&) = delete;
+ CritScope& operator=(const CritScope&) = delete;
+
+ private:
+ const RecursiveCriticalSection* const cs_;
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_
diff --git a/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc
new file mode 100644
index 0000000000..38f003d555
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2014 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/deprecated/recursive_critical_section.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/event.h"
+#include "rtc_base/platform_thread.h"
+#include "rtc_base/thread.h"
+#include "test/gtest.h"
+
+namespace rtc {
+
+namespace {
+
+constexpr webrtc::TimeDelta kLongTime = webrtc::TimeDelta::Seconds(10);
+constexpr int kNumThreads = 16;
+constexpr int kOperationsToRun = 1000;
+
+class UniqueValueVerifier {
+ public:
+ void Verify(const std::vector<int>& values) {
+ for (size_t i = 0; i < values.size(); ++i) {
+ std::pair<std::set<int>::iterator, bool> result =
+ all_values_.insert(values[i]);
+ // Each value should only be taken by one thread, so if this value
+ // has already been added, something went wrong.
+ EXPECT_TRUE(result.second)
+ << " Thread=" << Thread::Current() << " value=" << values[i];
+ }
+ }
+
+ void Finalize() {}
+
+ private:
+ std::set<int> all_values_;
+};
+
+class CompareAndSwapVerifier {
+ public:
+ CompareAndSwapVerifier() : zero_count_(0) {}
+
+ void Verify(const std::vector<int>& values) {
+ for (auto v : values) {
+ if (v == 0) {
+ EXPECT_EQ(0, zero_count_) << "Thread=" << Thread::Current();
+ ++zero_count_;
+ } else {
+ EXPECT_EQ(1, v) << " Thread=" << Thread::Current();
+ }
+ }
+ }
+
+ void Finalize() { EXPECT_EQ(1, zero_count_); }
+
+ private:
+ int zero_count_;
+};
+
+class RunnerBase {
+ public:
+ explicit RunnerBase(int value)
+ : threads_active_(0),
+ start_event_(true, false),
+ done_event_(true, false),
+ shared_value_(value) {}
+
+ bool Run() {
+ // Signal all threads to start.
+ start_event_.Set();
+
+ // Wait for all threads to finish.
+ return done_event_.Wait(kLongTime);
+ }
+
+ void SetExpectedThreadCount(int count) { threads_active_.store(count); }
+
+ int shared_value() const { return shared_value_; }
+
+ protected:
+ void BeforeStart() { ASSERT_TRUE(start_event_.Wait(kLongTime)); }
+
+ // Returns true if all threads have finished.
+ bool AfterEnd() {
+ if (threads_active_.fetch_sub(1) == 1) {
+ done_event_.Set();
+ return true;
+ }
+ return false;
+ }
+
+ std::atomic<int> threads_active_;
+ Event start_event_;
+ Event done_event_;
+ int shared_value_;
+};
+
+class RTC_LOCKABLE CriticalSectionLock {
+ public:
+ void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { cs_.Enter(); }
+ void Unlock() RTC_UNLOCK_FUNCTION() { cs_.Leave(); }
+
+ private:
+ RecursiveCriticalSection cs_;
+};
+
+template <class Lock>
+class LockRunner : public RunnerBase {
+ public:
+ LockRunner() : RunnerBase(0) {}
+
+ void Loop() {
+ BeforeStart();
+
+ lock_.Lock();
+
+ EXPECT_EQ(0, shared_value_);
+ int old = shared_value_;
+
+ // Use a loop to increase the chance of race.
+ for (int i = 0; i < kOperationsToRun; ++i) {
+ ++shared_value_;
+ }
+ EXPECT_EQ(old + kOperationsToRun, shared_value_);
+ shared_value_ = 0;
+
+ lock_.Unlock();
+
+ AfterEnd();
+ }
+
+ private:
+ Lock lock_;
+};
+
+template <typename Runner>
+void StartThreads(std::vector<std::unique_ptr<Thread>>* threads,
+ Runner* handler) {
+ for (int i = 0; i < kNumThreads; ++i) {
+ std::unique_ptr<Thread> thread(Thread::Create());
+ thread->Start();
+ thread->PostTask([handler] { handler->Loop(); });
+ threads->push_back(std::move(thread));
+ }
+}
+
+} // namespace
+
+TEST(RecursiveCriticalSectionTest, Basic) {
+ // Create and start lots of threads.
+ LockRunner<CriticalSectionLock> runner;
+ std::vector<std::unique_ptr<Thread>> threads;
+ StartThreads(&threads, &runner);
+ runner.SetExpectedThreadCount(kNumThreads);
+
+ // Release the hounds!
+ EXPECT_TRUE(runner.Run());
+ EXPECT_EQ(0, runner.shared_value());
+}
+
+class PerfTestData {
+ public:
+ PerfTestData(int expected_count, Event* event)
+ : cache_line_barrier_1_(),
+ cache_line_barrier_2_(),
+ expected_count_(expected_count),
+ event_(event) {
+ cache_line_barrier_1_[0]++; // Avoid 'is not used'.
+ cache_line_barrier_2_[0]++; // Avoid 'is not used'.
+ }
+ ~PerfTestData() {}
+
+ void AddToCounter(int add) {
+ rtc::CritScope cs(&lock_);
+ my_counter_ += add;
+ if (my_counter_ == expected_count_)
+ event_->Set();
+ }
+
+ int64_t total() const {
+ // Assume that only one thread is running now.
+ return my_counter_;
+ }
+
+ private:
+ uint8_t cache_line_barrier_1_[64];
+ RecursiveCriticalSection lock_;
+ uint8_t cache_line_barrier_2_[64];
+ int64_t my_counter_ = 0;
+ const int expected_count_;
+ Event* const event_;
+};
+
+class PerfTestThread {
+ public:
+ void Start(PerfTestData* data, int repeats, int id) {
+ RTC_DCHECK(!data_);
+ data_ = data;
+ repeats_ = repeats;
+ my_id_ = id;
+ thread_ = PlatformThread::SpawnJoinable(
+ [this] {
+ for (int i = 0; i < repeats_; ++i)
+ data_->AddToCounter(my_id_);
+ },
+ "CsPerf");
+ }
+
+ void Stop() {
+ RTC_DCHECK(data_);
+ thread_.Finalize();
+ repeats_ = 0;
+ data_ = nullptr;
+ my_id_ = 0;
+ }
+
+ private:
+ PlatformThread thread_;
+ PerfTestData* data_ = nullptr;
+ int repeats_ = 0;
+ int my_id_ = 0;
+};
+
+// Comparison of output of this test as tested on a MacBook Pro, 13-inch,
+// 2017, 3,5 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3,
+// running macOS Mojave, 10.14.3.
+//
+// Native mutex implementation using fair policy (previously macOS default):
+// Approximate CPU usage:
+// real 4m54.612s
+// user 1m20.575s
+// sys 3m48.872s
+// Unit test output:
+// [ OK ] RecursiveCriticalSectionTest.Performance (294375 ms)
+//
+// Native mutex implementation using first fit policy (current macOS default):
+// Approximate CPU usage:
+// real 0m11.535s
+// user 0m12.738s
+// sys 0m31.207s
+// Unit test output:
+// [ OK ] RecursiveCriticalSectionTest.Performance (11444 ms)
+//
+// Special partially spin lock based implementation:
+// Approximate CPU usage:
+// real 0m2.113s
+// user 0m3.014s
+// sys 0m4.495s
+// Unit test output:
+// [ OK ] RecursiveCriticalSectionTest.Performance (1885 ms)
+//
+// The test is disabled by default to avoid unecessarily loading the bots.
+TEST(RecursiveCriticalSectionTest, DISABLED_Performance) {
+ PerfTestThread threads[8];
+ Event event;
+
+ static const int kThreadRepeats = 10000000;
+ static const int kExpectedCount = kThreadRepeats * arraysize(threads);
+ PerfTestData test_data(kExpectedCount, &event);
+
+ for (auto& t : threads)
+ t.Start(&test_data, kThreadRepeats, 1);
+
+ event.Wait(Event::kForever);
+
+ for (auto& t : threads)
+ t.Stop();
+}
+
+} // namespace rtc