diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/third_party/webrtc/rtc_base | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/webrtc/rtc_base')
66 files changed, 1658 insertions, 474 deletions
diff --git a/chromium/third_party/webrtc/rtc_base/BUILD.gn b/chromium/third_party/webrtc/rtc_base/BUILD.gn index a61ede4ac98..c62b3f6afe7 100644 --- a/chromium/third_party/webrtc/rtc_base/BUILD.gn +++ b/chromium/third_party/webrtc/rtc_base/BUILD.gn @@ -59,8 +59,8 @@ rtc_library("rtc_base_approved") { "system:rtc_export", "system:unused", "third_party/base64", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [] # no-presubmit-check TODO(webrtc:8603) sources = [ @@ -154,6 +154,7 @@ rtc_library("platform_thread_types") { "platform_thread_types.cc", "platform_thread_types.h", ] + deps = [ ":macromagic" ] } rtc_source_set("refcount") { @@ -176,6 +177,7 @@ rtc_library("criticalsection") { ":checks", ":macromagic", ":platform_thread_types", + "synchronization:yield", "system:rtc_export", "system:unused", ] @@ -187,6 +189,7 @@ rtc_library("platform_thread") { ":rtc_task_queue_libevent", ":rtc_task_queue_win", ":rtc_task_queue_stdlib", + "synchronization:mutex", "synchronization:sequence_checker", ] sources = [ @@ -201,8 +204,8 @@ rtc_library("platform_thread") { ":rtc_event", ":thread_checker", ":timeutils", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("rtc_event") { @@ -225,8 +228,8 @@ rtc_library("rtc_event") { ":checks", "synchronization:yield_policy", "system:warn_current_thread_is_deadlocked", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } @@ -240,6 +243,9 @@ rtc_library("logging") { ":platform_thread_types", ":stringutils", ":timeutils", + "synchronization:mutex", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/meta:type_traits", "//third_party/abseil-cpp/absl/strings", @@ -301,6 +307,8 @@ rtc_library("checks") { ":safe_compare", "system:inline", "system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/meta:type_traits", "//third_party/abseil-cpp/absl/strings", ] @@ -317,13 +325,13 @@ rtc_library("rate_limiter") { deps = [ ":rtc_base_approved", "../system_wrappers", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_source_set("sanitizer") { sources = [ "sanitizer.h" ] - deps = [ "//third_party/abseil-cpp/absl/meta:type_traits" ] + absl_deps = [ "//third_party/abseil-cpp/absl/meta:type_traits" ] } rtc_source_set("bounded_inline_vector") { @@ -398,6 +406,8 @@ rtc_library("stringutils") { ":macromagic", ":safe_minmax", "../api:array_view", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] @@ -433,8 +443,8 @@ rtc_library("rtc_task_queue") { "../api/task_queue", "system:rtc_export", "task_utils:to_queued_task", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_source_set("rtc_operations_chain") { @@ -469,6 +479,8 @@ if (rtc_enable_libevent) { ":safe_conversions", ":timeutils", "../api/task_queue", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/container:inlined_vector", "//third_party/abseil-cpp/absl/strings", ] @@ -490,8 +502,8 @@ if (is_mac || is_ios) { ":logging", "../api/task_queue", "system:gcd_helpers", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } } @@ -512,8 +524,8 @@ if (is_win) { ":safe_conversions", ":timeutils", "../api/task_queue", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } } @@ -532,8 +544,8 @@ rtc_library("rtc_task_queue_stdlib") { ":safe_conversions", ":timeutils", "../api/task_queue", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("weak_ptr") { @@ -576,6 +588,8 @@ rtc_library("rtc_numerics") { "../api/units:data_rate", "../api/units:time_delta", "../api/units:timestamp", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/types:optional", ] @@ -760,6 +774,7 @@ rtc_library("rtc_base") { deps = [ ":checks", ":deprecation", + ":rtc_task_queue", ":stringutils", "../api:array_view", "../api:function_view", @@ -767,12 +782,16 @@ rtc_library("rtc_base") { "../api/task_queue", "../system_wrappers:field_trial", "network:sent_packet", + "synchronization:sequence_checker", "system:file_wrapper", "system:inline", "system:rtc_export", + "task_utils:pending_task_safety_flag", "task_utils:to_queued_task", "third_party/base64", "third_party/sigslot", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", @@ -801,6 +820,8 @@ rtc_library("rtc_base") { "crypt_string.h", "data_rate_limiter.cc", "data_rate_limiter.h", + "deprecated/signal_thread.cc", + "deprecated/signal_thread.h", "dscp.h", "file_rotating_stream.cc", "file_rotating_stream.h", @@ -853,7 +874,6 @@ rtc_library("rtc_base") { "rtc_certificate.h", "rtc_certificate_generator.cc", "rtc_certificate_generator.h", - "signal_thread.cc", "signal_thread.h", "sigslot_repeater.h", "socket.cc", @@ -1000,8 +1020,8 @@ rtc_library("gunit_helpers") { ":rtc_base_tests_utils", ":stringutils", "../test:test_support", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } rtc_library("testclient") { @@ -1066,6 +1086,8 @@ rtc_library("rtc_base_tests_utils") { "../api/units:timestamp", "memory:fifo_buffer", "third_party/sigslot", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", ] @@ -1087,8 +1109,8 @@ rtc_library("task_queue_for_test") { "../api/task_queue", "../api/task_queue:default_task_queue_factory", "task_utils:to_queued_task", - "//third_party/abseil-cpp/absl/strings", ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } if (rtc_include_tests) { @@ -1128,8 +1150,8 @@ if (rtc_include_tests) { "../test:test_support", "third_party/sigslot", "//testing/gtest", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] if (is_win) { sources += [ "win32_socket_server_unittest.cc" ] } @@ -1211,6 +1233,8 @@ if (rtc_include_tests) { "task_utils:to_queued_task", "third_party/base64", "third_party/sigslot", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/memory", ] @@ -1228,8 +1252,8 @@ if (rtc_include_tests) { ":task_queue_for_test", "../test:test_main", "../test:test_support", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_library("rtc_operations_chain_unittests") { @@ -1279,8 +1303,8 @@ if (rtc_include_tests) { ":rtc_numerics", "../test:test_main", "../test:test_support", - "//third_party/abseil-cpp/absl/algorithm:container", ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ] } rtc_library("rtc_json_unittests") { @@ -1304,6 +1328,7 @@ if (rtc_include_tests) { "callback_unittest.cc", "crc32_unittest.cc", "data_rate_limiter_unittest.cc", + "deprecated/signal_thread_unittest.cc", "fake_clock_unittest.cc", "helpers_unittest.cc", "ip_address_unittest.cc", @@ -1316,7 +1341,6 @@ if (rtc_include_tests) { "rolling_accumulator_unittest.cc", "rtc_certificate_generator_unittest.cc", "rtc_certificate_unittest.cc", - "signal_thread_unittest.cc", "sigslot_tester_unittest.cc", "test_client_unittest.cc", "thread_unittest.cc", @@ -1356,6 +1380,8 @@ if (rtc_include_tests) { "synchronization:synchronization_unittests", "task_utils:to_queued_task", "third_party/sigslot", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", diff --git a/chromium/third_party/webrtc/rtc_base/DEPS b/chromium/third_party/webrtc/rtc_base/DEPS index 679d06dfc89..c9f7dc5898e 100644 --- a/chromium/third_party/webrtc/rtc_base/DEPS +++ b/chromium/third_party/webrtc/rtc_base/DEPS @@ -1,8 +1,8 @@ include_rules = [ "+base/third_party/libevent", "+json", - "+third_party/jsoncpp", "+system_wrappers", + "+third_party/jsoncpp", ] specific_include_rules = { diff --git a/chromium/third_party/webrtc/rtc_base/async_invoker.h b/chromium/third_party/webrtc/rtc_base/async_invoker.h index f15955d811f..82cdb21a30f 100644 --- a/chromium/third_party/webrtc/rtc_base/async_invoker.h +++ b/chromium/third_party/webrtc/rtc_base/async_invoker.h @@ -87,7 +87,7 @@ namespace rtc { // destruction. This can be done by starting each chain of invocations on the // same thread on which it will be destroyed, or by using some other // synchronization method. -class AsyncInvoker : public MessageHandler { +class AsyncInvoker : public MessageHandlerAutoCleanup { public: AsyncInvoker(); ~AsyncInvoker() override; diff --git a/chromium/third_party/webrtc/rtc_base/bit_buffer_unittest.cc b/chromium/third_party/webrtc/rtc_base/bit_buffer_unittest.cc index b3521b4951e..441cd264959 100644 --- a/chromium/third_party/webrtc/rtc_base/bit_buffer_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/bit_buffer_unittest.cc @@ -142,7 +142,7 @@ TEST(BitBufferTest, ReadBits) { EXPECT_FALSE(buffer.ReadBits(&val, 1)); } -TEST(BitBufferTest, SetOffsetValues) { +TEST(BitBufferDeathTest, SetOffsetValues) { uint8_t bytes[4] = {0}; BitBufferWriter buffer(bytes, 4); diff --git a/chromium/third_party/webrtc/rtc_base/buffer.h b/chromium/third_party/webrtc/rtc_base/buffer.h index 3048b9179f4..d1639e2f71b 100644 --- a/chromium/third_party/webrtc/rtc_base/buffer.h +++ b/chromium/third_party/webrtc/rtc_base/buffer.h @@ -370,7 +370,9 @@ class BufferT { : capacity; std::unique_ptr<T[]> new_data(new T[new_capacity]); - std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T)); + if (data_ != nullptr) { + std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T)); + } MaybeZeroCompleteBuffer(); data_ = std::move(new_data); capacity_ = new_capacity; diff --git a/chromium/third_party/webrtc/rtc_base/buffer_unittest.cc b/chromium/third_party/webrtc/rtc_base/buffer_unittest.cc index 3e7396dd2c8..8beae43cf94 100644 --- a/chromium/third_party/webrtc/rtc_base/buffer_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/buffer_unittest.cc @@ -447,7 +447,7 @@ TEST(BufferTest, TestStruct) { EXPECT_EQ(kObsidian, buf[2].stone); } -TEST(BufferTest, DieOnUseAfterMove) { +TEST(BufferDeathTest, DieOnUseAfterMove) { Buffer buf(17); Buffer buf2 = std::move(buf); EXPECT_EQ(buf2.size(), 17u); diff --git a/chromium/third_party/webrtc/rtc_base/checks.h b/chromium/third_party/webrtc/rtc_base/checks.h index 2fde3f6640b..61c074ac822 100644 --- a/chromium/third_party/webrtc/rtc_base/checks.h +++ b/chromium/third_party/webrtc/rtc_base/checks.h @@ -69,7 +69,7 @@ RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg); // the reason that it's better to terminate might simply be that the error // handling code isn't in place yet; in production, the reason might be that // the author of the code truly believes that x will always be true, but that -// she recognizes that if she is wrong, abrupt and unpleasant process +// they recognizes that if they are wrong, abrupt and unpleasant process // termination is still better than carrying on with the assumption violated. // // RTC_CHECK always evaluates its argument, so it's OK for x to have side diff --git a/chromium/third_party/webrtc/rtc_base/checks_unittest.cc b/chromium/third_party/webrtc/rtc_base/checks_unittest.cc index e6e094e5975..91e04cf6a1c 100644 --- a/chromium/third_party/webrtc/rtc_base/checks_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/checks_unittest.cc @@ -19,7 +19,7 @@ TEST(ChecksTest, ExpressionNotEvaluatedWhenCheckPassing) { } #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) -TEST(ChecksTest, Checks) { +TEST(ChecksDeathTest, Checks) { #if RTC_CHECK_MSG_ENABLED EXPECT_DEATH(FATAL() << "message", "\n\n#\n" diff --git a/chromium/third_party/webrtc/rtc_base/critical_section.cc b/chromium/third_party/webrtc/rtc_base/critical_section.cc index 1969edefa50..c6b17ff1b22 100644 --- a/chromium/third_party/webrtc/rtc_base/critical_section.cc +++ b/chromium/third_party/webrtc/rtc_base/critical_section.cc @@ -15,6 +15,7 @@ #include "rtc_base/atomic_ops.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" // TODO(tommi): Split this file up to per-platform implementation files. @@ -42,7 +43,7 @@ CriticalSection::CriticalSection() { pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); #if defined(WEBRTC_MAC) pthread_mutexattr_setpolicy_np(&mutex_attribute, - _PTHREAD_MUTEX_POLICY_FAIRSHARE); + _PTHREAD_MUTEX_POLICY_FIRSTFIT); #endif pthread_mutex_init(&mutex_, &mutex_attribute); pthread_mutexattr_destroy(&mutex_attribute); @@ -217,19 +218,8 @@ CritScope::~CritScope() { } void GlobalLock::Lock() { -#if !defined(WEBRTC_WIN) && \ - (!defined(WEBRTC_MAC) || RTC_USE_NATIVE_MUTEX_ON_MAC) - const struct timespec ts_null = {0}; -#endif - while (AtomicOps::CompareAndSwap(&lock_acquired_, 0, 1)) { -#if defined(WEBRTC_WIN) - ::Sleep(0); -#elif defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC - sched_yield(); -#else - nanosleep(&ts_null, nullptr); -#endif + webrtc::YieldCurrentThread(); } } diff --git a/chromium/third_party/webrtc/rtc_base/critical_section_unittest.cc b/chromium/third_party/webrtc/rtc_base/critical_section_unittest.cc index 16aefd27400..3fa48323762 100644 --- a/chromium/third_party/webrtc/rtc_base/critical_section_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/critical_section_unittest.cc @@ -78,7 +78,7 @@ class CompareAndSwapVerifier { int zero_count_; }; -class RunnerBase : public MessageHandler { +class RunnerBase : public MessageHandlerAutoCleanup { public: explicit RunnerBase(int value) : threads_active_(0), diff --git a/chromium/third_party/webrtc/rtc_base/signal_thread.cc b/chromium/third_party/webrtc/rtc_base/deprecated/signal_thread.cc index e100fbe179e..96bdd65155a 100644 --- a/chromium/third_party/webrtc/rtc_base/signal_thread.cc +++ b/chromium/third_party/webrtc/rtc_base/deprecated/signal_thread.cc @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "rtc_base/signal_thread.h" +#include "rtc_base/deprecated/signal_thread.h" #include <memory> @@ -23,26 +23,30 @@ namespace rtc { // SignalThread /////////////////////////////////////////////////////////////////////////////// -SignalThread::SignalThread() +DEPRECATED_SignalThread::DEPRECATED_SignalThread() : main_(Thread::Current()), worker_(this), state_(kInit), refcount_(1) { - main_->SignalQueueDestroyed.connect(this, - &SignalThread::OnMainThreadDestroyed); + main_->SignalQueueDestroyed.connect( + this, &DEPRECATED_SignalThread::OnMainThreadDestroyed); worker_.SetName("SignalThread", this); } -SignalThread::~SignalThread() { +DEPRECATED_SignalThread::~DEPRECATED_SignalThread() { + rtc::CritScope lock(&cs_); RTC_DCHECK(refcount_ == 0); } -bool SignalThread::SetName(const std::string& name, const void* obj) { +bool DEPRECATED_SignalThread::SetName(const std::string& name, + const void* obj) { EnterExit ee(this); + RTC_DCHECK(!destroy_called_); RTC_DCHECK(main_->IsCurrent()); RTC_DCHECK(kInit == state_); return worker_.SetName(name, obj); } -void SignalThread::Start() { +void DEPRECATED_SignalThread::Start() { EnterExit ee(this); + RTC_DCHECK(!destroy_called_); RTC_DCHECK(main_->IsCurrent()); if (kInit == state_ || kComplete == state_) { state_ = kRunning; @@ -53,9 +57,13 @@ void SignalThread::Start() { } } -void SignalThread::Destroy(bool wait) { +void DEPRECATED_SignalThread::Destroy(bool wait) { EnterExit ee(this); - RTC_DCHECK(main_->IsCurrent()); + // Sometimes the caller can't guarantee which thread will call Destroy, only + // that it will be the last thing it does. + // RTC_DCHECK(main_->IsCurrent()); + RTC_DCHECK(!destroy_called_); + destroy_called_ = true; if ((kInit == state_) || (kComplete == state_)) { refcount_--; } else if (kRunning == state_ || kReleasing == state_) { @@ -76,8 +84,9 @@ void SignalThread::Destroy(bool wait) { } } -void SignalThread::Release() { +void DEPRECATED_SignalThread::Release() { EnterExit ee(this); + RTC_DCHECK(!destroy_called_); RTC_DCHECK(main_->IsCurrent()); if (kComplete == state_) { refcount_--; @@ -89,13 +98,14 @@ void SignalThread::Release() { } } -bool SignalThread::ContinueWork() { +bool DEPRECATED_SignalThread::ContinueWork() { EnterExit ee(this); + RTC_DCHECK(!destroy_called_); RTC_DCHECK(worker_.IsCurrent()); return worker_.ProcessMessages(0); } -void SignalThread::OnMessage(Message* msg) { +void DEPRECATED_SignalThread::OnMessage(Message* msg) { EnterExit ee(this); if (ST_MSG_WORKER_DONE == msg->message_id) { RTC_DCHECK(main_->IsCurrent()); @@ -126,21 +136,21 @@ void SignalThread::OnMessage(Message* msg) { } } -SignalThread::Worker::Worker(SignalThread* parent) +DEPRECATED_SignalThread::Worker::Worker(DEPRECATED_SignalThread* parent) : Thread(std::make_unique<NullSocketServer>(), /*do_init=*/false), parent_(parent) { DoInit(); } -SignalThread::Worker::~Worker() { +DEPRECATED_SignalThread::Worker::~Worker() { Stop(); } -void SignalThread::Worker::Run() { +void DEPRECATED_SignalThread::Worker::Run() { parent_->Run(); } -void SignalThread::Run() { +void DEPRECATED_SignalThread::Run() { DoWork(); { EnterExit ee(this); @@ -150,12 +160,12 @@ void SignalThread::Run() { } } -void SignalThread::OnMainThreadDestroyed() { +void DEPRECATED_SignalThread::OnMainThreadDestroyed() { EnterExit ee(this); main_ = nullptr; } -bool SignalThread::Worker::IsProcessingMessagesForTesting() { +bool DEPRECATED_SignalThread::Worker::IsProcessingMessagesForTesting() { return false; } diff --git a/chromium/third_party/webrtc/rtc_base/deprecated/signal_thread.h b/chromium/third_party/webrtc/rtc_base/deprecated/signal_thread.h new file mode 100644 index 00000000000..e84d4ce5580 --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/deprecated/signal_thread.h @@ -0,0 +1,166 @@ +/* + * 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_SIGNAL_THREAD_H_ +#define RTC_BASE_DEPRECATED_SIGNAL_THREAD_H_ + +#include <string> + +#include "rtc_base/checks.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/critical_section.h" +#include "rtc_base/deprecation.h" +#include "rtc_base/message_handler.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread.h" +#include "rtc_base/thread_annotations.h" + +namespace rtc { + +/////////////////////////////////////////////////////////////////////////////// +// NOTE: this class has been deprecated. Do not use for new code. New code +// should use factilities exposed by api/task_queue/ instead. +// +// SignalThread - Base class for worker threads. The main thread should call +// Start() to begin work, and then follow one of these models: +// Normal: Wait for SignalWorkDone, and then call Release to destroy. +// Cancellation: Call Release(true), to abort the worker thread. +// Fire-and-forget: Call Release(false), which allows the thread to run to +// completion, and then self-destruct without further notification. +// Periodic tasks: Wait for SignalWorkDone, then eventually call Start() +// again to repeat the task. When the instance isn't needed anymore, +// call Release. DoWork, OnWorkStart and OnWorkStop are called again, +// on a new thread. +// The subclass should override DoWork() to perform the background task. By +// periodically calling ContinueWork(), it can check for cancellation. +// OnWorkStart and OnWorkDone can be overridden to do pre- or post-work +// tasks in the context of the main thread. +/////////////////////////////////////////////////////////////////////////////// + +class DEPRECATED_SignalThread : public sigslot::has_slots<>, + protected MessageHandlerAutoCleanup { + public: + DEPRECATED_SignalThread(); + + // Context: Main Thread. Call before Start to change the worker's name. + bool SetName(const std::string& name, const void* obj); + + // Context: Main Thread. Call to begin the worker thread. + void Start(); + + // Context: Main Thread. If the worker thread is not running, deletes the + // object immediately. Otherwise, asks the worker thread to abort processing, + // and schedules the object to be deleted once the worker exits. + // SignalWorkDone will not be signalled. If wait is true, does not return + // until the thread is deleted. + void Destroy(bool wait); + + // Context: Main Thread. If the worker thread is complete, deletes the + // object immediately. Otherwise, schedules the object to be deleted once + // the worker thread completes. SignalWorkDone will be signalled. + void Release(); + + // Context: Main Thread. Signalled when work is complete. + sigslot::signal1<DEPRECATED_SignalThread*> SignalWorkDone; + + enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE }; + + protected: + ~DEPRECATED_SignalThread() override; + + Thread* worker() { return &worker_; } + + // Context: Main Thread. Subclass should override to do pre-work setup. + virtual void OnWorkStart() {} + + // Context: Worker Thread. Subclass should override to do work. + virtual void DoWork() = 0; + + // Context: Worker Thread. Subclass should call periodically to + // dispatch messages and determine if the thread should terminate. + bool ContinueWork(); + + // Context: Worker Thread. Subclass should override when extra work is + // needed to abort the worker thread. + virtual void OnWorkStop() {} + + // Context: Main Thread. Subclass should override to do post-work cleanup. + virtual void OnWorkDone() {} + + // Context: Any Thread. If subclass overrides, be sure to call the base + // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) + void OnMessage(Message* msg) override; + + private: + enum State { + kInit, // Initialized, but not started + kRunning, // Started and doing work + kReleasing, // Same as running, but to be deleted when work is done + kComplete, // Work is done + kStopping, // Work is being interrupted + }; + + class Worker : public Thread { + public: + explicit Worker(DEPRECATED_SignalThread* parent); + ~Worker() override; + void Run() override; + bool IsProcessingMessagesForTesting() override; + + private: + DEPRECATED_SignalThread* parent_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Worker); + }; + + class RTC_SCOPED_LOCKABLE EnterExit { + public: + explicit EnterExit(DEPRECATED_SignalThread* t) + RTC_EXCLUSIVE_LOCK_FUNCTION(t->cs_) + : t_(t) { + t_->cs_.Enter(); + // If refcount_ is zero then the object has already been deleted and we + // will be double-deleting it in ~EnterExit()! (shouldn't happen) + RTC_DCHECK_NE(0, t_->refcount_); + ++t_->refcount_; + } + ~EnterExit() RTC_UNLOCK_FUNCTION() { + bool d = (0 == --t_->refcount_); + t_->cs_.Leave(); + if (d) + delete t_; + } + + private: + DEPRECATED_SignalThread* t_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EnterExit); + }; + + void Run(); + void OnMainThreadDestroyed(); + + Thread* main_; + Worker worker_; + CriticalSection cs_; + State state_ RTC_GUARDED_BY(cs_); + int refcount_ RTC_GUARDED_BY(cs_); + bool destroy_called_ RTC_GUARDED_BY(cs_) = false; + + RTC_DISALLOW_COPY_AND_ASSIGN(DEPRECATED_SignalThread); +}; + +typedef RTC_DEPRECATED DEPRECATED_SignalThread SignalThread; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace rtc + +#endif // RTC_BASE_DEPRECATED_SIGNAL_THREAD_H_ diff --git a/chromium/third_party/webrtc/rtc_base/signal_thread_unittest.cc b/chromium/third_party/webrtc/rtc_base/deprecated/signal_thread_unittest.cc index 14761865b8a..c280e970bef 100644 --- a/chromium/third_party/webrtc/rtc_base/signal_thread_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/deprecated/signal_thread_unittest.cc @@ -28,9 +28,9 @@ static const int kTimeout = 10000; class SignalThreadTest : public ::testing::Test, public sigslot::has_slots<> { public: - class SlowSignalThread : public SignalThread { + class SlowSignalThread : public DEPRECATED_SignalThread { public: - SlowSignalThread(SignalThreadTest* harness) : harness_(harness) {} + explicit SlowSignalThread(SignalThreadTest* harness) : harness_(harness) {} ~SlowSignalThread() override { EXPECT_EQ(harness_->main_thread_, Thread::Current()); @@ -70,7 +70,7 @@ class SignalThreadTest : public ::testing::Test, public sigslot::has_slots<> { RTC_DISALLOW_COPY_AND_ASSIGN(SlowSignalThread); }; - void OnWorkComplete(rtc::SignalThread* thread) { + void OnWorkComplete(rtc::DEPRECATED_SignalThread* thread) { SlowSignalThread* t = static_cast<SlowSignalThread*>(thread); EXPECT_EQ(t->harness(), this); EXPECT_EQ(main_thread_, Thread::Current()); @@ -157,7 +157,7 @@ class OwnerThread : public Thread, public sigslot::has_slots<> { rtc::CritScope cs(&crit_); return has_run_; } - void OnWorkDone(SignalThread* /*signal_thread*/) { + void OnWorkDone(DEPRECATED_SignalThread* /*signal_thread*/) { FAIL() << " This shouldn't get called."; } diff --git a/chromium/third_party/webrtc/rtc_base/experiments/BUILD.gn b/chromium/third_party/webrtc/rtc_base/experiments/BUILD.gn index bb3e0ce8ae5..282b5b92709 100644 --- a/chromium/third_party/webrtc/rtc_base/experiments/BUILD.gn +++ b/chromium/third_party/webrtc/rtc_base/experiments/BUILD.gn @@ -17,8 +17,8 @@ rtc_library("alr_experiment") { "../:rtc_base_approved", "../../api/transport:field_trial_based_config", "../../api/transport:webrtc_key_value_config", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("field_trial_parser") { @@ -40,6 +40,8 @@ rtc_library("field_trial_parser") { "../../rtc_base:logging", "../../rtc_base:safe_conversions", "../../rtc_base:stringutils", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings:strings", "//third_party/abseil-cpp/absl/types:optional", @@ -57,8 +59,8 @@ rtc_library("quality_rampup_experiment") { "../../api/transport:field_trial_based_config", "../../api/transport:webrtc_key_value_config", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("quality_scaler_settings") { @@ -72,8 +74,8 @@ rtc_library("quality_scaler_settings") { "../../api/transport:field_trial_based_config", "../../api/transport:webrtc_key_value_config", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("quality_scaling_experiment") { @@ -85,8 +87,8 @@ rtc_library("quality_scaling_experiment") { "../:rtc_base_approved", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("normalize_simulcast_size_experiment") { @@ -97,8 +99,8 @@ rtc_library("normalize_simulcast_size_experiment") { deps = [ "../:rtc_base_approved", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("balanced_degradation_settings") { @@ -111,8 +113,8 @@ rtc_library("balanced_degradation_settings") { "../:rtc_base_approved", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("cpu_speed_experiment") { @@ -123,8 +125,8 @@ rtc_library("cpu_speed_experiment") { deps = [ "../:rtc_base_approved", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("rtt_mult_experiment") { @@ -135,8 +137,8 @@ rtc_library("rtt_mult_experiment") { deps = [ "../:rtc_base_approved", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("jitter_upper_bound_experiment") { @@ -147,8 +149,8 @@ rtc_library("jitter_upper_bound_experiment") { deps = [ "../:rtc_base_approved", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("rate_control_settings") { @@ -164,6 +166,8 @@ rtc_library("rate_control_settings") { "../../api/units:data_size", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] @@ -178,8 +182,8 @@ rtc_library("keyframe_interval_settings_experiment") { ":field_trial_parser", "../../api/transport:field_trial_based_config", "../../api/transport:webrtc_key_value_config", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("stable_target_rate_experiment") { @@ -192,8 +196,8 @@ rtc_library("stable_target_rate_experiment") { ":rate_control_settings", "../../api/transport:field_trial_based_config", "../../api/transport:webrtc_key_value_config", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("min_video_bitrate_experiment") { @@ -208,8 +212,8 @@ rtc_library("min_video_bitrate_experiment") { "../../rtc_base:checks", "../../rtc_base:logging", "../../system_wrappers:field_trial", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } if (rtc_include_tests) { @@ -255,7 +259,7 @@ if (rtc_include_tests) { "../../test:field_trial", "../../test:test_main", "../../test:test_support", - "//third_party/abseil-cpp/absl/types:optional", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } diff --git a/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.cc b/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.cc index caf7e623683..ee6675c924d 100644 --- a/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.cc +++ b/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.cc @@ -70,4 +70,8 @@ bool QualityRampupExperiment::BwHigh(int64_t now_ms, return (now_ms - *start_ms_) >= min_duration_ms_.Value(); } +bool QualityRampupExperiment::Enabled() const { + return min_pixels_ || min_duration_ms_ || max_bitrate_kbps_; +} + } // namespace webrtc diff --git a/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.h b/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.h index ff9d7d38e52..9d469011040 100644 --- a/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.h +++ b/chromium/third_party/webrtc/rtc_base/experiments/quality_rampup_experiment.h @@ -33,6 +33,8 @@ class QualityRampupExperiment final { // (max_bitrate_factor_) above |max_bitrate_kbps_| for |min_duration_ms_|. bool BwHigh(int64_t now_ms, uint32_t available_bw_kbps); + bool Enabled() const; + private: explicit QualityRampupExperiment( const WebRtcKeyValueConfig* const key_value_config); diff --git a/chromium/third_party/webrtc/rtc_base/fake_network.h b/chromium/third_party/webrtc/rtc_base/fake_network.h index 040b24205ef..8bd50b69f0e 100644 --- a/chromium/third_party/webrtc/rtc_base/fake_network.h +++ b/chromium/third_party/webrtc/rtc_base/fake_network.h @@ -31,7 +31,8 @@ const int kFakeIPv4NetworkPrefixLength = 24; const int kFakeIPv6NetworkPrefixLength = 64; // Fake network manager that allows us to manually specify the IPs to use. -class FakeNetworkManager : public NetworkManagerBase, public MessageHandler { +class FakeNetworkManager : public NetworkManagerBase, + public MessageHandlerAutoCleanup { public: FakeNetworkManager() {} diff --git a/chromium/third_party/webrtc/rtc_base/logging.cc b/chromium/third_party/webrtc/rtc_base/logging.cc index ff7369dd5c4..bd2afcc9dd1 100644 --- a/chromium/third_party/webrtc/rtc_base/logging.cc +++ b/chromium/third_party/webrtc/rtc_base/logging.cc @@ -47,6 +47,7 @@ static const int kMaxLogLineSize = 1024 - 60; #include "rtc_base/string_encode.h" #include "rtc_base/string_utils.h" #include "rtc_base/strings/string_builder.h" +#include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" #include "rtc_base/time_utils.h" @@ -72,7 +73,9 @@ const char* FilenameFromPath(const char* file) { } // Global lock for log subsystem, only needed to serialize access to streams_. -CriticalSection g_log_crit; +// TODO(bugs.webrtc.org/11665): this is not currently constant initialized and +// trivially destructible. +webrtc::Mutex g_log_mutex_; } // namespace ///////////////////////////////////////////////////////////////////////////// @@ -85,7 +88,7 @@ bool LogMessage::log_to_stderr_ = true; // Note: we explicitly do not clean this up, because of the uncertain ordering // of destructors at program exit. Let the person who sets the stream trigger // cleanup by setting to null, or let it leak (safe at program exit). -ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_crit) = +ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_mutex_) = nullptr; // Boolean options default to false (0) @@ -193,7 +196,7 @@ LogMessage::~LogMessage() { #endif } - CritScope cs(&g_log_crit); + webrtc::MutexLock lock(&g_log_mutex_); for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { if (severity_ >= entry->min_severity_) { #if defined(WEBRTC_ANDROID) @@ -242,7 +245,7 @@ void LogMessage::LogTimestamps(bool on) { void LogMessage::LogToDebug(LoggingSeverity min_sev) { g_dbg_sev = min_sev; - CritScope cs(&g_log_crit); + webrtc::MutexLock lock(&g_log_mutex_); UpdateMinLogSeverity(); } @@ -251,7 +254,7 @@ void LogMessage::SetLogToStderr(bool log_to_stderr) { } int LogMessage::GetLogToStream(LogSink* stream) { - CritScope cs(&g_log_crit); + webrtc::MutexLock lock(&g_log_mutex_); LoggingSeverity sev = LS_NONE; for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { if (stream == nullptr || stream == entry) { @@ -262,7 +265,7 @@ int LogMessage::GetLogToStream(LogSink* stream) { } void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) { - CritScope cs(&g_log_crit); + webrtc::MutexLock lock(&g_log_mutex_); stream->min_severity_ = min_sev; stream->next_ = streams_; streams_ = stream; @@ -270,7 +273,7 @@ void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) { } void LogMessage::RemoveLogToStream(LogSink* stream) { - CritScope cs(&g_log_crit); + webrtc::MutexLock lock(&g_log_mutex_); for (LogSink** entry = &streams_; *entry != nullptr; entry = &(*entry)->next_) { if (*entry == stream) { @@ -331,7 +334,7 @@ void LogMessage::ConfigureLogging(const char* params) { } void LogMessage::UpdateMinLogSeverity() - RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) { + RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) { LoggingSeverity min_sev = g_dbg_sev; for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { min_sev = std::min(min_sev, entry->min_severity_); @@ -439,7 +442,7 @@ bool LogMessage::IsNoop(LoggingSeverity severity) { // TODO(tommi): We're grabbing this lock for every LogMessage instance that // is going to be logged. This introduces unnecessary synchronization for // a feature that's mostly used for testing. - CritScope cs(&g_log_crit); + webrtc::MutexLock lock(&g_log_mutex_); return streams_ == nullptr; } diff --git a/chromium/third_party/webrtc/rtc_base/message_handler.cc b/chromium/third_party/webrtc/rtc_base/message_handler.cc index 18a06e241d3..42b4c50b8a3 100644 --- a/chromium/third_party/webrtc/rtc_base/message_handler.cc +++ b/chromium/third_party/webrtc/rtc_base/message_handler.cc @@ -15,7 +15,18 @@ namespace rtc { MessageHandler::~MessageHandler() { - ThreadManager::Clear(this); + if (auto_cleanup_) { + // Note that even though this clears currently pending messages for the + // message handler, it's still racy since it doesn't prevent threads that + // might be in the process of posting new messages with would-be dangling + // pointers. + // This is related to the design of Message having a raw pointer. + // We could consider whether it would be safer to require message handlers + // to be reference counted (as some are). + ThreadManager::Clear(this); + } } +MessageHandlerAutoCleanup::~MessageHandlerAutoCleanup() {} + } // namespace rtc diff --git a/chromium/third_party/webrtc/rtc_base/message_handler.h b/chromium/third_party/webrtc/rtc_base/message_handler.h index 85cb7854851..7b6e682e297 100644 --- a/chromium/third_party/webrtc/rtc_base/message_handler.h +++ b/chromium/third_party/webrtc/rtc_base/message_handler.h @@ -21,17 +21,41 @@ namespace rtc { struct Message; -// Messages get dispatched to a MessageHandler +// MessageQueue/Thread Messages get dispatched to a MessageHandler via the +// |OnMessage()| callback method. +// +// Note: Besides being an interface, the class can perform automatic cleanup +// in the destructor. +// TODO(bugs.webrtc.org/11908): The |auto_cleanup| parameter and associated +// logic is a temporary step while changing the MessageHandler class to be +// a pure virtual interface. The automatic cleanup step involves a number of +// complex operations and as part of this interface, can easily go by unnoticed +// and bundled into situations where it's not needed. class RTC_EXPORT MessageHandler { public: virtual ~MessageHandler(); virtual void OnMessage(Message* msg) = 0; protected: - MessageHandler() {} + // TODO(bugs.webrtc.org/11908): The |auto_cleanup| parameter needs to have a + // backwards compatible default value while external code is being updated. + explicit MessageHandler(bool auto_cleanup = true) + : auto_cleanup_(auto_cleanup) {} private: RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandler); + const bool auto_cleanup_; +}; + +class RTC_EXPORT MessageHandlerAutoCleanup : public MessageHandler { + public: + ~MessageHandlerAutoCleanup() override; + + protected: + MessageHandlerAutoCleanup() : MessageHandler(true) {} + + private: + RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandlerAutoCleanup); }; } // namespace rtc diff --git a/chromium/third_party/webrtc/rtc_base/net_helpers.cc b/chromium/third_party/webrtc/rtc_base/net_helpers.cc index 6ff3791738b..c6685e2a65c 100644 --- a/chromium/third_party/webrtc/rtc_base/net_helpers.cc +++ b/chromium/third_party/webrtc/rtc_base/net_helpers.cc @@ -10,8 +10,6 @@ #include "rtc_base/net_helpers.h" -#include <memory> - #if defined(WEBRTC_WIN) #include <ws2spi.h> #include <ws2tcpip.h> @@ -26,8 +24,11 @@ #endif #endif // defined(WEBRTC_POSIX) && !defined(__native_client__) +#include "api/task_queue/task_queue_base.h" #include "rtc_base/logging.h" #include "rtc_base/signal_thread.h" +#include "rtc_base/task_queue.h" +#include "rtc_base/task_utils/to_queued_task.h" #include "rtc_base/third_party/sigslot/sigslot.h" // for signal_with_thread... namespace rtc { @@ -83,18 +84,35 @@ int ResolveHostname(const std::string& hostname, #endif // !__native_client__ } -// AsyncResolver -AsyncResolver::AsyncResolver() : SignalThread(), error_(-1) {} +AsyncResolver::AsyncResolver() : error_(-1) {} -AsyncResolver::~AsyncResolver() = default; +AsyncResolver::~AsyncResolver() { + RTC_DCHECK_RUN_ON(&sequence_checker_); +} void AsyncResolver::Start(const SocketAddress& addr) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); addr_ = addr; - // SignalThred Start will kickoff the resolve process. - SignalThread::Start(); + webrtc::TaskQueueBase* current_task_queue = webrtc::TaskQueueBase::Current(); + popup_thread_ = Thread::Create(); + popup_thread_->Start(); + popup_thread_->PostTask(webrtc::ToQueuedTask( + [this, flag = safety_.flag(), addr, current_task_queue] { + std::vector<IPAddress> addresses; + int error = + ResolveHostname(addr.hostname().c_str(), addr.family(), &addresses); + current_task_queue->PostTask(webrtc::ToQueuedTask( + std::move(flag), [this, error, addresses = std::move(addresses)] { + RTC_DCHECK_RUN_ON(&sequence_checker_); + ResolveDone(std::move(addresses), error); + })); + })); } bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); if (error_ != 0 || addresses_.empty()) return false; @@ -109,20 +127,40 @@ bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const { } int AsyncResolver::GetError() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); return error_; } void AsyncResolver::Destroy(bool wait) { - SignalThread::Destroy(wait); + // Some callers have trouble guaranteeing that Destroy is called on the + // sequence guarded by |sequence_checker_|. + // RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); + destroy_called_ = true; + MaybeSelfDestruct(); } -void AsyncResolver::DoWork() { - error_ = - ResolveHostname(addr_.hostname().c_str(), addr_.family(), &addresses_); +const std::vector<IPAddress>& AsyncResolver::addresses() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); + return addresses_; } -void AsyncResolver::OnWorkDone() { +void AsyncResolver::ResolveDone(std::vector<IPAddress> addresses, int error) { + addresses_ = addresses; + error_ = error; + recursion_check_ = true; SignalDone(this); + MaybeSelfDestruct(); +} + +void AsyncResolver::MaybeSelfDestruct() { + if (!recursion_check_) { + delete this; + } else { + recursion_check_ = false; + } } const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) { diff --git a/chromium/third_party/webrtc/rtc_base/net_helpers.h b/chromium/third_party/webrtc/rtc_base/net_helpers.h index 1e06940be74..c6aa4be5b20 100644 --- a/chromium/third_party/webrtc/rtc_base/net_helpers.h +++ b/chromium/third_party/webrtc/rtc_base/net_helpers.h @@ -21,16 +21,23 @@ #include "rtc_base/async_resolver_interface.h" #include "rtc_base/ip_address.h" -#include "rtc_base/signal_thread.h" #include "rtc_base/socket_address.h" +#include "rtc_base/synchronization/sequence_checker.h" #include "rtc_base/system/rtc_export.h" +#include "rtc_base/task_utils/pending_task_safety_flag.h" +#include "rtc_base/thread.h" +#include "rtc_base/thread_annotations.h" namespace rtc { // AsyncResolver will perform async DNS resolution, signaling the result on // the SignalDone from AsyncResolverInterface when the operation completes. -class RTC_EXPORT AsyncResolver : public SignalThread, - public AsyncResolverInterface { +// +// This class is thread-compatible, and all methods and destruction needs to +// happen from the same rtc::Thread, except for Destroy which is allowed to +// happen on another context provided it's not happening concurrently to another +// public API call, and is the last access to the object. +class RTC_EXPORT AsyncResolver : public AsyncResolverInterface { public: AsyncResolver(); ~AsyncResolver() override; @@ -40,17 +47,22 @@ class RTC_EXPORT AsyncResolver : public SignalThread, int GetError() const override; void Destroy(bool wait) override; - const std::vector<IPAddress>& addresses() const { return addresses_; } - void set_error(int error) { error_ = error; } - - protected: - void DoWork() override; - void OnWorkDone() override; + const std::vector<IPAddress>& addresses() const; private: - SocketAddress addr_; - std::vector<IPAddress> addresses_; - int error_; + void ResolveDone(std::vector<IPAddress> addresses, int error) + RTC_EXCLUSIVE_LOCKS_REQUIRED(sequence_checker_); + void MaybeSelfDestruct(); + + SocketAddress addr_ RTC_GUARDED_BY(sequence_checker_); + std::vector<IPAddress> addresses_ RTC_GUARDED_BY(sequence_checker_); + int error_ RTC_GUARDED_BY(sequence_checker_); + webrtc::ScopedTaskSafety safety_ RTC_GUARDED_BY(sequence_checker_); + std::unique_ptr<Thread> popup_thread_ RTC_GUARDED_BY(sequence_checker_); + bool recursion_check_ = + false; // Protects against SignalDone calling into Destroy. + bool destroy_called_ = false; + webrtc::SequenceChecker sequence_checker_; }; // rtc namespaced wrappers for inet_ntop and inet_pton so we can avoid diff --git a/chromium/third_party/webrtc/rtc_base/network.h b/chromium/third_party/webrtc/rtc_base/network.h index a67d2a23392..9cf04de590d 100644 --- a/chromium/third_party/webrtc/rtc_base/network.h +++ b/chromium/third_party/webrtc/rtc_base/network.h @@ -217,7 +217,7 @@ class RTC_EXPORT NetworkManagerBase : public NetworkManager { // Basic implementation of the NetworkManager interface that gets list // of networks using OS APIs. class RTC_EXPORT BasicNetworkManager : public NetworkManagerBase, - public MessageHandler, + public MessageHandlerAutoCleanup, public sigslot::has_slots<> { public: BasicNetworkManager(); diff --git a/chromium/third_party/webrtc/rtc_base/network/BUILD.gn b/chromium/third_party/webrtc/rtc_base/network/BUILD.gn index 1d06defb3bc..35ae3d45f73 100644 --- a/chromium/third_party/webrtc/rtc_base/network/BUILD.gn +++ b/chromium/third_party/webrtc/rtc_base/network/BUILD.gn @@ -13,8 +13,6 @@ rtc_library("sent_packet") { "sent_packet.cc", "sent_packet.h", ] - deps = [ - "../system:rtc_export", - "//third_party/abseil-cpp/absl/types:optional", - ] + deps = [ "../system:rtc_export" ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } diff --git a/chromium/third_party/webrtc/rtc_base/network_monitor.cc b/chromium/third_party/webrtc/rtc_base/network_monitor.cc index 4eb52901f3c..eb2bce9e2cc 100644 --- a/chromium/third_party/webrtc/rtc_base/network_monitor.cc +++ b/chromium/third_party/webrtc/rtc_base/network_monitor.cc @@ -30,8 +30,11 @@ NetworkMonitorInterface::NetworkMonitorInterface() {} NetworkMonitorInterface::~NetworkMonitorInterface() {} -NetworkMonitorBase::NetworkMonitorBase() : worker_thread_(Thread::Current()) {} -NetworkMonitorBase::~NetworkMonitorBase() {} +NetworkMonitorBase::NetworkMonitorBase() + : MessageHandler(false), worker_thread_(Thread::Current()) {} +NetworkMonitorBase::~NetworkMonitorBase() { + worker_thread_->Clear(this); +} void NetworkMonitorBase::OnNetworksChanged() { RTC_LOG(LS_VERBOSE) << "Network change is received at the network monitor"; diff --git a/chromium/third_party/webrtc/rtc_base/null_socket_server_unittest.cc b/chromium/third_party/webrtc/rtc_base/null_socket_server_unittest.cc index 39c16313b16..a875d6c2846 100644 --- a/chromium/third_party/webrtc/rtc_base/null_socket_server_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/null_socket_server_unittest.cc @@ -25,7 +25,8 @@ namespace rtc { static const uint32_t kTimeout = 5000U; -class NullSocketServerTest : public ::testing::Test, public MessageHandler { +class NullSocketServerTest : public ::testing::Test, + public MessageHandlerAutoCleanup { protected: void OnMessage(Message* message) override { ss_.WakeUp(); } diff --git a/chromium/third_party/webrtc/rtc_base/openssl_adapter.h b/chromium/third_party/webrtc/rtc_base/openssl_adapter.h index 0e76836bafa..6f1f7dccabd 100644 --- a/chromium/third_party/webrtc/rtc_base/openssl_adapter.h +++ b/chromium/third_party/webrtc/rtc_base/openssl_adapter.h @@ -32,7 +32,8 @@ namespace rtc { -class OpenSSLAdapter final : public SSLAdapter, public MessageHandler { +class OpenSSLAdapter final : public SSLAdapter, + public MessageHandlerAutoCleanup { public: static bool InitializeSSL(); static bool CleanupSSL(); diff --git a/chromium/third_party/webrtc/rtc_base/openssl_adapter_unittest.cc b/chromium/third_party/webrtc/rtc_base/openssl_adapter_unittest.cc index b161304d652..4bd87992d4d 100644 --- a/chromium/third_party/webrtc/rtc_base/openssl_adapter_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/openssl_adapter_unittest.cc @@ -25,28 +25,34 @@ namespace { class MockAsyncSocket : public AsyncSocket { public: virtual ~MockAsyncSocket() = default; - MOCK_METHOD1(Accept, AsyncSocket*(SocketAddress*)); - MOCK_CONST_METHOD0(GetLocalAddress, SocketAddress()); - MOCK_CONST_METHOD0(GetRemoteAddress, SocketAddress()); - MOCK_METHOD1(Bind, int(const SocketAddress&)); - MOCK_METHOD1(Connect, int(const SocketAddress&)); - MOCK_METHOD2(Send, int(const void*, size_t)); - MOCK_METHOD3(SendTo, int(const void*, size_t, const SocketAddress&)); - MOCK_METHOD3(Recv, int(void*, size_t, int64_t*)); - MOCK_METHOD4(RecvFrom, int(void*, size_t, SocketAddress*, int64_t*)); - MOCK_METHOD1(Listen, int(int)); - MOCK_METHOD0(Close, int()); - MOCK_CONST_METHOD0(GetError, int()); - MOCK_METHOD1(SetError, void(int)); - MOCK_CONST_METHOD0(GetState, ConnState()); - MOCK_METHOD2(GetOption, int(Option, int*)); - MOCK_METHOD2(SetOption, int(Option, int)); + MOCK_METHOD(AsyncSocket*, Accept, (SocketAddress*), (override)); + MOCK_METHOD(SocketAddress, GetLocalAddress, (), (const, override)); + MOCK_METHOD(SocketAddress, GetRemoteAddress, (), (const, override)); + MOCK_METHOD(int, Bind, (const SocketAddress&), (override)); + MOCK_METHOD(int, Connect, (const SocketAddress&), (override)); + MOCK_METHOD(int, Send, (const void*, size_t), (override)); + MOCK_METHOD(int, + SendTo, + (const void*, size_t, const SocketAddress&), + (override)); + MOCK_METHOD(int, Recv, (void*, size_t, int64_t*), (override)); + MOCK_METHOD(int, + RecvFrom, + (void*, size_t, SocketAddress*, int64_t*), + (override)); + MOCK_METHOD(int, Listen, (int), (override)); + MOCK_METHOD(int, Close, (), (override)); + MOCK_METHOD(int, GetError, (), (const, override)); + MOCK_METHOD(void, SetError, (int), (override)); + MOCK_METHOD(ConnState, GetState, (), (const, override)); + MOCK_METHOD(int, GetOption, (Option, int*), (override)); + MOCK_METHOD(int, SetOption, (Option, int), (override)); }; class MockCertVerifier : public SSLCertificateVerifier { public: virtual ~MockCertVerifier() = default; - MOCK_METHOD1(Verify, bool(const SSLCertificate&)); + MOCK_METHOD(bool, Verify, (const SSLCertificate&), (override)); }; } // namespace diff --git a/chromium/third_party/webrtc/rtc_base/operations_chain_unittest.cc b/chromium/third_party/webrtc/rtc_base/operations_chain_unittest.cc index 968f94c060c..ed3c924998a 100644 --- a/chromium/third_party/webrtc/rtc_base/operations_chain_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/operations_chain_unittest.cc @@ -369,14 +369,15 @@ TEST(OperationsChainTest, FunctorIsNotDestroyedWhileExecuting) { #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) -TEST(OperationsChainTest, OperationNotInvokingCallbackShouldCrash) { +TEST(OperationsChainDeathTest, OperationNotInvokingCallbackShouldCrash) { scoped_refptr<OperationsChain> operations_chain = OperationsChain::Create(); EXPECT_DEATH( operations_chain->ChainOperation([](std::function<void()> callback) {}), ""); } -TEST(OperationsChainTest, OperationInvokingCallbackMultipleTimesShouldCrash) { +TEST(OperationsChainDeathTest, + OperationInvokingCallbackMultipleTimesShouldCrash) { scoped_refptr<OperationsChain> operations_chain = OperationsChain::Create(); EXPECT_DEATH( operations_chain->ChainOperation([](std::function<void()> callback) { diff --git a/chromium/third_party/webrtc/rtc_base/physical_socket_server.cc b/chromium/third_party/webrtc/rtc_base/physical_socket_server.cc index cf65300b4ac..3a953316695 100644 --- a/chromium/third_party/webrtc/rtc_base/physical_socket_server.cc +++ b/chromium/third_party/webrtc/rtc_base/physical_socket_server.cc @@ -1365,12 +1365,6 @@ bool PhysicalSocketServer::WaitSelect(int cmsWait, bool process_io) { #if defined(WEBRTC_USE_EPOLL) -// Initial number of events to process with one call to "epoll_wait". -static const size_t kInitialEpollEvents = 128; - -// Maximum number of events to process with one call to "epoll_wait". -static const size_t kMaxEpollEvents = 8192; - void PhysicalSocketServer::AddEpoll(Dispatcher* pdispatcher) { RTC_DCHECK(epoll_fd_ != INVALID_SOCKET); int fd = pdispatcher->GetDescriptor(); @@ -1437,20 +1431,13 @@ bool PhysicalSocketServer::WaitEpoll(int cmsWait) { tvStop = TimeAfter(cmsWait); } - if (epoll_events_.empty()) { - // The initial space to receive events is created only if epoll is used. - epoll_events_.resize(kInitialEpollEvents); - } - fWait_ = true; - while (fWait_) { // Wait then call handlers as appropriate // < 0 means error // 0 means timeout // > 0 means count of descriptors ready - int n = epoll_wait(epoll_fd_, &epoll_events_[0], - static_cast<int>(epoll_events_.size()), + int n = epoll_wait(epoll_fd_, epoll_events_.data(), epoll_events_.size(), static_cast<int>(tvWait)); if (n < 0) { if (errno != EINTR) { @@ -1483,13 +1470,6 @@ bool PhysicalSocketServer::WaitEpoll(int cmsWait) { } } - if (static_cast<size_t>(n) == epoll_events_.size() && - epoll_events_.size() < kMaxEpollEvents) { - // We used the complete space to receive events, increase size for future - // iterations. - epoll_events_.resize(std::max(epoll_events_.size() * 2, kMaxEpollEvents)); - } - if (cmsWait != kForever) { tvWait = TimeDiff(tvStop, TimeMillis()); if (tvWait < 0) { diff --git a/chromium/third_party/webrtc/rtc_base/physical_socket_server.h b/chromium/third_party/webrtc/rtc_base/physical_socket_server.h index e7985db7db6..e21e53b8ecb 100644 --- a/chromium/third_party/webrtc/rtc_base/physical_socket_server.h +++ b/chromium/third_party/webrtc/rtc_base/physical_socket_server.h @@ -16,6 +16,7 @@ #define WEBRTC_USE_EPOLL 1 #endif +#include <array> #include <memory> #include <set> #include <vector> @@ -24,6 +25,7 @@ #include "rtc_base/net_helpers.h" #include "rtc_base/socket_server.h" #include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread_annotations.h" #if defined(WEBRTC_POSIX) typedef int SOCKET; @@ -80,9 +82,12 @@ class RTC_EXPORT PhysicalSocketServer : public SocketServer { void Update(Dispatcher* dispatcher); private: + // The number of events to process with one call to "epoll_wait". + static constexpr size_t kNumEpollEvents = 128; + typedef std::set<Dispatcher*> DispatcherSet; - void AddRemovePendingDispatchers(); + void AddRemovePendingDispatchers() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); #if defined(WEBRTC_POSIX) bool WaitSelect(int cms, bool process_io); @@ -94,14 +99,18 @@ class RTC_EXPORT PhysicalSocketServer : public SocketServer { bool WaitEpoll(int cms); bool WaitPoll(int cms, Dispatcher* dispatcher); + // This array is accessed in isolation by a thread calling into Wait(). + // It's useless to use a SequenceChecker to guard it because a socket + // server can outlive the thread it's bound to, forcing the Wait call + // to have to reset the sequence checker on Wait calls. + std::array<epoll_event, kNumEpollEvents> epoll_events_; const int epoll_fd_ = INVALID_SOCKET; - std::vector<struct epoll_event> epoll_events_; #endif // WEBRTC_USE_EPOLL - DispatcherSet dispatchers_; - DispatcherSet pending_add_dispatchers_; - DispatcherSet pending_remove_dispatchers_; - bool processing_dispatchers_ = false; - Signaler* signal_wakeup_; + DispatcherSet dispatchers_ RTC_GUARDED_BY(crit_); + DispatcherSet pending_add_dispatchers_ RTC_GUARDED_BY(crit_); + DispatcherSet pending_remove_dispatchers_ RTC_GUARDED_BY(crit_); + bool processing_dispatchers_ RTC_GUARDED_BY(crit_) = false; + Signaler* signal_wakeup_; // Assigned in constructor only CriticalSection crit_; #if defined(WEBRTC_WIN) const WSAEVENT socket_ev_; diff --git a/chromium/third_party/webrtc/rtc_base/platform_thread_types.cc b/chromium/third_party/webrtc/rtc_base/platform_thread_types.cc index ed4a2282624..b0243b41dc8 100644 --- a/chromium/third_party/webrtc/rtc_base/platform_thread_types.cc +++ b/chromium/third_party/webrtc/rtc_base/platform_thread_types.cc @@ -15,6 +15,16 @@ #include <sys/syscall.h> #endif +#if defined(WEBRTC_WIN) +#include "rtc_base/arraysize.h" + +// The SetThreadDescription API was brought in version 1607 of Windows 10. +// For compatibility with various versions of winuser and avoid clashing with +// a potentially defined type, we use the RTC_ prefix. +typedef HRESULT(WINAPI* RTC_SetThreadDescription)(HANDLE hThread, + PCWSTR lpThreadDescription); +#endif + namespace rtc { PlatformThreadId CurrentThreadId() { @@ -58,6 +68,24 @@ bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) { void SetCurrentThreadName(const char* name) { #if defined(WEBRTC_WIN) + // The SetThreadDescription API works even if no debugger is attached. + // The names set with this API also show up in ETW traces. Very handy. + static auto set_thread_description_func = + reinterpret_cast<RTC_SetThreadDescription>(::GetProcAddress( + ::GetModuleHandleA("Kernel32.dll"), "SetThreadDescription")); + if (set_thread_description_func) { + // Convert from ASCII to UTF-16. + wchar_t wide_thread_name[64]; + for (size_t i = 0; i < arraysize(wide_thread_name) - 1; ++i) { + wide_thread_name[i] = name[i]; + if (wide_thread_name[i] == L'\0') + break; + } + // Guarantee null-termination. + wide_thread_name[arraysize(wide_thread_name) - 1] = L'\0'; + set_thread_description_func(::GetCurrentThread(), wide_thread_name); + } + // For details see: // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code #pragma pack(push, 8) diff --git a/chromium/third_party/webrtc/rtc_base/rate_statistics.cc b/chromium/third_party/webrtc/rtc_base/rate_statistics.cc index c4c2e78581b..85621fa5555 100644 --- a/chromium/third_party/webrtc/rtc_base/rate_statistics.cc +++ b/chromium/third_party/webrtc/rtc_base/rate_statistics.cc @@ -20,29 +20,26 @@ namespace webrtc { +RateStatistics::Bucket::Bucket(int64_t timestamp) + : sum(0), num_samples(0), timestamp(timestamp) {} + RateStatistics::RateStatistics(int64_t window_size_ms, float scale) - : buckets_(new Bucket[window_size_ms]()), - accumulated_count_(0), + : accumulated_count_(0), + first_timestamp_(-1), num_samples_(0), - oldest_time_(-window_size_ms), - oldest_index_(0), scale_(scale), max_window_size_ms_(window_size_ms), current_window_size_ms_(max_window_size_ms_) {} RateStatistics::RateStatistics(const RateStatistics& other) - : accumulated_count_(other.accumulated_count_), + : buckets_(other.buckets_), + accumulated_count_(other.accumulated_count_), + first_timestamp_(other.first_timestamp_), overflow_(other.overflow_), num_samples_(other.num_samples_), - oldest_time_(other.oldest_time_), - oldest_index_(other.oldest_index_), scale_(other.scale_), max_window_size_ms_(other.max_window_size_ms_), - current_window_size_ms_(other.current_window_size_ms_) { - buckets_ = std::make_unique<Bucket[]>(other.max_window_size_ms_); - std::copy(other.buckets_.get(), - other.buckets_.get() + other.max_window_size_ms_, buckets_.get()); -} + current_window_size_ms_(other.current_window_size_ms_) {} RateStatistics::RateStatistics(RateStatistics&& other) = default; @@ -52,33 +49,33 @@ void RateStatistics::Reset() { accumulated_count_ = 0; overflow_ = false; num_samples_ = 0; - oldest_time_ = -max_window_size_ms_; - oldest_index_ = 0; + first_timestamp_ = -1; current_window_size_ms_ = max_window_size_ms_; - for (int64_t i = 0; i < max_window_size_ms_; i++) - buckets_[i] = Bucket(); + buckets_.clear(); } void RateStatistics::Update(int64_t count, int64_t now_ms) { - RTC_DCHECK_LE(0, count); - if (now_ms < oldest_time_) { - // Too old data is ignored. - return; - } + RTC_DCHECK_GE(count, 0); EraseOld(now_ms); + if (first_timestamp_ == -1) { + first_timestamp_ = now_ms; + } + + if (buckets_.empty() || now_ms != buckets_.back().timestamp) { + if (!buckets_.empty() && now_ms < buckets_.back().timestamp) { + RTC_LOG(LS_WARNING) << "Timestamp " << now_ms + << " is before the last added " + "timestamp in the rate window: " + << buckets_.back().timestamp << ", aligning to that."; + now_ms = buckets_.back().timestamp; + } + buckets_.emplace_back(now_ms); + } + Bucket& last_bucket = buckets_.back(); + last_bucket.sum += count; + ++last_bucket.num_samples; - // First ever sample, reset window to start now. - if (!IsInitialized()) - oldest_time_ = now_ms; - - uint32_t now_offset = rtc::dchecked_cast<uint32_t>(now_ms - oldest_time_); - RTC_DCHECK_LT(now_offset, max_window_size_ms_); - uint32_t index = oldest_index_ + now_offset; - if (index >= max_window_size_ms_) - index -= max_window_size_ms_; - buckets_[index].sum += count; - ++buckets_[index].samples; if (std::numeric_limits<int64_t>::max() - accumulated_count_ > count) { accumulated_count_ += count; } else { @@ -92,10 +89,22 @@ absl::optional<int64_t> RateStatistics::Rate(int64_t now_ms) const { // of the members as mutable... const_cast<RateStatistics*>(this)->EraseOld(now_ms); + int active_window_size = 0; + if (first_timestamp_ != -1) { + if (first_timestamp_ <= now_ms - current_window_size_ms_) { + // Count window as full even if no data points currently in view, if the + // data stream started before the window. + active_window_size = current_window_size_ms_; + } else { + // Size of a single bucket is 1ms, so even if now_ms == first_timestmap_ + // the window size should be 1. + active_window_size = now_ms - first_timestamp_ + 1; + } + } + // If window is a single bucket or there is only one sample in a data set that // has not grown to the full window size, or if the accumulator has // overflowed, treat this as rate unavailable. - int active_window_size = now_ms - oldest_time_ + 1; if (num_samples_ == 0 || active_window_size <= 1 || (num_samples_ <= 1 && rtc::SafeLt(active_window_size, current_window_size_ms_)) || @@ -114,43 +123,35 @@ absl::optional<int64_t> RateStatistics::Rate(int64_t now_ms) const { } void RateStatistics::EraseOld(int64_t now_ms) { - if (!IsInitialized()) - return; - // New oldest time that is included in data set. - int64_t new_oldest_time = now_ms - current_window_size_ms_ + 1; - - // New oldest time is older than the current one, no need to cull data. - if (new_oldest_time <= oldest_time_) - return; + const int64_t new_oldest_time = now_ms - current_window_size_ms_ + 1; // Loop over buckets and remove too old data points. - while (num_samples_ > 0 && oldest_time_ < new_oldest_time) { - const Bucket& oldest_bucket = buckets_[oldest_index_]; + while (!buckets_.empty() && buckets_.front().timestamp < new_oldest_time) { + const Bucket& oldest_bucket = buckets_.front(); RTC_DCHECK_GE(accumulated_count_, oldest_bucket.sum); - RTC_DCHECK_GE(num_samples_, oldest_bucket.samples); + RTC_DCHECK_GE(num_samples_, oldest_bucket.num_samples); accumulated_count_ -= oldest_bucket.sum; - num_samples_ -= oldest_bucket.samples; - buckets_[oldest_index_] = Bucket(); - if (++oldest_index_ >= max_window_size_ms_) - oldest_index_ = 0; - ++oldest_time_; + num_samples_ -= oldest_bucket.num_samples; + buckets_.pop_front(); // This does not clear overflow_ even when counter is empty. // TODO(https://bugs.webrtc.org/11247): Consider if overflow_ can be reset. } - oldest_time_ = new_oldest_time; } bool RateStatistics::SetWindowSize(int64_t window_size_ms, int64_t now_ms) { if (window_size_ms <= 0 || window_size_ms > max_window_size_ms_) return false; + if (first_timestamp_ != -1) { + // If the window changes (e.g. decreases - removing data point, then + // increases again) we need to update the first timestamp mark as + // otherwise it indicates the window coveres a region of zeros, suddenly + // under-estimating the rate. + first_timestamp_ = std::max(first_timestamp_, now_ms - window_size_ms + 1); + } current_window_size_ms_ = window_size_ms; EraseOld(now_ms); return true; } -bool RateStatistics::IsInitialized() const { - return oldest_time_ != -max_window_size_ms_; -} - } // namespace webrtc diff --git a/chromium/third_party/webrtc/rtc_base/rate_statistics.h b/chromium/third_party/webrtc/rtc_base/rate_statistics.h index 11c8cee7af2..dc8d7f5272a 100644 --- a/chromium/third_party/webrtc/rtc_base/rate_statistics.h +++ b/chromium/third_party/webrtc/rtc_base/rate_statistics.h @@ -14,6 +14,7 @@ #include <stddef.h> #include <stdint.h> +#include <deque> #include <memory> #include "absl/types/optional.h" @@ -28,6 +29,10 @@ namespace webrtc { // high; for instance, a 20 Mbit/sec video stream can wrap a 32-bit byte // counter in 14 minutes. +// Note that timestamps used in Update(), Rate() and SetWindowSize() must never +// decrease for two consecutive calls. +// TODO(bugs.webrtc.org/11600): Migrate from int64_t to Timestamp. + class RTC_EXPORT RateStatistics { public: static constexpr float kBpsScale = 8000.0f; @@ -65,19 +70,22 @@ class RTC_EXPORT RateStatistics { private: void EraseOld(int64_t now_ms); - bool IsInitialized() const; - // Counters are kept in buckets (circular buffer), with one bucket - // per millisecond. struct Bucket { + explicit Bucket(int64_t timestamp); int64_t sum; // Sum of all samples in this bucket. - int samples; // Number of samples in this bucket. + int num_samples; // Number of samples in this bucket. + const int64_t timestamp; // Timestamp this bucket corresponds to. }; - std::unique_ptr<Bucket[]> buckets_; + // All buckets within the time window, ordered by time. + std::deque<Bucket> buckets_; - // Total count recorded in buckets. + // Total count recorded in all buckets. int64_t accumulated_count_; + // Timestamp of the first data point seen, or -1 of none seen. + int64_t first_timestamp_; + // True if accumulated_count_ has ever grown too large to be // contained in its integer type. bool overflow_ = false; @@ -85,12 +93,6 @@ class RTC_EXPORT RateStatistics { // The total number of samples in the buckets. int num_samples_; - // Oldest time recorded in buckets. - int64_t oldest_time_; - - // Bucket index of oldest counter recorded in buckets. - int64_t oldest_index_; - // To convert counts/ms to desired units const float scale_; diff --git a/chromium/third_party/webrtc/rtc_base/rtc_certificate_generator.cc b/chromium/third_party/webrtc/rtc_base/rtc_certificate_generator.cc index 4c9d378dd2f..72f4277fa0c 100644 --- a/chromium/third_party/webrtc/rtc_base/rtc_certificate_generator.cc +++ b/chromium/third_party/webrtc/rtc_base/rtc_certificate_generator.cc @@ -40,7 +40,7 @@ enum { // request. We are using a separate helper class so that a generation request // can outlive the |RTCCertificateGenerator| that spawned it. class RTCCertificateGenerationTask : public RefCountInterface, - public MessageHandler { + public MessageHandlerAutoCleanup { public: RTCCertificateGenerationTask( Thread* signaling_thread, diff --git a/chromium/third_party/webrtc/rtc_base/signal_thread.h b/chromium/third_party/webrtc/rtc_base/signal_thread.h index d9e8ade9b0e..b444d549949 100644 --- a/chromium/third_party/webrtc/rtc_base/signal_thread.h +++ b/chromium/third_party/webrtc/rtc_base/signal_thread.h @@ -1,5 +1,5 @@ /* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. + * Copyright 2020 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 @@ -11,147 +11,9 @@ #ifndef RTC_BASE_SIGNAL_THREAD_H_ #define RTC_BASE_SIGNAL_THREAD_H_ -#include <string> - -#include "rtc_base/checks.h" -#include "rtc_base/constructor_magic.h" -#include "rtc_base/critical_section.h" -#include "rtc_base/message_handler.h" -#include "rtc_base/third_party/sigslot/sigslot.h" -#include "rtc_base/thread.h" -#include "rtc_base/thread_annotations.h" - -namespace rtc { - -/////////////////////////////////////////////////////////////////////////////// -// SignalThread - Base class for worker threads. The main thread should call -// Start() to begin work, and then follow one of these models: -// Normal: Wait for SignalWorkDone, and then call Release to destroy. -// Cancellation: Call Release(true), to abort the worker thread. -// Fire-and-forget: Call Release(false), which allows the thread to run to -// completion, and then self-destruct without further notification. -// Periodic tasks: Wait for SignalWorkDone, then eventually call Start() -// again to repeat the task. When the instance isn't needed anymore, -// call Release. DoWork, OnWorkStart and OnWorkStop are called again, -// on a new thread. -// The subclass should override DoWork() to perform the background task. By -// periodically calling ContinueWork(), it can check for cancellation. -// OnWorkStart and OnWorkDone can be overridden to do pre- or post-work -// tasks in the context of the main thread. -/////////////////////////////////////////////////////////////////////////////// - -class SignalThread : public sigslot::has_slots<>, protected MessageHandler { - public: - SignalThread(); - - // Context: Main Thread. Call before Start to change the worker's name. - bool SetName(const std::string& name, const void* obj); - - // Context: Main Thread. Call to begin the worker thread. - void Start(); - - // Context: Main Thread. If the worker thread is not running, deletes the - // object immediately. Otherwise, asks the worker thread to abort processing, - // and schedules the object to be deleted once the worker exits. - // SignalWorkDone will not be signalled. If wait is true, does not return - // until the thread is deleted. - void Destroy(bool wait); - - // Context: Main Thread. If the worker thread is complete, deletes the - // object immediately. Otherwise, schedules the object to be deleted once - // the worker thread completes. SignalWorkDone will be signalled. - void Release(); - - // Context: Main Thread. Signalled when work is complete. - sigslot::signal1<SignalThread*> SignalWorkDone; - - enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE }; - - protected: - ~SignalThread() override; - - Thread* worker() { return &worker_; } - - // Context: Main Thread. Subclass should override to do pre-work setup. - virtual void OnWorkStart() {} - - // Context: Worker Thread. Subclass should override to do work. - virtual void DoWork() = 0; - - // Context: Worker Thread. Subclass should call periodically to - // dispatch messages and determine if the thread should terminate. - bool ContinueWork(); - - // Context: Worker Thread. Subclass should override when extra work is - // needed to abort the worker thread. - virtual void OnWorkStop() {} - - // Context: Main Thread. Subclass should override to do post-work cleanup. - virtual void OnWorkDone() {} - - // Context: Any Thread. If subclass overrides, be sure to call the base - // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) - void OnMessage(Message* msg) override; - - private: - enum State { - kInit, // Initialized, but not started - kRunning, // Started and doing work - kReleasing, // Same as running, but to be deleted when work is done - kComplete, // Work is done - kStopping, // Work is being interrupted - }; - - class Worker : public Thread { - public: - explicit Worker(SignalThread* parent); - ~Worker() override; - void Run() override; - bool IsProcessingMessagesForTesting() override; - - private: - SignalThread* parent_; - - RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Worker); - }; - - class RTC_SCOPED_LOCKABLE EnterExit { - public: - explicit EnterExit(SignalThread* t) RTC_EXCLUSIVE_LOCK_FUNCTION(t->cs_) - : t_(t) { - t_->cs_.Enter(); - // If refcount_ is zero then the object has already been deleted and we - // will be double-deleting it in ~EnterExit()! (shouldn't happen) - RTC_DCHECK_NE(0, t_->refcount_); - ++t_->refcount_; - } - ~EnterExit() RTC_UNLOCK_FUNCTION() { - bool d = (0 == --t_->refcount_); - t_->cs_.Leave(); - if (d) - delete t_; - } - - private: - SignalThread* t_; - - RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EnterExit); - }; - - void Run(); - void OnMainThreadDestroyed(); - - Thread* main_; - Worker worker_; - CriticalSection cs_; - State state_; - int refcount_; - - RTC_DISALLOW_COPY_AND_ASSIGN(SignalThread); -}; - -/////////////////////////////////////////////////////////////////////////////// - -} // namespace rtc +// The facilities in this file have been deprecated. Please do not use them +// in new code. New code should use factilities exposed by api/task_queue/ +// instead. +#include "rtc_base/deprecated/signal_thread.h" #endif // RTC_BASE_SIGNAL_THREAD_H_ diff --git a/chromium/third_party/webrtc/rtc_base/socket_unittest.cc b/chromium/third_party/webrtc/rtc_base/socket_unittest.cc index 6ea4b47bd1d..04024fb184b 100644 --- a/chromium/third_party/webrtc/rtc_base/socket_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/socket_unittest.cc @@ -651,7 +651,7 @@ void SocketTest::CloseInClosedCallbackInternal(const IPAddress& loopback) { EXPECT_TRUE(Socket::CS_CLOSED == client->GetState()); } -class Sleeper : public MessageHandler { +class Sleeper : public MessageHandlerAutoCleanup { public: void OnMessage(Message* msg) override { Thread::Current()->SleepMs(500); } }; diff --git a/chromium/third_party/webrtc/rtc_base/ssl_adapter_unittest.cc b/chromium/third_party/webrtc/rtc_base/ssl_adapter_unittest.cc index 125b4bd50d0..498eba312bc 100644 --- a/chromium/third_party/webrtc/rtc_base/ssl_adapter_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/ssl_adapter_unittest.cc @@ -50,7 +50,7 @@ static std::string GetSSLProtocolName(const rtc::SSLMode& ssl_mode) { class MockCertVerifier : public rtc::SSLCertificateVerifier { public: virtual ~MockCertVerifier() = default; - MOCK_METHOD1(Verify, bool(const rtc::SSLCertificate&)); + MOCK_METHOD(bool, Verify, (const rtc::SSLCertificate&), (override)); }; // TODO(benwright) - Move to using INSTANTIATE_TEST_SUITE_P instead of using diff --git a/chromium/third_party/webrtc/rtc_base/stream.h b/chromium/third_party/webrtc/rtc_base/stream.h index bfb9dc2c41e..036c5ad8c74 100644 --- a/chromium/third_party/webrtc/rtc_base/stream.h +++ b/chromium/third_party/webrtc/rtc_base/stream.h @@ -54,7 +54,7 @@ struct StreamEventData : public MessageData { StreamEventData(int ev, int er) : events(ev), error(er) {} }; -class RTC_EXPORT StreamInterface : public MessageHandler { +class RTC_EXPORT StreamInterface : public MessageHandlerAutoCleanup { public: enum { MSG_POST_EVENT = 0xF1F1, MSG_MAX = MSG_POST_EVENT }; diff --git a/chromium/third_party/webrtc/rtc_base/strings/string_builder_unittest.cc b/chromium/third_party/webrtc/rtc_base/strings/string_builder_unittest.cc index 84717ad1d10..99dfd862923 100644 --- a/chromium/third_party/webrtc/rtc_base/strings/string_builder_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/strings/string_builder_unittest.cc @@ -59,7 +59,7 @@ TEST(SimpleStringBuilder, StdString) { // off. #if (GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)) || !RTC_DCHECK_IS_ON -TEST(SimpleStringBuilder, BufferOverrunConstCharP) { +TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharP) { char sb_buf[4]; SimpleStringBuilder sb(sb_buf); const char* const msg = "This is just too much"; @@ -71,7 +71,7 @@ TEST(SimpleStringBuilder, BufferOverrunConstCharP) { #endif } -TEST(SimpleStringBuilder, BufferOverrunStdString) { +TEST(SimpleStringBuilderDeathTest, BufferOverrunStdString) { char sb_buf[4]; SimpleStringBuilder sb(sb_buf); sb << 12; @@ -84,7 +84,7 @@ TEST(SimpleStringBuilder, BufferOverrunStdString) { #endif } -TEST(SimpleStringBuilder, BufferOverrunInt) { +TEST(SimpleStringBuilderDeathTest, BufferOverrunInt) { char sb_buf[4]; SimpleStringBuilder sb(sb_buf); constexpr int num = -12345; @@ -100,7 +100,7 @@ TEST(SimpleStringBuilder, BufferOverrunInt) { #endif } -TEST(SimpleStringBuilder, BufferOverrunDouble) { +TEST(SimpleStringBuilderDeathTest, BufferOverrunDouble) { char sb_buf[5]; SimpleStringBuilder sb(sb_buf); constexpr double num = 123.456; @@ -113,7 +113,7 @@ TEST(SimpleStringBuilder, BufferOverrunDouble) { #endif } -TEST(SimpleStringBuilder, BufferOverrunConstCharPAlreadyFull) { +TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharPAlreadyFull) { char sb_buf[4]; SimpleStringBuilder sb(sb_buf); sb << 123; @@ -126,7 +126,7 @@ TEST(SimpleStringBuilder, BufferOverrunConstCharPAlreadyFull) { #endif } -TEST(SimpleStringBuilder, BufferOverrunIntAlreadyFull) { +TEST(SimpleStringBuilderDeathTest, BufferOverrunIntAlreadyFull) { char sb_buf[4]; SimpleStringBuilder sb(sb_buf); sb << "xyz"; diff --git a/chromium/third_party/webrtc/rtc_base/swap_queue_unittest.cc b/chromium/third_party/webrtc/rtc_base/swap_queue_unittest.cc index 199ac6b1854..3862d850fa4 100644 --- a/chromium/third_party/webrtc/rtc_base/swap_queue_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/swap_queue_unittest.cc @@ -135,7 +135,7 @@ TEST(SwapQueueTest, SuccessfulItemVerifyFunctor) { } #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) -TEST(SwapQueueTest, UnsuccessfulItemVerifyFunctor) { +TEST(SwapQueueDeathTest, UnsuccessfulItemVerifyFunctor) { // Queue item verifier for the test. auto minus_2_verifier = [](const int& i) { return i > -2; }; SwapQueue<int, decltype(minus_2_verifier)> queue(2, minus_2_verifier); @@ -148,7 +148,7 @@ TEST(SwapQueueTest, UnsuccessfulItemVerifyFunctor) { EXPECT_DEATH(result = queue.Insert(&invalid_value), ""); } -TEST(SwapQueueTest, UnSuccessfulItemVerifyInsert) { +TEST(SwapQueueDeathTest, UnSuccessfulItemVerifyInsert) { std::vector<int> template_element(kChunkSize); SwapQueue<std::vector<int>, SwapQueueItemVerifier<std::vector<int>, &LengthVerifierFunction>> @@ -158,7 +158,7 @@ TEST(SwapQueueTest, UnSuccessfulItemVerifyInsert) { EXPECT_DEATH(result = queue.Insert(&invalid_chunk), ""); } -TEST(SwapQueueTest, UnSuccessfulItemVerifyRemove) { +TEST(SwapQueueDeathTest, UnSuccessfulItemVerifyRemove) { std::vector<int> template_element(kChunkSize); SwapQueue<std::vector<int>, SwapQueueItemVerifier<std::vector<int>, &LengthVerifierFunction>> diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/BUILD.gn b/chromium/third_party/webrtc/rtc_base/synchronization/BUILD.gn index 3e7b22d4f93..f6e6d0bfaaf 100644 --- a/chromium/third_party/webrtc/rtc_base/synchronization/BUILD.gn +++ b/chromium/third_party/webrtc/rtc_base/synchronization/BUILD.gn @@ -12,6 +12,38 @@ if (is_android) { import("//build/config/android/rules.gni") } +rtc_library("yield") { + sources = [ + "yield.cc", + "yield.h", + ] + deps = [] +} + +rtc_library("mutex") { + sources = [ + "mutex.cc", + "mutex.h", + "mutex_critical_section.h", + "mutex_pthread.h", + ] + if (rtc_use_absl_mutex) { + sources += [ "mutex_abseil.h" ] + } + + deps = [ + ":yield", + "..:checks", + "..:macromagic", + "..:platform_thread_types", + "../system:unused", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] + if (rtc_use_absl_mutex) { + absl_deps += [ "//third_party/abseil-cpp/absl/synchronization" ] + } +} + rtc_library("rw_lock_wrapper") { public = [ "rw_lock_wrapper.h" ] sources = [ "rw_lock_wrapper.cc" ] @@ -40,6 +72,7 @@ rtc_library("sequence_checker") { "..:criticalsection", "..:macromagic", "..:platform_thread_types", + "..:stringutils", "../../api/task_queue", "../system:rtc_export", ] @@ -50,8 +83,8 @@ rtc_library("yield_policy") { "yield_policy.cc", "yield_policy.h", ] - deps = [ - "..:checks", + deps = [ "..:checks" ] + absl_deps = [ "//third_party/abseil-cpp/absl/base:config", "//third_party/abseil-cpp/absl/base:core_headers", ] @@ -60,11 +93,30 @@ rtc_library("yield_policy") { if (rtc_include_tests) { rtc_library("synchronization_unittests") { testonly = true - sources = [ "yield_policy_unittest.cc" ] + sources = [ + "mutex_unittest.cc", + "yield_policy_unittest.cc", + ] deps = [ + ":mutex", + ":yield", ":yield_policy", + "..:checks", + "..:macromagic", + "..:rtc_base", "..:rtc_event", "../../test:test_support", + "//third_party/google_benchmark", + ] + } + + rtc_library("mutex_benchmark") { + testonly = true + sources = [ "mutex_benchmark.cc" ] + deps = [ + ":mutex", + "../system:unused", + "//third_party/google_benchmark", ] } diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/DEPS b/chromium/third_party/webrtc/rtc_base/synchronization/DEPS new file mode 100644 index 00000000000..4ed1f2444bc --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/DEPS @@ -0,0 +1,11 @@ +specific_include_rules = { + "mutex_abseil\.h": [ + "+absl/synchronization" + ], + ".*_benchmark\.cc": [ + "+benchmark", + ], + ".*_unittest\.cc": [ + "+benchmark", + ] +} diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/mutex.cc b/chromium/third_party/webrtc/rtc_base/synchronization/mutex.cc new file mode 100644 index 00000000000..6c2d6ff7f06 --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/mutex.cc @@ -0,0 +1,39 @@ +/* + * Copyright 2020 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/synchronization/mutex.h" + +#include "rtc_base/checks.h" +#include "rtc_base/synchronization/yield.h" + +namespace webrtc { + +#if !defined(WEBRTC_ABSL_MUTEX) +void GlobalMutex::Lock() { + while (mutex_locked_.exchange(1)) { + YieldCurrentThread(); + } +} + +void GlobalMutex::Unlock() { + int old = mutex_locked_.exchange(0); + RTC_DCHECK_EQ(old, 1) << "Unlock called without calling Lock first"; +} + +GlobalMutexLock::GlobalMutexLock(GlobalMutex* mutex) : mutex_(mutex) { + mutex_->Lock(); +} + +GlobalMutexLock::~GlobalMutexLock() { + mutex_->Unlock(); +} +#endif // #if !defined(WEBRTC_ABSL_MUTEX) + +} // namespace webrtc diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/mutex.h b/chromium/third_party/webrtc/rtc_base/synchronization/mutex.h new file mode 100644 index 00000000000..cc12c7edf0f --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/mutex.h @@ -0,0 +1,145 @@ +/* + * Copyright 2020 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_SYNCHRONIZATION_MUTEX_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_H_ + +#include <atomic> + +#include "absl/base/const_init.h" +#include "rtc_base/checks.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/system/unused.h" +#include "rtc_base/thread_annotations.h" + +#if defined(WEBRTC_ABSL_MUTEX) +#include "rtc_base/synchronization/mutex_abseil.h" // nogncheck +#elif defined(WEBRTC_WIN) +#include "rtc_base/synchronization/mutex_critical_section.h" +#elif defined(WEBRTC_POSIX) +#include "rtc_base/synchronization/mutex_pthread.h" +#else +#error Unsupported platform. +#endif + +namespace webrtc { + +// The Mutex guarantees exclusive access and aims to follow Abseil semantics +// (i.e. non-reentrant etc). +class RTC_LOCKABLE Mutex final { + public: + Mutex() = default; + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { + rtc::PlatformThreadRef current = CurrentThreadRefAssertingNotBeingHolder(); + impl_.Lock(); + // |holder_| changes from 0 to CurrentThreadRef(). + holder_.store(current, std::memory_order_relaxed); + } + RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + rtc::PlatformThreadRef current = CurrentThreadRefAssertingNotBeingHolder(); + if (impl_.TryLock()) { + // |holder_| changes from 0 to CurrentThreadRef(). + holder_.store(current, std::memory_order_relaxed); + return true; + } + return false; + } + void Unlock() RTC_UNLOCK_FUNCTION() { + // |holder_| changes from CurrentThreadRef() to 0. If something else than + // CurrentThreadRef() is stored in |holder_|, the Unlock results in + // undefined behavior as mutexes can't be unlocked from another thread than + // the one that locked it, or called while not being locked. + holder_.store(0, std::memory_order_relaxed); + impl_.Unlock(); + } + + private: + rtc::PlatformThreadRef CurrentThreadRefAssertingNotBeingHolder() { + rtc::PlatformThreadRef holder = holder_.load(std::memory_order_relaxed); + rtc::PlatformThreadRef current = rtc::CurrentThreadRef(); + // TODO(bugs.webrtc.org/11567): remove this temporary check after migrating + // fully to Mutex. + RTC_CHECK_NE(holder, current); + return current; + } + + MutexImpl impl_; + // TODO(bugs.webrtc.org/11567): remove |holder_| after migrating fully to + // Mutex. + // |holder_| contains the PlatformThreadRef of the thread currently holding + // the lock, or 0. + // Remarks on the used memory orders: the atomic load in + // CurrentThreadRefAssertingNotBeingHolder() observes either of two things: + // 1. our own previous write to holder_ with our thread ID. + // 2. another thread (with ID y) writing y and then 0 from an initial value of + // 0. If we're observing case 1, our own stores are obviously ordered before + // the load, and hit the CHECK. If we're observing case 2, the value observed + // w.r.t |impl_| being locked depends on the memory order. Since we only care + // that it's different from CurrentThreadRef()), we use the more performant + // option, memory_order_relaxed. + std::atomic<rtc::PlatformThreadRef> holder_ = {0}; +}; + +// MutexLock, for serializing execution through a scope. +class RTC_SCOPED_LOCKABLE MutexLock final { + public: + MutexLock(const MutexLock&) = delete; + MutexLock& operator=(const MutexLock&) = delete; + + explicit MutexLock(Mutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(mutex) + : mutex_(mutex) { + mutex->Lock(); + } + ~MutexLock() RTC_UNLOCK_FUNCTION() { mutex_->Unlock(); } + + private: + Mutex* mutex_; +}; + +// A mutex used to protect global variables. Do NOT use for other purposes. +#if defined(WEBRTC_ABSL_MUTEX) +using GlobalMutex = absl::Mutex; +using GlobalMutexLock = absl::MutexLock; +#else +class RTC_LOCKABLE GlobalMutex final { + public: + GlobalMutex(const GlobalMutex&) = delete; + GlobalMutex& operator=(const GlobalMutex&) = delete; + + constexpr explicit GlobalMutex(absl::ConstInitType /*unused*/) + : mutex_locked_(0) {} + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION(); + void Unlock() RTC_UNLOCK_FUNCTION(); + + private: + std::atomic<int> mutex_locked_; // 0 means lock not taken, 1 means taken. +}; + +// GlobalMutexLock, for serializing execution through a scope. +class RTC_SCOPED_LOCKABLE GlobalMutexLock final { + public: + GlobalMutexLock(const GlobalMutexLock&) = delete; + GlobalMutexLock& operator=(const GlobalMutexLock&) = delete; + + explicit GlobalMutexLock(GlobalMutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(); + ~GlobalMutexLock() RTC_UNLOCK_FUNCTION(); + + private: + GlobalMutex* mutex_; +}; +#endif // if defined(WEBRTC_ABSL_MUTEX) + +} // namespace webrtc + +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_ diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/mutex_abseil.h b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_abseil.h new file mode 100644 index 00000000000..4ad1d07eef1 --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_abseil.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 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_SYNCHRONIZATION_MUTEX_ABSEIL_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_ABSEIL_H_ + +#include "absl/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class RTC_LOCKABLE MutexImpl final { + public: + MutexImpl() = default; + MutexImpl(const MutexImpl&) = delete; + MutexImpl& operator=(const MutexImpl&) = delete; + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { mutex_.Lock(); } + RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + return mutex_.TryLock(); + } + void Unlock() RTC_UNLOCK_FUNCTION() { mutex_.Unlock(); } + + private: + absl::Mutex mutex_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_ABSEIL_H_ diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/mutex_benchmark.cc b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_benchmark.cc new file mode 100644 index 00000000000..40adca65d86 --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_benchmark.cc @@ -0,0 +1,95 @@ +/* + * Copyright 2020 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 "benchmark/benchmark.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/system/unused.h" + +namespace webrtc { + +class PerfTestData { + public: + PerfTestData() : cache_line_barrier_1_(), cache_line_barrier_2_() { + cache_line_barrier_1_[0]++; // Avoid 'is not used'. + cache_line_barrier_2_[0]++; // Avoid 'is not used'. + } + + int AddToCounter(int add) { + MutexLock mu(&mu_); + my_counter_ += add; + return 0; + } + + private: + uint8_t cache_line_barrier_1_[64]; + Mutex mu_; + uint8_t cache_line_barrier_2_[64]; + int64_t my_counter_ = 0; +}; + +void BM_LockWithMutex(benchmark::State& state) { + static PerfTestData test_data; + for (auto s : state) { + RTC_UNUSED(s); + benchmark::DoNotOptimize(test_data.AddToCounter(2)); + } +} + +BENCHMARK(BM_LockWithMutex)->Threads(1); +BENCHMARK(BM_LockWithMutex)->Threads(2); +BENCHMARK(BM_LockWithMutex)->Threads(4); +BENCHMARK(BM_LockWithMutex)->ThreadPerCpu(); + +} // namespace webrtc + +/* + +Results: + +NB when reproducing: Remember to turn of power management features such as CPU +scaling before running! + +pthreads (Linux): +---------------------------------------------------------------------- +Run on (12 X 4500 MHz CPU s) +CPU Caches: + L1 Data 32 KiB (x6) + L1 Instruction 32 KiB (x6) + L2 Unified 1024 KiB (x6) + L3 Unified 8448 KiB (x1) +Load Average: 0.26, 0.28, 0.44 +---------------------------------------------------------------------- +Benchmark Time CPU Iterations +---------------------------------------------------------------------- +BM_LockWithMutex/threads:1 13.4 ns 13.4 ns 52192906 +BM_LockWithMutex/threads:2 44.2 ns 88.4 ns 8189944 +BM_LockWithMutex/threads:4 52.0 ns 198 ns 3743244 +BM_LockWithMutex/threads:12 84.9 ns 944 ns 733524 + +std::mutex performs like the pthread implementation (Linux). + +Abseil (Linux): +---------------------------------------------------------------------- +Run on (12 X 4500 MHz CPU s) +CPU Caches: + L1 Data 32 KiB (x6) + L1 Instruction 32 KiB (x6) + L2 Unified 1024 KiB (x6) + L3 Unified 8448 KiB (x1) +Load Average: 0.27, 0.24, 0.37 +---------------------------------------------------------------------- +Benchmark Time CPU Iterations +---------------------------------------------------------------------- +BM_LockWithMutex/threads:1 15.0 ns 15.0 ns 46550231 +BM_LockWithMutex/threads:2 91.1 ns 182 ns 4059212 +BM_LockWithMutex/threads:4 40.8 ns 131 ns 5496560 +BM_LockWithMutex/threads:12 37.0 ns 130 ns 5377668 + +*/ diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/mutex_critical_section.h b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_critical_section.h new file mode 100644 index 00000000000..d206794988b --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_critical_section.h @@ -0,0 +1,54 @@ +/* + * Copyright 2020 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_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_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 + +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class RTC_LOCKABLE MutexImpl final { + public: + MutexImpl() { InitializeCriticalSection(&critical_section_); } + MutexImpl(const MutexImpl&) = delete; + MutexImpl& operator=(const MutexImpl&) = delete; + ~MutexImpl() { DeleteCriticalSection(&critical_section_); } + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { + EnterCriticalSection(&critical_section_); + } + RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + return TryEnterCriticalSection(&critical_section_) != FALSE; + } + void Unlock() RTC_UNLOCK_FUNCTION() { + LeaveCriticalSection(&critical_section_); + } + + private: + CRITICAL_SECTION critical_section_; +}; + +} // namespace webrtc + +#endif // #if defined(WEBRTC_WIN) +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/mutex_pthread.h b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_pthread.h new file mode 100644 index 00000000000..c9496e72c9a --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_pthread.h @@ -0,0 +1,53 @@ +/* + * Copyright 2020 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_SYNCHRONIZATION_MUTEX_PTHREAD_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ + +#if defined(WEBRTC_POSIX) + +#include <pthread.h> +#if defined(WEBRTC_MAC) +#include <pthread_spis.h> +#endif + +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class RTC_LOCKABLE MutexImpl final { + public: + MutexImpl() { + pthread_mutexattr_t mutex_attribute; + pthread_mutexattr_init(&mutex_attribute); +#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); + } + MutexImpl(const MutexImpl&) = delete; + MutexImpl& operator=(const MutexImpl&) = delete; + ~MutexImpl() { pthread_mutex_destroy(&mutex_); } + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { pthread_mutex_lock(&mutex_); } + RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + return pthread_mutex_trylock(&mutex_) == 0; + } + void Unlock() RTC_UNLOCK_FUNCTION() { pthread_mutex_unlock(&mutex_); } + + private: + pthread_mutex_t mutex_; +}; + +} // namespace webrtc +#endif // #if defined(WEBRTC_POSIX) +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/mutex_unittest.cc b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_unittest.cc new file mode 100644 index 00000000000..b8c45d0a8cf --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/mutex_unittest.cc @@ -0,0 +1,206 @@ +/* + * Copyright 2020 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/synchronization/mutex.h" + +#include <stddef.h> +#include <stdint.h> + +#include <atomic> +#include <memory> +#include <type_traits> +#include <utility> +#include <vector> + +#include "benchmark/benchmark.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/location.h" +#include "rtc_base/message_handler.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/synchronization/yield.h" +#include "rtc_base/thread.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::rtc::Event; +using ::rtc::Message; +using ::rtc::MessageHandler; +using ::rtc::Thread; + +constexpr int kNumThreads = 16; + +template <class MutexType> +class RTC_LOCKABLE RawMutexLocker { + public: + explicit RawMutexLocker(MutexType& mutex) : mutex_(mutex) {} + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { mutex_.Lock(); } + void Unlock() RTC_UNLOCK_FUNCTION() { mutex_.Unlock(); } + + private: + MutexType& mutex_; +}; + +class RTC_LOCKABLE RawMutexTryLocker { + public: + explicit RawMutexTryLocker(Mutex& mutex) : mutex_(mutex) {} + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { + while (!mutex_.TryLock()) { + YieldCurrentThread(); + } + } + void Unlock() RTC_UNLOCK_FUNCTION() { mutex_.Unlock(); } + + private: + Mutex& mutex_; +}; + +template <class MutexType, class MutexLockType> +class MutexLockLocker { + public: + explicit MutexLockLocker(MutexType& mutex) : mutex_(mutex) {} + void Lock() { lock_ = std::make_unique<MutexLockType>(&mutex_); } + void Unlock() { lock_ = nullptr; } + + private: + MutexType& mutex_; + std::unique_ptr<MutexLockType> lock_; +}; + +template <class MutexType, class MutexLocker> +class LockRunner : public rtc::MessageHandlerAutoCleanup { + public: + template <typename... Args> + explicit LockRunner(Args... args) + : threads_active_(0), + start_event_(true, false), + done_event_(true, false), + shared_value_(0), + mutex_(args...), + locker_(mutex_) {} + + 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_ = count; } + + int shared_value() { + int shared_value; + locker_.Lock(); + shared_value = shared_value_; + locker_.Unlock(); + return shared_value_; + } + + void OnMessage(Message* msg) override { + ASSERT_TRUE(start_event_.Wait(kLongTime)); + locker_.Lock(); + + EXPECT_EQ(0, shared_value_); + int old = shared_value_; + + // Use a loop to increase the chance of race. If the |locker_| + // implementation is faulty, it would be improbable that the error slips + // through. + for (int i = 0; i < kOperationsToRun; ++i) { + benchmark::DoNotOptimize(++shared_value_); + } + EXPECT_EQ(old + kOperationsToRun, shared_value_); + shared_value_ = 0; + + locker_.Unlock(); + if (threads_active_.fetch_sub(1) == 1) { + done_event_.Set(); + } + } + + private: + static constexpr int kLongTime = 10000; // 10 seconds + static constexpr int kOperationsToRun = 1000; + + std::atomic<int> threads_active_; + Event start_event_; + Event done_event_; + int shared_value_; + MutexType mutex_; + MutexLocker locker_; +}; + +void StartThreads(std::vector<std::unique_ptr<Thread>>& threads, + MessageHandler* handler) { + for (int i = 0; i < kNumThreads; ++i) { + std::unique_ptr<Thread> thread(Thread::Create()); + thread->Start(); + thread->Post(RTC_FROM_HERE, handler); + threads.push_back(std::move(thread)); + } +} + +TEST(MutexTest, ProtectsSharedResourceWithMutexAndRawMutexLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<Mutex, RawMutexLocker<Mutex>> runner; + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +TEST(MutexTest, ProtectsSharedResourceWithMutexAndRawMutexTryLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<Mutex, RawMutexTryLocker> runner; + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +TEST(MutexTest, ProtectsSharedResourceWithMutexAndMutexLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<Mutex, MutexLockLocker<Mutex, MutexLock>> runner; + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +TEST(MutexTest, ProtectsSharedResourceWithGlobalMutexAndRawMutexLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<GlobalMutex, RawMutexLocker<GlobalMutex>> runner(absl::kConstInit); + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +TEST(MutexTest, ProtectsSharedResourceWithGlobalMutexAndMutexLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<GlobalMutex, MutexLockLocker<GlobalMutex, GlobalMutexLock>> runner( + absl::kConstInit); + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +TEST(MutexTest, GlobalMutexCanHaveStaticStorageDuration) { + ABSL_CONST_INIT static GlobalMutex global_lock(absl::kConstInit); + global_lock.Lock(); + global_lock.Unlock(); +} + +} // namespace +} // namespace webrtc diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.cc b/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.cc index d64f32a616d..ff433db137f 100644 --- a/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.cc +++ b/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.cc @@ -13,6 +13,8 @@ #include <dispatch/dispatch.h> #endif +#include "rtc_base/strings/string_builder.h" + namespace webrtc { namespace { // On Mac, returns the label of the current dispatch queue; elsewhere, return @@ -24,8 +26,16 @@ const void* GetSystemQueueRef() { return nullptr; #endif } + } // namespace +std::string ExpectationToString(const webrtc::SequenceChecker* checker) { +#if RTC_DCHECK_IS_ON + return checker->ExpectationToString(); +#endif + return std::string(); +} + SequenceCheckerImpl::SequenceCheckerImpl() : attached_(true), valid_thread_(rtc::CurrentThreadRef()), @@ -62,4 +72,41 @@ void SequenceCheckerImpl::Detach() { // reset on the next call to IsCurrent(). } +#if RTC_DCHECK_IS_ON +std::string SequenceCheckerImpl::ExpectationToString() const { + const TaskQueueBase* const current_queue = TaskQueueBase::Current(); + const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); + const void* const current_system_queue = GetSystemQueueRef(); + rtc::CritScope scoped_lock(&lock_); + if (!attached_) + return "Checker currently not attached."; + + // The format of the string is meant to compliment the one we have inside of + // FatalLog() (checks.cc). Example: + // + // # Expected: TQ: 0x0 SysQ: 0x7fff69541330 Thread: 0x11dcf6dc0 + // # Actual: TQ: 0x7fa8f0604190 SysQ: 0x7fa8f0604a30 Thread: 0x700006f1a000 + // TaskQueue doesn't match + + rtc::StringBuilder message; + message.AppendFormat( + "# Expected: TQ: %p SysQ: %p Thread: %p\n" + "# Actual: TQ: %p SysQ: %p Thread: %p\n", + valid_queue_, valid_system_queue_, + reinterpret_cast<const void*>(valid_thread_), current_queue, + current_system_queue, reinterpret_cast<const void*>(current_thread)); + + if ((valid_queue_ || current_queue) && valid_queue_ != current_queue) { + message << "TaskQueue doesn't match\n"; + } else if (valid_system_queue_ && + valid_system_queue_ != current_system_queue) { + message << "System queue doesn't match\n"; + } else if (!rtc::IsThreadRefEqual(valid_thread_, current_thread)) { + message << "Threads don't match\n"; + } + + return message.Release(); +} +#endif // RTC_DCHECK_IS_ON + } // namespace webrtc diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.h b/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.h index fe644fa14e3..fd0a69983af 100644 --- a/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.h +++ b/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker.h @@ -10,6 +10,8 @@ #ifndef RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ #define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ +#include <type_traits> + #include "api/task_queue/task_queue_base.h" #include "rtc_base/critical_section.h" #include "rtc_base/platform_thread_types.h" @@ -34,6 +36,11 @@ class RTC_EXPORT SequenceCheckerImpl { // used exclusively on another thread. void Detach(); + // Returns a string that is formatted to match with the error string printed + // by RTC_CHECK() when a condition is not met. + // This is used in conjunction with the RTC_DCHECK_RUN_ON() macro. + std::string ExpectationToString() const; + private: rtc::CriticalSection lock_; // These are mutable so that IsCurrent can set them. @@ -162,8 +169,19 @@ class RTC_SCOPED_LOCKABLE SequenceCheckerScope { #define RTC_RUN_ON(x) \ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x)) +namespace webrtc { +std::string ExpectationToString(const webrtc::SequenceChecker* checker); + +// Catch-all implementation for types other than explicitly supported above. +template <typename ThreadLikeObject> +std::string ExpectationToString(const ThreadLikeObject*) { + return std::string(); +} + +} // namespace webrtc + #define RTC_DCHECK_RUN_ON(x) \ webrtc::webrtc_seq_check_impl::SequenceCheckerScope seq_check_scope(x); \ - RTC_DCHECK((x)->IsCurrent()) + RTC_DCHECK((x)->IsCurrent()) << webrtc::ExpectationToString(x) #endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker_unittest.cc b/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker_unittest.cc index 1e62e9759b4..6fcb522c545 100644 --- a/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/synchronization/sequence_checker_unittest.cc @@ -31,7 +31,7 @@ class CompileTimeTestForGuardedBy { int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; } void CallMeFromSequence() { - RTC_DCHECK_RUN_ON(&sequence_checker_) << "Should be called on sequence"; + RTC_DCHECK_RUN_ON(&sequence_checker_); guarded_ = 41; } @@ -158,7 +158,12 @@ void TestAnnotationsOnWrongQueue() { } #if RTC_DCHECK_IS_ON -TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueDebug) { +// Note: Ending the test suite name with 'DeathTest' is important as it causes +// gtest to order this test before any other non-death-tests, to avoid potential +// global process state pollution such as shared worker threads being started +// (e.g. a side effect of calling InitCocoaMultiThreading() on Mac causes one or +// two additional threads to be created). +TEST(SequenceCheckerDeathTest, TestAnnotationsOnWrongQueueDebug) { ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, ""); } #else diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/yield.cc b/chromium/third_party/webrtc/rtc_base/synchronization/yield.cc new file mode 100644 index 00000000000..cbb58d12ab0 --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/yield.cc @@ -0,0 +1,36 @@ +/* + * Copyright 2020 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/synchronization/yield.h" + +#if defined(WEBRTC_WIN) +#include <windows.h> +#else +#include <sched.h> +#include <time.h> +#endif + +namespace webrtc { + +void YieldCurrentThread() { + // TODO(bugs.webrtc.org/11634): use dedicated OS functionality instead of + // sleep for yielding. +#if defined(WEBRTC_WIN) + ::Sleep(0); +#elif defined(WEBRTC_MAC) && defined(RTC_USE_NATIVE_MUTEX_ON_MAC) && \ + !RTC_USE_NATIVE_MUTEX_ON_MAC + sched_yield(); +#else + static const struct timespec ts_null = {0}; + nanosleep(&ts_null, nullptr); +#endif +} + +} // namespace webrtc diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/yield.h b/chromium/third_party/webrtc/rtc_base/synchronization/yield.h new file mode 100644 index 00000000000..d4f5f99f375 --- /dev/null +++ b/chromium/third_party/webrtc/rtc_base/synchronization/yield.h @@ -0,0 +1,20 @@ +/* + * Copyright 2020 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_SYNCHRONIZATION_YIELD_H_ +#define RTC_BASE_SYNCHRONIZATION_YIELD_H_ + +namespace webrtc { + +// Request rescheduling of threads. +void YieldCurrentThread(); + +} // namespace webrtc + +#endif // RTC_BASE_SYNCHRONIZATION_YIELD_H_ diff --git a/chromium/third_party/webrtc/rtc_base/synchronization/yield_policy_unittest.cc b/chromium/third_party/webrtc/rtc_base/synchronization/yield_policy_unittest.cc index e0c622510a1..0bf38f4537c 100644 --- a/chromium/third_party/webrtc/rtc_base/synchronization/yield_policy_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/synchronization/yield_policy_unittest.cc @@ -20,7 +20,7 @@ namespace rtc { namespace { class MockYieldHandler : public YieldInterface { public: - MOCK_METHOD0(YieldExecution, void()); + MOCK_METHOD(void, YieldExecution, (), (override)); }; } // namespace TEST(YieldPolicyTest, HandlerReceivesYieldSignalWhenSet) { diff --git a/chromium/third_party/webrtc/rtc_base/system/BUILD.gn b/chromium/third_party/webrtc/rtc_base/system/BUILD.gn index 79cb301038f..98867588ccc 100644 --- a/chromium/third_party/webrtc/rtc_base/system/BUILD.gn +++ b/chromium/third_party/webrtc/rtc_base/system/BUILD.gn @@ -75,10 +75,8 @@ rtc_source_set("thread_registry") { deps = [ "..:rtc_base_approved" ] if (is_android && !build_with_chromium) { sources += [ "thread_registry.cc" ] - deps += [ - "../../sdk/android:native_api_stacktrace", - "//third_party/abseil-cpp/absl/base:core_headers", - ] + deps += [ "../../sdk/android:native_api_stacktrace" ] + absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] } } diff --git a/chromium/third_party/webrtc/rtc_base/task_utils/BUILD.gn b/chromium/third_party/webrtc/rtc_base/task_utils/BUILD.gn index 1882cd9ee8d..54f9a048f02 100644 --- a/chromium/third_party/webrtc/rtc_base/task_utils/BUILD.gn +++ b/chromium/third_party/webrtc/rtc_base/task_utils/BUILD.gn @@ -21,9 +21,10 @@ rtc_library("repeating_task") { "../../api/task_queue", "../../api/units:time_delta", "../../api/units:timestamp", + "../../system_wrappers:system_wrappers", "../synchronization:sequence_checker", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } rtc_library("pending_task_safety_flag") { @@ -81,7 +82,7 @@ if (rtc_include_tests) { ":to_queued_task", "../../api/task_queue", "../../test:test_support", - "//third_party/abseil-cpp/absl/memory", ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } } diff --git a/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.cc b/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.cc index 71911e6982c..574e6331f14 100644 --- a/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.cc +++ b/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.cc @@ -17,17 +17,18 @@ namespace webrtc { namespace webrtc_repeating_task_impl { + RepeatingTaskBase::RepeatingTaskBase(TaskQueueBase* task_queue, - TimeDelta first_delay) + TimeDelta first_delay, + Clock* clock) : task_queue_(task_queue), - next_run_time_(Timestamp::Micros(rtc::TimeMicros()) + first_delay) { - sequence_checker_.Detach(); -} + clock_(clock), + next_run_time_(clock_->CurrentTime() + first_delay) {} RepeatingTaskBase::~RepeatingTaskBase() = default; bool RepeatingTaskBase::Run() { - RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK_RUN_ON(task_queue_); // Return true to tell the TaskQueue to destruct this object. if (next_run_time_.IsPlusInfinity()) return true; @@ -40,7 +41,7 @@ bool RepeatingTaskBase::Run() { return true; RTC_DCHECK(delay.IsFinite()); - TimeDelta lost_time = Timestamp::Micros(rtc::TimeMicros()) - next_run_time_; + TimeDelta lost_time = clock_->CurrentTime() - next_run_time_; next_run_time_ += delay; delay -= lost_time; delay = std::max(delay, TimeDelta::Zero()); @@ -53,7 +54,7 @@ bool RepeatingTaskBase::Run() { } void RepeatingTaskBase::Stop() { - RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK_RUN_ON(task_queue_); RTC_DCHECK(next_run_time_.IsFinite()); next_run_time_ = Timestamp::PlusInfinity(); } diff --git a/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.h b/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.h index 75d03bfe5e6..487b7d19d46 100644 --- a/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.h +++ b/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task.h @@ -19,7 +19,7 @@ #include "api/task_queue/task_queue_base.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" -#include "rtc_base/synchronization/sequence_checker.h" +#include "system_wrappers/include/clock.h" namespace webrtc { @@ -28,7 +28,9 @@ class RepeatingTaskHandle; namespace webrtc_repeating_task_impl { class RepeatingTaskBase : public QueuedTask { public: - RepeatingTaskBase(TaskQueueBase* task_queue, TimeDelta first_delay); + RepeatingTaskBase(TaskQueueBase* task_queue, + TimeDelta first_delay, + Clock* clock); ~RepeatingTaskBase() override; void Stop(); @@ -39,16 +41,10 @@ class RepeatingTaskBase : public QueuedTask { bool Run() final; TaskQueueBase* const task_queue_; + Clock* const clock_; // This is always finite, except for the special case where it's PlusInfinity // to signal that the task should stop. - Timestamp next_run_time_ RTC_GUARDED_BY(sequence_checker_); - // We use a SequenceChecker to check for correct usage instead of using - // RTC_DCHECK_RUN_ON(task_queue_). This is to work around a compatibility - // issue with some TQ implementations such as rtc::Thread that don't - // consistently set themselves as the 'current' TQ when running tasks. - // The SequenceChecker detects those implementations differently but gives - // the same effect as far as thread safety goes. - SequenceChecker sequence_checker_; + Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_); }; // The template closure pattern is based on rtc::ClosureTask. @@ -57,8 +53,9 @@ class RepeatingTaskImpl final : public RepeatingTaskBase { public: RepeatingTaskImpl(TaskQueueBase* task_queue, TimeDelta first_delay, - Closure&& closure) - : RepeatingTaskBase(task_queue, first_delay), + Closure&& closure, + Clock* clock) + : RepeatingTaskBase(task_queue, first_delay, clock), closure_(std::forward<Closure>(closure)) { static_assert( std::is_same<TimeDelta, @@ -98,10 +95,11 @@ class RepeatingTaskHandle { // repeated task is owned by the TaskQueue. template <class Closure> static RepeatingTaskHandle Start(TaskQueueBase* task_queue, - Closure&& closure) { + Closure&& closure, + Clock* clock = Clock::GetRealTimeClock()) { auto repeating_task = std::make_unique< webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>( - task_queue, TimeDelta::Zero(), std::forward<Closure>(closure)); + task_queue, TimeDelta::Zero(), std::forward<Closure>(closure), clock); auto* repeating_task_ptr = repeating_task.get(); task_queue->PostTask(std::move(repeating_task)); return RepeatingTaskHandle(repeating_task_ptr); @@ -110,12 +108,14 @@ class RepeatingTaskHandle { // DelayedStart is equivalent to Start except that the first invocation of the // closure will be delayed by the given amount. template <class Closure> - static RepeatingTaskHandle DelayedStart(TaskQueueBase* task_queue, - TimeDelta first_delay, - Closure&& closure) { + static RepeatingTaskHandle DelayedStart( + TaskQueueBase* task_queue, + TimeDelta first_delay, + Closure&& closure, + Clock* clock = Clock::GetRealTimeClock()) { auto repeating_task = std::make_unique< webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>( - task_queue, first_delay, std::forward<Closure>(closure)); + task_queue, first_delay, std::forward<Closure>(closure), clock); auto* repeating_task_ptr = repeating_task.get(); task_queue->PostDelayedTask(std::move(repeating_task), first_delay.ms()); return RepeatingTaskHandle(repeating_task_ptr); diff --git a/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task_unittest.cc b/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task_unittest.cc index 83efb29209a..2fb15d1e5a3 100644 --- a/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/task_utils/repeating_task_unittest.cc @@ -40,8 +40,23 @@ void Sleep(TimeDelta time_delta) { class MockClosure { public: - MOCK_METHOD0(Call, TimeDelta()); - MOCK_METHOD0(Delete, void()); + MOCK_METHOD(TimeDelta, Call, ()); + MOCK_METHOD(void, Delete, ()); +}; + +class MockTaskQueue : public TaskQueueBase { + public: + MockTaskQueue() : task_queue_setter_(this) {} + + MOCK_METHOD(void, Delete, (), (override)); + MOCK_METHOD(void, PostTask, (std::unique_ptr<QueuedTask> task), (override)); + MOCK_METHOD(void, + PostDelayedTask, + (std::unique_ptr<QueuedTask> task, uint32_t milliseconds), + (override)); + + private: + CurrentTaskQueueSetter task_queue_setter_; }; class MoveOnlyClosure { @@ -228,4 +243,37 @@ TEST(RepeatingTaskTest, Example) { // task queue destruction and running the desctructor closure. } +TEST(RepeatingTaskTest, ClockIntegration) { + std::unique_ptr<QueuedTask> delayed_task; + uint32_t expected_ms = 0; + SimulatedClock clock(Timestamp::Millis(0)); + + NiceMock<MockTaskQueue> task_queue; + ON_CALL(task_queue, PostDelayedTask) + .WillByDefault( + Invoke([&delayed_task, &expected_ms](std::unique_ptr<QueuedTask> task, + uint32_t milliseconds) { + EXPECT_EQ(milliseconds, expected_ms); + delayed_task = std::move(task); + })); + + expected_ms = 100; + RepeatingTaskHandle handle = RepeatingTaskHandle::DelayedStart( + &task_queue, TimeDelta::Millis(100), + [&clock]() { + EXPECT_EQ(Timestamp::Millis(100), clock.CurrentTime()); + // Simulate work happening for 10ms. + clock.AdvanceTimeMilliseconds(10); + return TimeDelta::Millis(100); + }, + &clock); + + clock.AdvanceTimeMilliseconds(100); + QueuedTask* task_to_run = delayed_task.release(); + expected_ms = 90; + EXPECT_FALSE(task_to_run->Run()); + EXPECT_NE(nullptr, delayed_task.get()); + handle.Stop(); +} + } // namespace webrtc diff --git a/chromium/third_party/webrtc/rtc_base/thread.cc b/chromium/third_party/webrtc/rtc_base/thread.cc index 0fb2e813e03..566edff13fd 100644 --- a/chromium/third_party/webrtc/rtc_base/thread.cc +++ b/chromium/third_party/webrtc/rtc_base/thread.cc @@ -32,8 +32,10 @@ #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" #include "rtc_base/critical_section.h" +#include "rtc_base/event.h" #include "rtc_base/logging.h" #include "rtc_base/null_socket_server.h" +#include "rtc_base/synchronization/sequence_checker.h" #include "rtc_base/task_utils/to_queued_task.h" #include "rtc_base/time_utils.h" #include "rtc_base/trace_event.h" @@ -72,7 +74,7 @@ const int kSlowDispatchLoggingThreshold = 50; // 50 ms class MessageHandlerWithTask final : public MessageHandler { public: - MessageHandlerWithTask() = default; + MessageHandlerWithTask() : MessageHandler(false) {} void OnMessage(Message* msg) override { static_cast<rtc_thread_internal::MessageLikeTask*>(msg->pdata)->Run(); @@ -163,13 +165,16 @@ void ThreadManager::RemoveFromSendGraph(Thread* thread) { void ThreadManager::RegisterSendAndCheckForCycles(Thread* source, Thread* target) { + RTC_DCHECK(source); + RTC_DCHECK(target); + CritScope cs(&crit_); std::deque<Thread*> all_targets({target}); // We check the pre-existing who-sends-to-who graph for any path from target // to source. This loop is guaranteed to terminate because per the send graph // invariant, there are no cycles in the graph. - for (auto it = all_targets.begin(); it != all_targets.end(); ++it) { - const auto& targets = send_graph_[*it]; + for (size_t i = 0; i < all_targets.size(); i++) { + const auto& targets = send_graph_[all_targets[i]]; all_targets.insert(all_targets.end(), targets.begin(), targets.end()); } RTC_CHECK_EQ(absl::c_count(all_targets, source), 0) @@ -296,6 +301,21 @@ void ThreadManager::SetCurrentThread(Thread* thread) { RTC_DLOG(LS_ERROR) << "SetCurrentThread: Overwriting an existing value?"; } #endif // RTC_DLOG_IS_ON + + if (thread) { + thread->EnsureIsCurrentTaskQueue(); + } else { + Thread* current = CurrentThread(); + if (current) { + // The current thread is being cleared, e.g. as a result of + // UnwrapCurrent() being called or when a thread is being stopped + // (see PreRun()). This signals that the Thread instance is being detached + // from the thread, which also means that TaskQueue::Current() must not + // return a pointer to the Thread instance. + current->ClearCurrentTaskQueue(); + } + } + SetCurrentThreadInternal(thread); } @@ -824,7 +844,6 @@ void* Thread::PreRun(void* pv) { Thread* thread = static_cast<Thread*>(pv); ThreadManager::Instance()->SetCurrentThread(thread); rtc::SetCurrentThreadName(thread->name_.c_str()); - CurrentTaskQueueSetter set_current_task_queue(thread); #if defined(WEBRTC_MAC) ScopedAutoReleasePool pool; #endif @@ -875,45 +894,62 @@ void Thread::Send(const Location& posted_from, AssertBlockingIsAllowedOnCurrentThread(); - AutoThread thread; Thread* current_thread = Thread::Current(); - RTC_DCHECK(current_thread != nullptr); // AutoThread ensures this + #if RTC_DCHECK_IS_ON - ThreadManager::Instance()->RegisterSendAndCheckForCycles(current_thread, - this); + if (current_thread) { + RTC_DCHECK(current_thread->IsInvokeToThreadAllowed(this)); + ThreadManager::Instance()->RegisterSendAndCheckForCycles(current_thread, + this); + } #endif + + // Perhaps down the line we can get rid of this workaround and always require + // current_thread to be valid when Send() is called. + std::unique_ptr<rtc::Event> done_event; + if (!current_thread) + done_event.reset(new rtc::Event()); + bool ready = false; - PostTask( - webrtc::ToQueuedTask([msg]() mutable { msg.phandler->OnMessage(&msg); }, - [this, &ready, current_thread] { - CritScope cs(&crit_); - ready = true; - current_thread->socketserver()->WakeUp(); - })); - - bool waited = false; - crit_.Enter(); - while (!ready) { - crit_.Leave(); - current_thread->socketserver()->Wait(kForever, false); - waited = true; + PostTask(webrtc::ToQueuedTask( + [&msg]() mutable { msg.phandler->OnMessage(&msg); }, + [this, &ready, current_thread, done = done_event.get()] { + if (current_thread) { + CritScope cs(&crit_); + ready = true; + current_thread->socketserver()->WakeUp(); + } else { + done->Set(); + } + })); + + if (current_thread) { + bool waited = false; crit_.Enter(); - } - crit_.Leave(); - - // Our Wait loop above may have consumed some WakeUp events for this - // Thread, that weren't relevant to this Send. Losing these WakeUps can - // cause problems for some SocketServers. - // - // Concrete example: - // Win32SocketServer on thread A calls Send on thread B. While processing the - // message, thread B Posts a message to A. We consume the wakeup for that - // Post while waiting for the Send to complete, which means that when we exit - // this loop, we need to issue another WakeUp, or else the Posted message - // won't be processed in a timely manner. - - if (waited) { - current_thread->socketserver()->WakeUp(); + while (!ready) { + crit_.Leave(); + current_thread->socketserver()->Wait(kForever, false); + waited = true; + crit_.Enter(); + } + crit_.Leave(); + + // Our Wait loop above may have consumed some WakeUp events for this + // Thread, that weren't relevant to this Send. Losing these WakeUps can + // cause problems for some SocketServers. + // + // Concrete example: + // Win32SocketServer on thread A calls Send on thread B. While processing + // the message, thread B Posts a message to A. We consume the wakeup for + // that Post while waiting for the Send to complete, which means that when + // we exit this loop, we need to issue another WakeUp, or else the Posted + // message won't be processed in a timely manner. + + if (waited) { + current_thread->socketserver()->WakeUp(); + } + } else { + done_event->Wait(rtc::Event::kForever); } } @@ -925,7 +961,7 @@ void Thread::InvokeInternal(const Location& posted_from, class FunctorMessageHandler : public MessageHandler { public: explicit FunctorMessageHandler(rtc::FunctionView<void()> functor) - : functor_(functor) {} + : MessageHandler(false), functor_(functor) {} void OnMessage(Message* msg) override { functor_(); } private: @@ -935,6 +971,17 @@ void Thread::InvokeInternal(const Location& posted_from, Send(posted_from, &handler); } +// Called by the ThreadManager when being set as the current thread. +void Thread::EnsureIsCurrentTaskQueue() { + task_queue_registration_ = + std::make_unique<TaskQueueBase::CurrentTaskQueueSetter>(this); +} + +// Called by the ThreadManager when being set as the current thread. +void Thread::ClearCurrentTaskQueue() { + task_queue_registration_.reset(); +} + void Thread::QueuedTaskHandler::OnMessage(Message* msg) { RTC_DCHECK(msg); auto* data = static_cast<ScopedMessageData<webrtc::QueuedTask>*>(msg->pdata); @@ -949,6 +996,50 @@ void Thread::QueuedTaskHandler::OnMessage(Message* msg) { task.release(); } +void Thread::AllowInvokesToThread(Thread* thread) { +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) + if (!IsCurrent()) { + PostTask(webrtc::ToQueuedTask( + [thread, this]() { AllowInvokesToThread(thread); })); + return; + } + RTC_DCHECK_RUN_ON(this); + allowed_threads_.push_back(thread); + invoke_policy_enabled_ = true; +#endif +} + +void Thread::DisallowAllInvokes() { +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) + if (!IsCurrent()) { + PostTask(webrtc::ToQueuedTask([this]() { DisallowAllInvokes(); })); + return; + } + RTC_DCHECK_RUN_ON(this); + allowed_threads_.clear(); + invoke_policy_enabled_ = true; +#endif +} + +// Returns true if no policies added or if there is at least one policy +// that permits invocation to |target| thread. +bool Thread::IsInvokeToThreadAllowed(rtc::Thread* target) { +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) + RTC_DCHECK_RUN_ON(this); + if (!invoke_policy_enabled_) { + return true; + } + for (const auto* thread : allowed_threads_) { + if (thread == target) { + return true; + } + } + return false; +#else + return true; +#endif +} + void Thread::PostTask(std::unique_ptr<webrtc::QueuedTask> task) { // Though Post takes MessageData by raw pointer (last parameter), it still // takes it with ownership. diff --git a/chromium/third_party/webrtc/rtc_base/thread.h b/chromium/third_party/webrtc/rtc_base/thread.h index 74aab623c87..341f94285bc 100644 --- a/chromium/third_party/webrtc/rtc_base/thread.h +++ b/chromium/third_party/webrtc/rtc_base/thread.h @@ -338,6 +338,19 @@ class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { InvokeInternal(posted_from, functor); } + // Allows invoke to specified |thread|. Thread never will be dereferenced and + // will be used only for reference-based comparison, so instance can be safely + // deleted. If NDEBUG is defined and DCHECK_ALWAYS_ON is undefined do nothing. + void AllowInvokesToThread(Thread* thread); + + // If NDEBUG is defined and DCHECK_ALWAYS_ON is undefined do nothing. + void DisallowAllInvokes(); + // Returns true if |target| was allowed by AllowInvokesToThread() or if no + // calls were made to AllowInvokesToThread and DisallowAllInvokes. Otherwise + // returns false. + // If NDEBUG is defined and DCHECK_ALWAYS_ON is undefined always returns true. + bool IsInvokeToThreadAllowed(rtc::Thread* target); + // Posts a task to invoke the functor on |this| thread asynchronously, i.e. // without blocking the thread that invoked PostTask(). Ownership of |functor| // is passed and (usually, see below) destroyed on |this| thread after it is @@ -524,6 +537,7 @@ class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { private: class QueuedTaskHandler final : public MessageHandler { public: + QueuedTaskHandler() : MessageHandler(false) {} void OnMessage(Message* msg) override; }; @@ -551,6 +565,12 @@ class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { void InvokeInternal(const Location& posted_from, rtc::FunctionView<void()> functor); + // Called by the ThreadManager when being set as the current thread. + void EnsureIsCurrentTaskQueue(); + + // Called by the ThreadManager when being unset as the current thread. + void ClearCurrentTaskQueue(); + // Returns a static-lifetime MessageHandler which runs message with // MessageLikeTask payload data. static MessageHandler* GetPostTaskMessageHandler(); @@ -560,6 +580,10 @@ class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { MessageList messages_ RTC_GUARDED_BY(crit_); PriorityQueue delayed_messages_ RTC_GUARDED_BY(crit_); uint32_t delayed_next_num_ RTC_GUARDED_BY(crit_); +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) + std::vector<Thread*> allowed_threads_ RTC_GUARDED_BY(this); + bool invoke_policy_enabled_ RTC_GUARDED_BY(this) = false; +#endif CriticalSection crit_; bool fInitialized_; bool fDestroyed_; @@ -595,6 +619,8 @@ class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { // Runs webrtc::QueuedTask posted to the Thread. QueuedTaskHandler queued_task_handler_; + std::unique_ptr<TaskQueueBase::CurrentTaskQueueSetter> + task_queue_registration_; friend class ThreadManager; @@ -604,7 +630,9 @@ class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { // AutoThread automatically installs itself at construction // uninstalls at destruction, if a Thread object is // _not already_ associated with the current OS thread. - +// +// NOTE: *** This class should only be used by tests *** +// class AutoThread : public Thread { public: AutoThread(); diff --git a/chromium/third_party/webrtc/rtc_base/thread_unittest.cc b/chromium/third_party/webrtc/rtc_base/thread_unittest.cc index d53a3879141..193819c6e40 100644 --- a/chromium/third_party/webrtc/rtc_base/thread_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/thread_unittest.cc @@ -94,7 +94,7 @@ class SocketClient : public TestGenerator, public sigslot::has_slots<> { }; // Receives messages and sends on a socket. -class MessageClient : public MessageHandler, public TestGenerator { +class MessageClient : public MessageHandlerAutoCleanup, public TestGenerator { public: MessageClient(Thread* pth, Socket* socket) : socket_(socket) {} @@ -516,7 +516,7 @@ TEST_F(ThreadQueueTest, DisposeNotLocked) { EXPECT_FALSE(was_locked); } -class DeletedMessageHandler : public MessageHandler { +class DeletedMessageHandler : public MessageHandlerAutoCleanup { public: explicit DeletedMessageHandler(bool* deleted) : deleted_(deleted) {} ~DeletedMessageHandler() override { *deleted_ = true; } @@ -606,12 +606,13 @@ TEST(ThreadManager, ProcessAllMessageQueuesWithClearedQueue) { ThreadManager::ProcessAllMessageQueuesForTesting(); } -class RefCountedHandler : public MessageHandler, public rtc::RefCountInterface { +class RefCountedHandler : public MessageHandlerAutoCleanup, + public rtc::RefCountInterface { public: void OnMessage(Message* msg) override {} }; -class EmptyHandler : public MessageHandler { +class EmptyHandler : public MessageHandlerAutoCleanup { public: void OnMessage(Message* msg) override {} }; @@ -1148,6 +1149,18 @@ TEST(ThreadPostDelayedTaskTest, InvokesInDelayOrder) { EXPECT_TRUE(fourth.Wait(0)); } +TEST(ThreadPostDelayedTaskTest, IsCurrentTaskQueue) { + auto current_tq = webrtc::TaskQueueBase::Current(); + { + std::unique_ptr<rtc::Thread> thread(rtc::Thread::Create()); + thread->WrapCurrent(); + EXPECT_EQ(webrtc::TaskQueueBase::Current(), + static_cast<webrtc::TaskQueueBase*>(thread.get())); + thread->UnwrapCurrent(); + } + EXPECT_EQ(webrtc::TaskQueueBase::Current(), current_tq); +} + class ThreadFactory : public webrtc::TaskQueueFactory { public: std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> diff --git a/chromium/third_party/webrtc/rtc_base/virtual_socket_server.h b/chromium/third_party/webrtc/rtc_base/virtual_socket_server.h index f45fabf0af1..5ad66a8d34e 100644 --- a/chromium/third_party/webrtc/rtc_base/virtual_socket_server.h +++ b/chromium/third_party/webrtc/rtc_base/virtual_socket_server.h @@ -304,7 +304,7 @@ class VirtualSocketServer : public SocketServer, public sigslot::has_slots<> { // Implements the socket interface using the virtual network. Packets are // passed as messages using the message queue of the socket server. class VirtualSocket : public AsyncSocket, - public MessageHandler, + public MessageHandlerAutoCleanup, public sigslot::has_slots<> { public: VirtualSocket(VirtualSocketServer* server, int family, int type, bool async); diff --git a/chromium/third_party/webrtc/rtc_base/virtual_socket_unittest.cc b/chromium/third_party/webrtc/rtc_base/virtual_socket_unittest.cc index b274b40857d..78003f5cb24 100644 --- a/chromium/third_party/webrtc/rtc_base/virtual_socket_unittest.cc +++ b/chromium/third_party/webrtc/rtc_base/virtual_socket_unittest.cc @@ -53,7 +53,7 @@ using webrtc::testing::SSE_WRITE; using webrtc::testing::StreamSink; // Sends at a constant rate but with random packet sizes. -struct Sender : public MessageHandler { +struct Sender : public MessageHandlerAutoCleanup { Sender(Thread* th, AsyncSocket* s, uint32_t rt) : thread(th), socket(std::make_unique<AsyncUDPSocket>(s)), @@ -99,7 +99,8 @@ struct Sender : public MessageHandler { char dummy[4096]; }; -struct Receiver : public MessageHandler, public sigslot::has_slots<> { +struct Receiver : public MessageHandlerAutoCleanup, + public sigslot::has_slots<> { Receiver(Thread* th, AsyncSocket* s, uint32_t bw) : thread(th), socket(std::make_unique<AsyncUDPSocket>(s)), |