Bump to WebRTC M120 release

Some API deprecation -- ExperimentalAgc and ExperimentalNs are gone.
We're continuing to carry iSAC even though it's gone upstream, but maybe
we'll want to drop that soon.
This commit is contained in:
Arun Raghavan
2023-12-12 10:42:58 -05:00
parent 9a202fb8c2
commit c6abf6cd3f
479 changed files with 20900 additions and 11996 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,79 +0,0 @@
/*
* Copyright 2011 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_ATOMIC_OPS_H_
#define RTC_BASE_ATOMIC_OPS_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>
// clang-format on
#endif // defined(WEBRTC_WIN)
namespace rtc {
class AtomicOps {
public:
#if defined(WEBRTC_WIN)
// Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
static int Increment(volatile int* i) {
return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
}
static int Decrement(volatile int* i) {
return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
}
static int AcquireLoad(volatile const int* i) { return *i; }
static void ReleaseStore(volatile int* i, int value) { *i = value; }
static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
return ::InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(i),
new_value, old_value);
}
// Pointer variants.
template <typename T>
static T* AcquireLoadPtr(T* volatile* ptr) {
return *ptr;
}
template <typename T>
static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
return static_cast<T*>(::InterlockedCompareExchangePointer(
reinterpret_cast<PVOID volatile*>(ptr), new_value, old_value));
}
#else
static int Increment(volatile int* i) { return __sync_add_and_fetch(i, 1); }
static int Decrement(volatile int* i) { return __sync_sub_and_fetch(i, 1); }
static int AcquireLoad(volatile const int* i) {
return __atomic_load_n(i, __ATOMIC_ACQUIRE);
}
static void ReleaseStore(volatile int* i, int value) {
__atomic_store_n(i, value, __ATOMIC_RELEASE);
}
static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
return __sync_val_compare_and_swap(i, old_value, new_value);
}
// Pointer variants.
template <typename T>
static T* AcquireLoadPtr(T* volatile* ptr) {
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
}
template <typename T>
static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
#endif
};
} // namespace rtc
#endif // RTC_BASE_ATOMIC_OPS_H_

View File

@ -19,6 +19,7 @@
#include <type_traits>
#include <utility>
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/type_traits.h"
@ -105,7 +106,10 @@ class BufferT {
internal::BufferCompat<T, U>::value>::type* = nullptr>
BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) {
static_assert(sizeof(T) == sizeof(U), "");
std::memcpy(data_.get(), data, size * sizeof(U));
if (size > 0) {
RTC_DCHECK(data);
std::memcpy(data_.get(), data, size * sizeof(U));
}
}
// Construct a buffer from the contents of an array.
@ -117,6 +121,13 @@ class BufferT {
~BufferT() { MaybeZeroCompleteBuffer(); }
// Implicit conversion to absl::string_view if T is compatible with char.
template <typename U = T>
operator typename std::enable_if<internal::BufferCompat<U, char>::value,
absl::string_view>::type() const {
return absl::string_view(data<char>(), size());
}
// Get a pointer to the data. Just .data() will give you a (const) T*, but if
// T is a byte-sized integer, you may also use .data<U>() for any other
// byte-sized integer U.
@ -229,13 +240,13 @@ class BufferT {
SetData(w.data(), w.size());
}
// Replaces the data in the buffer with at most |max_elements| of data, using
// the function |setter|, which should have the following signature:
// Replaces the data in the buffer with at most `max_elements` of data, using
// the function `setter`, which should have the following signature:
//
// size_t setter(ArrayView<U> view)
//
// |setter| is given an appropriately typed ArrayView of length exactly
// |max_elements| that describes the area where it should write the data; it
// `setter` is given an appropriately typed ArrayView of length exactly
// `max_elements` that describes the area where it should write the data; it
// should return the number of elements actually written. (If it doesn't fill
// the whole ArrayView, it should leave the unused space at the end.)
template <typename U = T,
@ -259,6 +270,10 @@ class BufferT {
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
void AppendData(const U* data, size_t size) {
if (size == 0) {
return;
}
RTC_DCHECK(data);
RTC_DCHECK(IsConsistent());
const size_t new_size = size_ + size;
EnsureCapacityWithHeadroom(new_size, true);
@ -290,13 +305,13 @@ class BufferT {
AppendData(&item, 1);
}
// Appends at most |max_elements| to the end of the buffer, using the function
// |setter|, which should have the following signature:
// Appends at most `max_elements` to the end of the buffer, using the function
// `setter`, which should have the following signature:
//
// size_t setter(ArrayView<U> view)
//
// |setter| is given an appropriately typed ArrayView of length exactly
// |max_elements| that describes the area where it should write the data; it
// `setter` is given an appropriately typed ArrayView of length exactly
// `max_elements` that describes the area where it should write the data; it
// should return the number of elements actually written. (If it doesn't fill
// the whole ArrayView, it should leave the unused space at the end.)
template <typename U = T,

View File

@ -15,6 +15,8 @@
#include <cstdio>
#include <cstdlib>
#include "absl/strings/string_view.h"
#if defined(WEBRTC_ANDROID)
#define RTC_LOG_TAG_ANDROID "rtc"
#include <android/log.h> // NOLINT
@ -36,6 +38,7 @@
#include "rtc_base/checks.h"
namespace {
#if defined(__GNUC__)
__attribute__((__format__(__printf__, 2, 3)))
#endif
@ -59,6 +62,30 @@ void AppendFormat(std::string* s, const char* fmt, ...) {
namespace rtc {
namespace webrtc_checks_impl {
#if !defined(WEBRTC_CHROMIUM_BUILD)
RTC_NORETURN void WriteFatalLog(absl::string_view output) {
#if defined(WEBRTC_ANDROID)
std::string output_str(output);
__android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n",
output_str.c_str());
#endif
fflush(stdout);
fwrite(output.data(), output.size(), 1, stderr);
fflush(stderr);
#if defined(WEBRTC_WIN)
DebugBreak();
#endif
abort();
}
RTC_NORETURN void WriteFatalLog(const char* file,
int line,
absl::string_view output) {
WriteFatalLog(output);
}
#endif // !defined(WEBRTC_CHROMIUM_BUILD)
#if RTC_CHECK_MSG_ENABLED
// Reads one argument from args, appends it to s and advances fmt.
// Returns true iff an argument was sucessfully parsed.
@ -149,19 +176,7 @@ RTC_NORETURN void FatalLog(const char* file,
va_end(args);
const char* output = s.c_str();
#if defined(WEBRTC_ANDROID)
__android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output);
#endif
fflush(stdout);
fprintf(stderr, "%s", output);
fflush(stderr);
#if defined(WEBRTC_WIN)
DebugBreak();
#endif
abort();
WriteFatalLog(file, line, s);
}
#else // RTC_CHECK_MSG_ENABLED
RTC_NORETURN void FatalLog(const char* file, int line) {
@ -174,22 +189,40 @@ RTC_NORETURN void FatalLog(const char* file, int line) {
"# Check failed.\n"
"# ",
file, line, LAST_SYSTEM_ERROR);
const char* output = s.c_str();
#if defined(WEBRTC_ANDROID)
__android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output);
#endif
fflush(stdout);
fprintf(stderr, "%s", output);
fflush(stderr);
#if defined(WEBRTC_WIN)
DebugBreak();
#endif
abort();
WriteFatalLog(file, line, s);
}
#endif // RTC_CHECK_MSG_ENABLED
#if RTC_DCHECK_IS_ON
RTC_NORETURN void UnreachableCodeReached(const char* file, int line) {
std::string s;
AppendFormat(&s,
"\n\n"
"#\n"
"# Unreachable code reached: %s, line %d\n"
"# last system error: %u\n"
"# ",
file, line, LAST_SYSTEM_ERROR);
WriteFatalLog(file, line, s);
}
#else // !RTC_DCHECK_IS_ON
RTC_NORETURN void UnreachableCodeReached() {
std::string s;
AppendFormat(&s,
"\n\n"
"#\n"
"# Unreachable code reached (file and line unknown)\n"
"# last system error: %u\n"
"# ",
LAST_SYSTEM_ERROR);
WriteFatalLog(s);
}
#endif // !RTC_DCHECK_IS_ON
} // namespace webrtc_checks_impl
} // namespace rtc

View File

@ -56,6 +56,7 @@ RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
#include "api/scoped_refptr.h"
#include "rtc_base/numerics/safe_compare.h"
#include "rtc_base/system/inline.h"
#include "rtc_base/system/rtc_export.h"
@ -95,7 +96,7 @@ RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
// messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and
// RTC_DCHECK.
//
// - FATAL() aborts unconditionally.
// - RTC_FATAL() aborts unconditionally.
namespace rtc {
namespace webrtc_checks_impl {
@ -121,6 +122,13 @@ enum class CheckArgType : int8_t {
kCheckOp,
};
// These two functions are public so they can be overridden from
// webrtc_overrides in chromium.
RTC_NORETURN void WriteFatalLog(const char* file,
int line,
absl::string_view output);
RTC_NORETURN void WriteFatalLog(absl::string_view output);
#if RTC_CHECK_MSG_ENABLED
RTC_NORETURN RTC_EXPORT void FatalLog(const char* file,
int line,
@ -192,6 +200,12 @@ inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) {
return {x};
}
template <typename T>
inline Val<CheckArgType::kVoidP, const void*> MakeVal(
const rtc::scoped_refptr<T>& p) {
return {p.get()};
}
// The enum class types are not implicitly convertible to arithmetic types.
template <typename T,
absl::enable_if_t<std::is_enum<T>::value &&
@ -338,9 +352,25 @@ class FatalLogCall final {
const char* message_;
};
#if RTC_DCHECK_IS_ON
// Be helpful, and include file and line in the RTC_CHECK_NOTREACHED error
// message.
#define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS __FILE__, __LINE__
RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(const char* file, int line);
#else
// Be mindful of binary size, and don't include file and line in the
// RTC_CHECK_NOTREACHED error message.
#define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS
RTC_NORETURN RTC_EXPORT void UnreachableCodeReached();
#endif
} // namespace webrtc_checks_impl
// The actual stream used isn't important. We reference |ignored| in the code
// The actual stream used isn't important. We reference `ignored` in the code
// but don't evaluate it; this is to avoid "unused variable" warnings (we do so
// in a particularly convoluted way with an extra ?: because that appears to be
// the simplest construct that keeps Visual Studio from complaining about
@ -352,8 +382,8 @@ class FatalLogCall final {
::rtc::webrtc_checks_impl::LogStreamer<>()
// Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if
// values of the same types as |a| and |b| can't be compared with the given
// operation, and that would evaluate |a| and |b| if evaluated.
// values of the same types as `a` and `b` can't be compared with the given
// operation, and that would evaluate `a` and `b` if evaluated.
#define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \
RTC_EAT_STREAM_PARAMETERS(((void)::rtc::Safe##op(a, b)))
@ -361,7 +391,7 @@ class FatalLogCall final {
// controlled by NDEBUG or anything else, so the check will be executed
// regardless of compilation mode.
//
// We make sure RTC_CHECK et al. always evaluates |condition|, as
// We make sure RTC_CHECK et al. always evaluates `condition`, as
// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
//
// RTC_CHECK_OP is a helper macro for binary operators.
@ -381,22 +411,20 @@ class FatalLogCall final {
::rtc::webrtc_checks_impl::LogStreamer<>() << (val1) << (val2)
#else
#define RTC_CHECK(condition) \
(condition) \
? static_cast<void>(0) \
: true ? ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, \
__LINE__, "") & \
::rtc::webrtc_checks_impl::LogStreamer<>() \
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
::rtc::webrtc_checks_impl::LogStreamer<>()
(condition) ? static_cast<void>(0) \
: true ? ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
"") & \
::rtc::webrtc_checks_impl::LogStreamer<>() \
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
::rtc::webrtc_checks_impl::LogStreamer<>()
#define RTC_CHECK_OP(name, op, val1, val2) \
::rtc::Safe##name((val1), (val2)) \
? static_cast<void>(0) \
: true ? ::rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__, \
__LINE__, "") & \
::rtc::webrtc_checks_impl::LogStreamer<>() \
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
::rtc::webrtc_checks_impl::LogStreamer<>()
::rtc::Safe##name((val1), (val2)) ? static_cast<void>(0) \
: true ? ::rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__, __LINE__, \
"") & \
::rtc::webrtc_checks_impl::LogStreamer<>() \
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
::rtc::webrtc_checks_impl::LogStreamer<>()
#endif
#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2)
@ -428,10 +456,17 @@ class FatalLogCall final {
#endif
#define RTC_UNREACHABLE_CODE_HIT false
#define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
#define RTC_DCHECK_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
// TODO(bugs.webrtc.org/8454): Add an RTC_ prefix or rename differently.
#define FATAL() \
// Kills the process with an error message. Never returns. Use when you wish to
// assert that a point in the code is never reached.
#define RTC_CHECK_NOTREACHED() \
do { \
::rtc::webrtc_checks_impl::UnreachableCodeReached( \
RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS); \
} while (0)
#define RTC_FATAL() \
::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
"FATAL()") & \
::rtc::webrtc_checks_impl::LogStreamer<>()

View File

@ -0,0 +1,56 @@
# Copyright (c) 2021 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.
import("../../webrtc.gni")
rtc_library("flat_containers_internal") {
sources = [
"flat_tree.cc",
"flat_tree.h",
"identity.h",
"invoke.h",
"move_only_int.h",
]
deps = [
"..:checks",
"../system:no_unique_address",
]
absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ]
visibility = [ ":*" ]
}
rtc_source_set("flat_set") {
sources = [ "flat_set.h" ]
deps = [ ":flat_containers_internal" ]
}
rtc_source_set("flat_map") {
sources = [ "flat_map.h" ]
deps = [
":flat_containers_internal",
"..:checks",
]
}
rtc_library("unittests") {
testonly = true
sources = [
"flat_map_unittest.cc",
"flat_set_unittest.cc",
"flat_tree_unittest.cc",
]
deps = [
":flat_containers_internal",
":flat_map",
":flat_set",
"../../test:test_support",
"//testing/gmock:gmock",
"//testing/gtest:gtest",
]
absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ]
}

View File

@ -0,0 +1,178 @@
/*
* Copyright (c) 2021 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.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_FLAT_SET_H_
#define RTC_BASE_CONTAINERS_FLAT_SET_H_
#include <functional>
#include <vector>
#include "rtc_base/containers/flat_tree.h" // IWYU pragma: export
#include "rtc_base/containers/identity.h"
namespace webrtc {
// flat_set is a container with a std::set-like interface that stores its
// contents in a sorted container, by default a vector.
//
// Its implementation mostly tracks the corresponding standardization proposal
// https://wg21.link/P1222.
//
//
// PROS
//
// - Good memory locality.
// - Low overhead, especially for smaller sets.
// - Performance is good for more workloads than you might expect (see
// //base/containers/README.md in Chromium repository)
// - Supports C++14 set interface.
//
// CONS
//
// - Inserts and removals are O(n).
//
// IMPORTANT NOTES
//
// - Iterators are invalidated across mutations.
// - If possible, construct a flat_set in one operation by inserting into
// a container and moving that container into the flat_set constructor.
// - For multiple removals use base::EraseIf() which is O(n) rather than
// O(n * removed_items).
//
// QUICK REFERENCE
//
// Most of the core functionality is inherited from flat_tree. Please see
// flat_tree.h for more details for most of these functions. As a quick
// reference, the functions available are:
//
// Constructors (inputs need not be sorted):
// flat_set(const flat_set&);
// flat_set(flat_set&&);
// flat_set(InputIterator first, InputIterator last,
// const Compare& compare = Compare());
// flat_set(const container_type& items,
// const Compare& compare = Compare());
// flat_set(container_type&& items,
// const Compare& compare = Compare()); // Re-use storage.
// flat_set(std::initializer_list<value_type> ilist,
// const Compare& comp = Compare());
//
// Constructors (inputs need to be sorted):
// flat_set(sorted_unique_t,
// InputIterator first, InputIterator last,
// const Compare& compare = Compare());
// flat_set(sorted_unique_t,
// const container_type& items,
// const Compare& compare = Compare());
// flat_set(sorted_unique_t,
// container_type&& items,
// const Compare& compare = Compare()); // Re-use storage.
// flat_set(sorted_unique_t,
// std::initializer_list<value_type> ilist,
// const Compare& comp = Compare());
//
// Assignment functions:
// flat_set& operator=(const flat_set&);
// flat_set& operator=(flat_set&&);
// flat_set& operator=(initializer_list<Key>);
//
// Memory management functions:
// void reserve(size_t);
// size_t capacity() const;
// void shrink_to_fit();
//
// Size management functions:
// void clear();
// size_t size() const;
// size_t max_size() const;
// bool empty() const;
//
// Iterator functions:
// iterator begin();
// const_iterator begin() const;
// const_iterator cbegin() const;
// iterator end();
// const_iterator end() const;
// const_iterator cend() const;
// reverse_iterator rbegin();
// const reverse_iterator rbegin() const;
// const_reverse_iterator crbegin() const;
// reverse_iterator rend();
// const_reverse_iterator rend() const;
// const_reverse_iterator crend() const;
//
// Insert and accessor functions:
// pair<iterator, bool> insert(const key_type&);
// pair<iterator, bool> insert(key_type&&);
// void insert(InputIterator first, InputIterator last);
// iterator insert(const_iterator hint, const key_type&);
// iterator insert(const_iterator hint, key_type&&);
// pair<iterator, bool> emplace(Args&&...);
// iterator emplace_hint(const_iterator, Args&&...);
//
// Underlying type functions:
// container_type extract() &&;
// void replace(container_type&&);
//
// Erase functions:
// iterator erase(iterator);
// iterator erase(const_iterator);
// iterator erase(const_iterator first, const_iterator& last);
// template <typename K> size_t erase(const K& key);
//
// Comparators (see std::set documentation).
// key_compare key_comp() const;
// value_compare value_comp() const;
//
// Search functions:
// template <typename K> size_t count(const K&) const;
// template <typename K> iterator find(const K&);
// template <typename K> const_iterator find(const K&) const;
// template <typename K> bool contains(const K&) const;
// template <typename K> pair<iterator, iterator> equal_range(K&);
// template <typename K> iterator lower_bound(const K&);
// template <typename K> const_iterator lower_bound(const K&) const;
// template <typename K> iterator upper_bound(const K&);
// template <typename K> const_iterator upper_bound(const K&) const;
//
// General functions:
// void swap(flat_set&);
//
// Non-member operators:
// bool operator==(const flat_set&, const flat_set);
// bool operator!=(const flat_set&, const flat_set);
// bool operator<(const flat_set&, const flat_set);
// bool operator>(const flat_set&, const flat_set);
// bool operator>=(const flat_set&, const flat_set);
// bool operator<=(const flat_set&, const flat_set);
//
template <class Key,
class Compare = std::less<>,
class Container = std::vector<Key>>
using flat_set = typename ::webrtc::flat_containers_internal::
flat_tree<Key, webrtc::identity, Compare, Container>;
// ----------------------------------------------------------------------------
// General operations.
// Erases all elements that match predicate. It has O(size) complexity.
//
// flat_set<int> numbers;
// ...
// EraseIf(numbers, [](int number) { return number % 2 == 1; });
// NOLINTNEXTLINE(misc-unused-using-decls)
using ::webrtc::flat_containers_internal::EraseIf;
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_FLAT_SET_H_

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2021 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
@ -8,22 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/synchronization/rw_lock_wrapper.h"
// This implementation is borrowed from Chromium.
#if defined(_WIN32)
#include "rtc_base/synchronization/rw_lock_win.h"
#else
#include "rtc_base/synchronization/rw_lock_posix.h"
#endif
#include "rtc_base/containers/flat_tree.h"
namespace webrtc {
RWLockWrapper* RWLockWrapper::CreateRWLock() {
#ifdef _WIN32
return RWLockWin::Create();
#else
return RWLockPosix::Create();
#endif
}
sorted_unique_t sorted_unique;
} // namespace webrtc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2021 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.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_IDENTITY_H_
#define RTC_BASE_CONTAINERS_IDENTITY_H_
#include <utility>
namespace webrtc {
// Implementation of C++20's std::identity.
//
// Reference:
// - https://en.cppreference.com/w/cpp/utility/functional/identity
// - https://wg21.link/func.identity
struct identity {
template <typename T>
constexpr T&& operator()(T&& t) const noexcept {
return std::forward<T>(t);
}
using is_transparent = void;
};
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_IDENTITY_H_

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_DEPRECATION_H_
#define RTC_BASE_DEPRECATION_H_
// Annotate the declarations of deprecated functions with this to cause a
// compiler warning when they're used. Like so:
//
// RTC_DEPRECATED std::pony PonyPlz(const std::pony_spec& ps);
//
// NOTE 1: The annotation goes on the declaration in the .h file, not the
// definition in the .cc file!
//
// NOTE 2: In order to keep unit testing the deprecated function without
// getting warnings, do something like this:
//
// std::pony DEPRECATED_PonyPlz(const std::pony_spec& ps);
// RTC_DEPRECATED inline std::pony PonyPlz(const std::pony_spec& ps) {
// return DEPRECATED_PonyPlz(ps);
// }
//
// In other words, rename the existing function, and provide an inline wrapper
// using the original name that calls it. That way, callers who are willing to
// call it using the DEPRECATED_-prefixed name don't get the warning.
//
// TODO(kwiberg): Remove this when we can use [[deprecated]] from C++14.
#if defined(_MSC_VER)
// Note: Deprecation warnings seem to fail to trigger on Windows
// (https://bugs.chromium.org/p/webrtc/issues/detail?id=5368).
#define RTC_DEPRECATED __declspec(deprecated)
#elif defined(__GNUC__)
#define RTC_DEPRECATED __attribute__((__deprecated__))
#else
#define RTC_DEPRECATED
#endif
#endif // RTC_BASE_DEPRECATION_H_

View File

@ -25,9 +25,12 @@
#include "rtc_base/checks.h"
#include "rtc_base/synchronization/yield_policy.h"
#include "rtc_base/system/warn_current_thread_is_deadlocked.h"
#include "rtc_base/time_utils.h"
namespace rtc {
using ::webrtc::TimeDelta;
Event::Event() : Event(false, false) {}
#if defined(WEBRTC_WIN)
@ -51,9 +54,12 @@ void Event::Reset() {
ResetEvent(event_handle_);
}
bool Event::Wait(const int give_up_after_ms, int /*warn_after_ms*/) {
bool Event::Wait(TimeDelta give_up_after, TimeDelta /*warn_after*/) {
ScopedYieldPolicy::YieldExecution();
const DWORD ms = give_up_after_ms == kForever ? INFINITE : give_up_after_ms;
const DWORD ms =
give_up_after.IsPlusInfinity()
? INFINITE
: give_up_after.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms();
return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
}
@ -108,7 +114,7 @@ void Event::Reset() {
namespace {
timespec GetTimespec(const int milliseconds_from_now) {
timespec GetTimespec(TimeDelta duration_from_now) {
timespec ts;
// Get the current time.
@ -118,17 +124,19 @@ timespec GetTimespec(const int milliseconds_from_now) {
timeval tv;
gettimeofday(&tv, nullptr);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
ts.tv_nsec = tv.tv_usec * kNumNanosecsPerMicrosec;
#endif
// Add the specified number of milliseconds to it.
ts.tv_sec += (milliseconds_from_now / 1000);
ts.tv_nsec += (milliseconds_from_now % 1000) * 1000000;
int64_t microsecs_from_now = duration_from_now.us();
ts.tv_sec += microsecs_from_now / kNumMicrosecsPerSec;
ts.tv_nsec +=
(microsecs_from_now % kNumMicrosecsPerSec) * kNumNanosecsPerMicrosec;
// Normalize.
if (ts.tv_nsec >= 1000000000) {
if (ts.tv_nsec >= kNumNanosecsPerSec) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
ts.tv_nsec -= kNumNanosecsPerSec;
}
return ts;
@ -136,22 +144,21 @@ timespec GetTimespec(const int milliseconds_from_now) {
} // namespace
bool Event::Wait(const int give_up_after_ms, const int warn_after_ms) {
bool Event::Wait(TimeDelta give_up_after, TimeDelta warn_after) {
// Instant when we'll log a warning message (because we've been waiting so
// long it might be a bug), but not yet give up waiting. nullopt if we
// shouldn't log a warning.
const absl::optional<timespec> warn_ts =
warn_after_ms == kForever ||
(give_up_after_ms != kForever && warn_after_ms > give_up_after_ms)
warn_after >= give_up_after
? absl::nullopt
: absl::make_optional(GetTimespec(warn_after_ms));
: absl::make_optional(GetTimespec(warn_after));
// Instant when we'll stop waiting and return an error. nullopt if we should
// never give up.
const absl::optional<timespec> give_up_ts =
give_up_after_ms == kForever
give_up_after.IsPlusInfinity()
? absl::nullopt
: absl::make_optional(GetTimespec(give_up_after_ms));
: absl::make_optional(GetTimespec(give_up_after));
ScopedYieldPolicy::YieldExecution();
pthread_mutex_lock(&event_mutex_);

View File

@ -11,6 +11,8 @@
#ifndef RTC_BASE_EVENT_H_
#define RTC_BASE_EVENT_H_
#include "api/units/time_delta.h"
#if defined(WEBRTC_WIN)
#include <windows.h>
#elif defined(WEBRTC_POSIX)
@ -19,11 +21,43 @@
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
#endif
#include "rtc_base/synchronization/yield_policy.h"
namespace rtc {
// RTC_DISALLOW_WAIT() utility
//
// Sets a stack-scoped flag that disallows use of `rtc::Event::Wait` by means
// of raising a DCHECK when a call to `rtc::Event::Wait()` is made..
// This is useful to guard synchronization-free scopes against regressions.
//
// Example of what this would catch (`ScopeToProtect` calls `Foo`):
//
// void Foo(TaskQueue* tq) {
// Event event;
// tq->PostTask([&event]() {
// event.Set();
// });
// event.Wait(Event::kForever); // <- Will trigger a DCHECK.
// }
//
// void ScopeToProtect() {
// TaskQueue* tq = GetSomeTaskQueue();
// RTC_DISALLOW_WAIT(); // Policy takes effect.
// Foo(tq);
// }
//
#if RTC_DCHECK_IS_ON
#define RTC_DISALLOW_WAIT() ScopedDisallowWait disallow_wait_##__LINE__
#else
#define RTC_DISALLOW_WAIT()
#endif
class Event {
public:
static const int kForever = -1;
// TODO(bugs.webrtc.org/14366): Consider removing this redundant alias.
static constexpr webrtc::TimeDelta kForever =
webrtc::TimeDelta::PlusInfinity();
Event();
Event(bool manual_reset, bool initially_signaled);
@ -35,19 +69,22 @@ class Event {
void Reset();
// Waits for the event to become signaled, but logs a warning if it takes more
// than `warn_after_ms` milliseconds, and gives up completely if it takes more
// than `give_up_after_ms` milliseconds. (If `warn_after_ms >=
// give_up_after_ms`, no warning will be logged.) Either or both may be
// `kForever`, which means wait indefinitely.
// than `warn_after`, and gives up completely if it takes more than
// `give_up_after`. (If `warn_after >= give_up_after`, no warning will be
// logged.) Either or both may be `kForever`, which means wait indefinitely.
//
// Care is taken so that the underlying OS wait call isn't requested to sleep
// shorter than `give_up_after`.
//
// Returns true if the event was signaled, false if there was a timeout or
// some other error.
bool Wait(int give_up_after_ms, int warn_after_ms);
bool Wait(webrtc::TimeDelta give_up_after, webrtc::TimeDelta warn_after);
// Waits with the given timeout and a reasonable default warning timeout.
bool Wait(int give_up_after_ms) {
return Wait(give_up_after_ms,
give_up_after_ms == kForever ? 3000 : kForever);
bool Wait(webrtc::TimeDelta give_up_after) {
return Wait(give_up_after, give_up_after.IsPlusInfinity()
? webrtc::TimeDelta::Seconds(3)
: kForever);
}
private:
@ -81,6 +118,20 @@ class ScopedAllowBaseSyncPrimitivesForTesting {
~ScopedAllowBaseSyncPrimitivesForTesting() {}
};
#if RTC_DCHECK_IS_ON
class ScopedDisallowWait {
public:
ScopedDisallowWait() = default;
private:
class DisallowYieldHandler : public YieldInterface {
public:
void YieldExecution() override { RTC_DCHECK_NOTREACHED(); }
} handler_;
rtc::ScopedYieldPolicy policy{&handler_};
};
#endif
} // namespace rtc
#endif // RTC_BASE_EVENT_H_

View File

@ -14,10 +14,12 @@
#include <stdio.h>
#include <string.h>
#include <atomic>
#include <string>
#include <vector>
#include "rtc_base/atomic_ops.h"
#include "absl/strings/string_view.h"
#include "api/sequence_checker.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
#include "rtc_base/logging.h"
@ -25,7 +27,6 @@
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/thread_annotations.h"
#include "rtc_base/thread_checker.h"
#include "rtc_base/time_utils.h"
#include "rtc_base/trace_event.h"
@ -79,19 +80,12 @@ namespace rtc {
namespace tracing {
namespace {
static void EventTracingThreadFunc(void* params);
// Atomic-int fast path for avoiding logging when disabled.
static volatile int g_event_logging_active = 0;
static std::atomic<int> g_event_logging_active(0);
// TODO(pbos): Log metadata for all threads, etc.
class EventLogger final {
public:
EventLogger()
: logging_thread_(EventTracingThreadFunc,
this,
"EventTracingThread",
kLowPriority) {}
~EventLogger() { RTC_DCHECK(thread_checker_.IsCurrent()); }
void AddTraceEvent(const char* name,
@ -129,11 +123,12 @@ class EventLogger final {
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
void Log() {
RTC_DCHECK(output_file_);
static const int kLoggingIntervalMs = 100;
static constexpr webrtc::TimeDelta kLoggingInterval =
webrtc::TimeDelta::Millis(100);
fprintf(output_file_, "{ \"traceEvents\": [\n");
bool has_logged_event = false;
while (true) {
bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs);
bool shutting_down = shutdown_event_.Wait(kLoggingInterval);
std::vector<TraceEvent> events;
{
webrtc::MutexLock lock(&mutex_);
@ -205,11 +200,12 @@ class EventLogger final {
}
// Enable event logging (fast-path). This should be disabled since starting
// shouldn't be done twice.
RTC_CHECK_EQ(0,
rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 0, 1));
int zero = 0;
RTC_CHECK(g_event_logging_active.compare_exchange_strong(zero, 1));
// Finally start, everything should be set up now.
logging_thread_.Start();
logging_thread_ =
PlatformThread::SpawnJoinable([this] { Log(); }, "EventTracingThread");
TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start");
}
@ -217,13 +213,14 @@ class EventLogger final {
RTC_DCHECK(thread_checker_.IsCurrent());
TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Stop");
// Try to stop. Abort if we're not currently logging.
if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0)
int one = 1;
if (g_event_logging_active.compare_exchange_strong(one, 0))
return;
// Wake up logging thread to finish writing.
shutdown_event_.Set();
// Join the logging thread.
logging_thread_.Stop();
logging_thread_.Finalize();
}
private:
@ -321,16 +318,12 @@ class EventLogger final {
std::vector<TraceEvent> trace_events_ RTC_GUARDED_BY(mutex_);
rtc::PlatformThread logging_thread_;
rtc::Event shutdown_event_;
rtc::ThreadChecker thread_checker_;
webrtc::SequenceChecker thread_checker_;
FILE* output_file_ = nullptr;
bool output_file_owned_ = false;
};
static void EventTracingThreadFunc(void* params) {
static_cast<EventLogger*>(params)->Log();
}
static EventLogger* volatile g_event_logger = nullptr;
static std::atomic<EventLogger*> g_event_logger(nullptr);
static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT("");
const unsigned char* InternalGetCategoryEnabled(const char* name) {
const char* prefix_ptr = &kDisabledTracePrefix[0];
@ -344,6 +337,10 @@ const unsigned char* InternalGetCategoryEnabled(const char* name) {
: name);
}
const unsigned char* InternalEnableAllCategories(const char* name) {
return reinterpret_cast<const unsigned char*>(name);
}
void InternalAddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
@ -354,56 +351,59 @@ void InternalAddTraceEvent(char phase,
const unsigned long long* arg_values,
unsigned char flags) {
// Fast path for when event tracing is inactive.
if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0)
if (g_event_logging_active.load() == 0)
return;
g_event_logger->AddTraceEvent(name, category_enabled, phase, num_args,
arg_names, arg_types, arg_values,
rtc::TimeMicros(), 1, rtc::CurrentThreadId());
g_event_logger.load()->AddTraceEvent(
name, category_enabled, phase, num_args, arg_names, arg_types, arg_values,
rtc::TimeMicros(), 1, rtc::CurrentThreadId());
}
} // namespace
void SetupInternalTracer() {
RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
&g_event_logger, static_cast<EventLogger*>(nullptr),
new EventLogger()) == nullptr);
webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent);
void SetupInternalTracer(bool enable_all_categories) {
EventLogger* null_logger = nullptr;
RTC_CHECK(
g_event_logger.compare_exchange_strong(null_logger, new EventLogger()));
webrtc::SetupEventTracer(enable_all_categories ? InternalEnableAllCategories
: InternalGetCategoryEnabled,
InternalAddTraceEvent);
}
void StartInternalCaptureToFile(FILE* file) {
if (g_event_logger) {
g_event_logger->Start(file, false);
EventLogger* event_logger = g_event_logger.load();
if (event_logger) {
event_logger->Start(file, false);
}
}
bool StartInternalCapture(const char* filename) {
if (!g_event_logger)
bool StartInternalCapture(absl::string_view filename) {
EventLogger* event_logger = g_event_logger.load();
if (!event_logger)
return false;
FILE* file = fopen(filename, "w");
FILE* file = fopen(std::string(filename).c_str(), "w");
if (!file) {
RTC_LOG(LS_ERROR) << "Failed to open trace file '" << filename
<< "' for writing.";
return false;
}
g_event_logger->Start(file, true);
event_logger->Start(file, true);
return true;
}
void StopInternalCapture() {
if (g_event_logger) {
g_event_logger->Stop();
EventLogger* event_logger = g_event_logger.load();
if (event_logger) {
event_logger->Stop();
}
}
void ShutdownInternalTracer() {
StopInternalCapture();
EventLogger* old_logger = rtc::AtomicOps::AcquireLoadPtr(&g_event_logger);
EventLogger* old_logger = g_event_logger.load(std::memory_order_acquire);
RTC_DCHECK(old_logger);
RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
&g_event_logger, old_logger,
static_cast<EventLogger*>(nullptr)) == old_logger);
RTC_CHECK(g_event_logger.compare_exchange_strong(old_logger, nullptr));
delete old_logger;
webrtc::SetupEventTracer(nullptr, nullptr);
}

View File

@ -28,6 +28,9 @@
#include <stdio.h>
#include "absl/strings/string_view.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name);
@ -70,12 +73,12 @@ class EventTracer {
namespace rtc {
namespace tracing {
// Set up internal event tracer.
void SetupInternalTracer();
bool StartInternalCapture(const char* filename);
void StartInternalCaptureToFile(FILE* file);
void StopInternalCapture();
RTC_EXPORT void SetupInternalTracer(bool enable_all_categories = true);
RTC_EXPORT bool StartInternalCapture(absl::string_view filename);
RTC_EXPORT void StartInternalCaptureToFile(FILE* file);
RTC_EXPORT void StopInternalCapture();
// Make sure we run this, this will tear down the internal tracing.
void ShutdownInternalTracer();
RTC_EXPORT void ShutdownInternalTracer();
} // namespace tracing
} // namespace rtc

View File

@ -16,21 +16,15 @@
#include <type_traits>
#include <utility>
#include "absl/strings/string_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
namespace {
int FindOrEnd(std::string str, size_t start, char delimiter) {
size_t pos = str.find(delimiter, start);
pos = (pos == std::string::npos) ? str.length() : pos;
return static_cast<int>(pos);
}
} // namespace
FieldTrialParameterInterface::FieldTrialParameterInterface(std::string key)
FieldTrialParameterInterface::FieldTrialParameterInterface(
absl::string_view key)
: key_(key) {}
FieldTrialParameterInterface::~FieldTrialParameterInterface() {
RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_
@ -39,8 +33,8 @@ FieldTrialParameterInterface::~FieldTrialParameterInterface() {
void ParseFieldTrial(
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string trial_string) {
std::map<std::string, FieldTrialParameterInterface*> field_map;
absl::string_view trial_string) {
std::map<absl::string_view, FieldTrialParameterInterface*> field_map;
FieldTrialParameterInterface* keyless_field = nullptr;
for (FieldTrialParameterInterface* field : fields) {
field->MarkAsUsed();
@ -60,18 +54,29 @@ void ParseFieldTrial(
field_map[field->key_] = field;
}
}
bool logged_unknown_key = false;
size_t i = 0;
while (i < trial_string.length()) {
int val_end = FindOrEnd(trial_string, i, ',');
int colon_pos = FindOrEnd(trial_string, i, ':');
int key_end = std::min(val_end, colon_pos);
int val_begin = key_end + 1;
std::string key = trial_string.substr(i, key_end - i);
absl::string_view tail = trial_string;
while (!tail.empty()) {
size_t key_end = tail.find_first_of(",:");
absl::string_view key = tail.substr(0, key_end);
absl::optional<std::string> opt_value;
if (val_end >= val_begin)
opt_value = trial_string.substr(val_begin, val_end - val_begin);
i = val_end + 1;
if (key_end == absl::string_view::npos) {
tail = "";
} else if (tail[key_end] == ':') {
tail = tail.substr(key_end + 1);
size_t value_end = tail.find(',');
opt_value.emplace(tail.substr(0, value_end));
if (value_end == absl::string_view::npos) {
tail = "";
} else {
tail = tail.substr(value_end + 1);
}
} else {
RTC_DCHECK_EQ(tail[key_end], ',');
tail = tail.substr(key_end + 1);
}
auto field = field_map.find(key);
if (field != field_map.end()) {
if (!field->second->Parse(std::move(opt_value))) {
@ -79,19 +84,25 @@ void ParseFieldTrial(
<< "' in trial: \"" << trial_string << "\"";
}
} else if (!opt_value && keyless_field && !key.empty()) {
if (!keyless_field->Parse(key)) {
if (!keyless_field->Parse(std::string(key))) {
RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '"
<< key << "' in trial: \"" << trial_string << "\"";
}
} else {
RTC_LOG(LS_INFO) << "No field with key: '" << key
<< "' (found in trial: \"" << trial_string << "\")";
std::string valid_keys;
for (const auto& f : field_map) {
valid_keys += f.first;
valid_keys += ", ";
} else if (key.empty() || key[0] != '_') {
// "_" is be used to prefix keys that are part of the string for
// debugging purposes but not neccessarily used.
// e.g. WebRTC-Experiment/param: value, _DebuggingString
if (!logged_unknown_key) {
RTC_LOG(LS_INFO) << "No field with key: '" << key
<< "' (found in trial: \"" << trial_string << "\")";
std::string valid_keys;
for (const auto& f : field_map) {
valid_keys.append(f.first.data(), f.first.size());
valid_keys += ", ";
}
RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys;
logged_unknown_key = true;
}
RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys;
}
}
@ -101,7 +112,7 @@ void ParseFieldTrial(
}
template <>
absl::optional<bool> ParseTypedParameter<bool>(std::string str) {
absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str) {
if (str == "true" || str == "1") {
return true;
} else if (str == "false" || str == "0") {
@ -111,10 +122,10 @@ absl::optional<bool> ParseTypedParameter<bool>(std::string str) {
}
template <>
absl::optional<double> ParseTypedParameter<double>(std::string str) {
absl::optional<double> ParseTypedParameter<double>(absl::string_view str) {
double value;
char unit[2]{0, 0};
if (sscanf(str.c_str(), "%lf%1s", &value, unit) >= 1) {
if (sscanf(std::string(str).c_str(), "%lf%1s", &value, unit) >= 1) {
if (unit[0] == '%')
return value / 100;
return value;
@ -124,9 +135,9 @@ absl::optional<double> ParseTypedParameter<double>(std::string str) {
}
template <>
absl::optional<int> ParseTypedParameter<int>(std::string str) {
absl::optional<int> ParseTypedParameter<int>(absl::string_view str) {
int64_t value;
if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) {
if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) {
return static_cast<int>(value);
}
@ -135,9 +146,9 @@ absl::optional<int> ParseTypedParameter<int>(std::string str) {
}
template <>
absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str) {
absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str) {
int64_t value;
if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) {
if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) {
return static_cast<unsigned>(value);
}
@ -146,34 +157,36 @@ absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str) {
}
template <>
absl::optional<std::string> ParseTypedParameter<std::string>(std::string str) {
return std::move(str);
absl::optional<std::string> ParseTypedParameter<std::string>(
absl::string_view str) {
return std::string(str);
}
template <>
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
std::string str) {
absl::string_view str) {
return ParseOptionalParameter<bool>(str);
}
template <>
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
std::string str) {
absl::string_view str) {
return ParseOptionalParameter<int>(str);
}
template <>
absl::optional<absl::optional<unsigned>>
ParseTypedParameter<absl::optional<unsigned>>(std::string str) {
ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str) {
return ParseOptionalParameter<unsigned>(str);
}
template <>
absl::optional<absl::optional<double>>
ParseTypedParameter<absl::optional<double>>(std::string str) {
ParseTypedParameter<absl::optional<double>>(absl::string_view str) {
return ParseOptionalParameter<double>(str);
}
FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {}
FieldTrialFlag::FieldTrialFlag(absl::string_view key)
: FieldTrialFlag(key, false) {}
FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value)
FieldTrialFlag::FieldTrialFlag(absl::string_view key, bool default_value)
: FieldTrialParameterInterface(key), value_(default_value) {}
bool FieldTrialFlag::Get() const {
@ -198,7 +211,7 @@ bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
}
AbstractFieldTrialEnum::AbstractFieldTrialEnum(
std::string key,
absl::string_view key,
int default_value,
std::map<std::string, int> mapping)
: FieldTrialParameterInterface(key),

View File

@ -18,6 +18,7 @@
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
// Field trial parser functionality. Provides funcitonality to parse field trial
@ -45,10 +46,10 @@ class FieldTrialParameterInterface {
FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
default;
explicit FieldTrialParameterInterface(std::string key);
explicit FieldTrialParameterInterface(absl::string_view key);
friend void ParseFieldTrial(
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string raw_string);
absl::string_view trial_string);
void MarkAsUsed() { used_ = true; }
virtual bool Parse(absl::optional<std::string> str_value) = 0;
@ -65,19 +66,19 @@ class FieldTrialParameterInterface {
// with extracted values if available.
void ParseFieldTrial(
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string raw_string);
absl::string_view trial_string);
// Specialize this in code file for custom types. Should return absl::nullopt if
// the given string cannot be properly parsed.
template <typename T>
absl::optional<T> ParseTypedParameter(std::string);
absl::optional<T> ParseTypedParameter(absl::string_view);
// This class uses the ParseTypedParameter function to implement a parameter
// implementation with an enforced default value.
template <typename T>
class FieldTrialParameter : public FieldTrialParameterInterface {
public:
FieldTrialParameter(std::string key, T default_value)
FieldTrialParameter(absl::string_view key, T default_value)
: FieldTrialParameterInterface(key), value_(default_value) {}
T Get() const { return value_; }
operator T() const { return Get(); }
@ -107,7 +108,7 @@ class FieldTrialParameter : public FieldTrialParameterInterface {
template <typename T>
class FieldTrialConstrained : public FieldTrialParameterInterface {
public:
FieldTrialConstrained(std::string key,
FieldTrialConstrained(absl::string_view key,
T default_value,
absl::optional<T> lower_limit,
absl::optional<T> upper_limit)
@ -140,7 +141,7 @@ class FieldTrialConstrained : public FieldTrialParameterInterface {
class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
public:
AbstractFieldTrialEnum(std::string key,
AbstractFieldTrialEnum(absl::string_view key,
int default_value,
std::map<std::string, int> mapping);
~AbstractFieldTrialEnum() override;
@ -161,7 +162,7 @@ class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
template <typename T>
class FieldTrialEnum : public AbstractFieldTrialEnum {
public:
FieldTrialEnum(std::string key,
FieldTrialEnum(absl::string_view key,
T default_value,
std::map<std::string, T> mapping)
: AbstractFieldTrialEnum(key,
@ -184,9 +185,9 @@ class FieldTrialEnum : public AbstractFieldTrialEnum {
template <typename T>
class FieldTrialOptional : public FieldTrialParameterInterface {
public:
explicit FieldTrialOptional(std::string key)
explicit FieldTrialOptional(absl::string_view key)
: FieldTrialParameterInterface(key) {}
FieldTrialOptional(std::string key, absl::optional<T> default_value)
FieldTrialOptional(absl::string_view key, absl::optional<T> default_value)
: FieldTrialParameterInterface(key), value_(default_value) {}
absl::optional<T> GetOptional() const { return value_; }
const T& Value() const { return value_.value(); }
@ -216,10 +217,10 @@ class FieldTrialOptional : public FieldTrialParameterInterface {
// explicit value is provided, the flag evaluates to true.
class FieldTrialFlag : public FieldTrialParameterInterface {
public:
explicit FieldTrialFlag(std::string key);
FieldTrialFlag(std::string key, bool default_value);
explicit FieldTrialFlag(absl::string_view key);
FieldTrialFlag(absl::string_view key, bool default_value);
bool Get() const;
operator bool() const;
explicit operator bool() const;
protected:
bool Parse(absl::optional<std::string> str_value) override;
@ -229,7 +230,8 @@ class FieldTrialFlag : public FieldTrialParameterInterface {
};
template <typename T>
absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) {
absl::optional<absl::optional<T>> ParseOptionalParameter(
absl::string_view str) {
if (str.empty())
return absl::optional<T>();
auto parsed = ParseTypedParameter<T>(str);
@ -239,28 +241,29 @@ absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) {
}
template <>
absl::optional<bool> ParseTypedParameter<bool>(std::string str);
absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str);
template <>
absl::optional<double> ParseTypedParameter<double>(std::string str);
absl::optional<double> ParseTypedParameter<double>(absl::string_view str);
template <>
absl::optional<int> ParseTypedParameter<int>(std::string str);
absl::optional<int> ParseTypedParameter<int>(absl::string_view str);
template <>
absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str);
absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str);
template <>
absl::optional<std::string> ParseTypedParameter<std::string>(std::string str);
absl::optional<std::string> ParseTypedParameter<std::string>(
absl::string_view str);
template <>
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
std::string str);
absl::string_view str);
template <>
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
std::string str);
absl::string_view str);
template <>
absl::optional<absl::optional<unsigned>>
ParseTypedParameter<absl::optional<unsigned>>(std::string str);
ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str);
template <>
absl::optional<absl::optional<double>>
ParseTypedParameter<absl::optional<double>>(std::string str);
ParseTypedParameter<absl::optional<double>>(absl::string_view str);
// Accepts true, false, else parsed with sscanf %i, true if != 0.
extern template class FieldTrialParameter<bool>;

View File

@ -15,7 +15,6 @@
#if RTC_LOG_ENABLED()
#if defined(WEBRTC_WIN)
#include <winsock2.h>
#include <windows.h>
#if _MSC_VER < 1900
#define snprintf _snprintf
@ -43,6 +42,8 @@ static const int kMaxLogLineSize = 1024 - 60;
#include <vector>
#include "absl/base/attributes.h"
#include "absl/strings/string_view.h"
#include "api/units/timestamp.h"
#include "rtc_base/checks.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/string_encode.h"
@ -54,15 +55,18 @@ static const int kMaxLogLineSize = 1024 - 60;
namespace rtc {
namespace {
// By default, release builds don't log, debug builds at info level
#if !defined(NDEBUG)
static LoggingSeverity g_min_sev = LS_INFO;
static LoggingSeverity g_dbg_sev = LS_INFO;
constexpr LoggingSeverity kDefaultLoggingSeverity = LS_INFO;
#else
static LoggingSeverity g_min_sev = LS_NONE;
static LoggingSeverity g_dbg_sev = LS_NONE;
constexpr LoggingSeverity kDefaultLoggingSeverity = LS_NONE;
#endif
// Note: `g_min_sev` and `g_dbg_sev` can be changed while running.
LoggingSeverity g_min_sev = kDefaultLoggingSeverity;
LoggingSeverity g_dbg_sev = kDefaultLoggingSeverity;
// Return the filename portion of the string (that following the last slash).
const char* FilenameFromPath(const char* file) {
const char* end1 = ::strrchr(file, '/');
@ -74,11 +78,38 @@ const char* FilenameFromPath(const char* file) {
}
// Global lock for log subsystem, only needed to serialize access to streams_.
// TODO(bugs.webrtc.org/11665): this is not currently constant initialized and
// trivially destructible.
webrtc::Mutex g_log_mutex_;
webrtc::Mutex& GetLoggingLock() {
static webrtc::Mutex& mutex = *new webrtc::Mutex();
return mutex;
}
} // namespace
std::string LogLineRef::DefaultLogLine() const {
rtc::StringBuilder log_output;
if (timestamp_ != webrtc::Timestamp::MinusInfinity()) {
// TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
char timestamp[50]; // Maximum string length of an int64_t is 20.
int len =
snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
timestamp_.ms() / 1000, timestamp_.ms() % 1000);
RTC_DCHECK_LT(len, sizeof(timestamp));
log_output << timestamp;
}
if (thread_id_.has_value()) {
log_output << "[" << *thread_id_ << "] ";
}
if (!filename_.empty()) {
#if defined(WEBRTC_ANDROID)
log_output << "(line " << line_ << "): ";
#else
log_output << "(" << filename_ << ":" << line_ << "): ";
#endif
}
log_output << message_;
return log_output.Release();
}
/////////////////////////////////////////////////////////////////////////////
// LogMessage
/////////////////////////////////////////////////////////////////////////////
@ -89,12 +120,13 @@ 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_mutex_) =
ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(GetLoggingLock()) =
nullptr;
ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
// Boolean options default to false (0)
bool LogMessage::thread_, LogMessage::timestamp_;
// Boolean options default to false.
ABSL_CONST_INIT bool LogMessage::log_thread_ = false;
ABSL_CONST_INIT bool LogMessage::log_timestamp_ = false;
LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
: LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
@ -103,35 +135,28 @@ LogMessage::LogMessage(const char* file,
int line,
LoggingSeverity sev,
LogErrorContext err_ctx,
int err)
: severity_(sev) {
if (timestamp_) {
int err) {
log_line_.set_severity(sev);
if (log_timestamp_) {
int64_t log_start_time = LogStartTime();
// Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
// in log messages represents the real system time.
int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
int64_t time = TimeDiff(SystemTimeMillis(), log_start_time);
// Also ensure WallClockStartTime is initialized, so that it matches
// LogStartTime.
WallClockStartTime();
// TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
char timestamp[50]; // Maximum string length of an int64_t is 20.
int len =
snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
time / 1000, time % 1000);
RTC_DCHECK_LT(len, sizeof(timestamp));
print_stream_ << timestamp;
log_line_.set_timestamp(webrtc::Timestamp::Millis(time));
}
if (thread_) {
PlatformThreadId id = CurrentThreadId();
print_stream_ << "[" << id << "] ";
if (log_thread_) {
log_line_.set_thread_id(CurrentThreadId());
}
if (file != nullptr) {
log_line_.set_filename(FilenameFromPath(file));
log_line_.set_line(line);
#if defined(WEBRTC_ANDROID)
tag_ = FilenameFromPath(file);
print_stream_ << "(line " << line << "): ";
#else
print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
log_line_.set_tag(log_line_.filename());
#endif
}
@ -172,51 +197,32 @@ LogMessage::LogMessage(const char* file,
int line,
LoggingSeverity sev,
const char* tag)
: LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
tag_ = tag;
: LogMessage(file, line, sev, ERRCTX_NONE, /*err=*/0) {
log_line_.set_tag(tag);
print_stream_ << tag << ": ";
}
#endif
// DEPRECATED. Currently only used by downstream projects that use
// implementation details of logging.h. Work is ongoing to remove those
// dependencies.
LogMessage::LogMessage(const char* file,
int line,
LoggingSeverity sev,
const std::string& tag)
: LogMessage(file, line, sev) {
print_stream_ << tag << ": ";
}
LogMessage::~LogMessage() {
FinishPrintStream();
const std::string str = print_stream_.Release();
log_line_.set_message(print_stream_.Release());
if (severity_ >= g_dbg_sev) {
#if defined(WEBRTC_ANDROID)
OutputToDebug(str, severity_, tag_);
#else
OutputToDebug(str, severity_);
#endif
if (log_line_.severity() >= g_dbg_sev) {
OutputToDebug(log_line_);
}
webrtc::MutexLock lock(&g_log_mutex_);
webrtc::MutexLock lock(&GetLoggingLock());
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
if (severity_ >= entry->min_severity_) {
#if defined(WEBRTC_ANDROID)
entry->OnLogMessage(str, severity_, tag_);
#else
entry->OnLogMessage(str, severity_);
#endif
if (log_line_.severity() >= entry->min_severity_) {
entry->OnLogMessage(log_line_);
}
}
}
void LogMessage::AddTag(const char* tag) {
#ifdef WEBRTC_ANDROID
tag_ = tag;
log_line_.set_tag(tag);
#endif
}
@ -242,16 +248,16 @@ uint32_t LogMessage::WallClockStartTime() {
}
void LogMessage::LogThreads(bool on) {
thread_ = on;
log_thread_ = on;
}
void LogMessage::LogTimestamps(bool on) {
timestamp_ = on;
log_timestamp_ = on;
}
void LogMessage::LogToDebug(LoggingSeverity min_sev) {
g_dbg_sev = min_sev;
webrtc::MutexLock lock(&g_log_mutex_);
webrtc::MutexLock lock(&GetLoggingLock());
UpdateMinLogSeverity();
}
@ -260,7 +266,7 @@ void LogMessage::SetLogToStderr(bool log_to_stderr) {
}
int LogMessage::GetLogToStream(LogSink* stream) {
webrtc::MutexLock lock(&g_log_mutex_);
webrtc::MutexLock lock(&GetLoggingLock());
LoggingSeverity sev = LS_NONE;
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
if (stream == nullptr || stream == entry) {
@ -271,7 +277,7 @@ int LogMessage::GetLogToStream(LogSink* stream) {
}
void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
webrtc::MutexLock lock(&g_log_mutex_);
webrtc::MutexLock lock(&GetLoggingLock());
stream->min_severity_ = min_sev;
stream->next_ = streams_;
streams_ = stream;
@ -280,7 +286,7 @@ void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
}
void LogMessage::RemoveLogToStream(LogSink* stream) {
webrtc::MutexLock lock(&g_log_mutex_);
webrtc::MutexLock lock(&GetLoggingLock());
for (LogSink** entry = &streams_; *entry != nullptr;
entry = &(*entry)->next_) {
if (*entry == stream) {
@ -292,7 +298,7 @@ void LogMessage::RemoveLogToStream(LogSink* stream) {
UpdateMinLogSeverity();
}
void LogMessage::ConfigureLogging(const char* params) {
void LogMessage::ConfigureLogging(absl::string_view params) {
LoggingSeverity current_level = LS_VERBOSE;
LoggingSeverity debug_level = GetLogToDebug();
@ -342,7 +348,7 @@ void LogMessage::ConfigureLogging(const char* params) {
}
void LogMessage::UpdateMinLogSeverity()
RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) {
RTC_EXCLUSIVE_LOCKS_REQUIRED(GetLoggingLock()) {
LoggingSeverity min_sev = g_dbg_sev;
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
min_sev = std::min(min_sev, entry->min_severity_);
@ -350,46 +356,35 @@ void LogMessage::UpdateMinLogSeverity()
g_min_sev = min_sev;
}
#if defined(WEBRTC_ANDROID)
void LogMessage::OutputToDebug(const std::string& str,
LoggingSeverity severity,
const char* tag) {
#else
void LogMessage::OutputToDebug(const std::string& str,
LoggingSeverity severity) {
#endif
void LogMessage::OutputToDebug(const LogLineRef& log_line) {
std::string msg_str = log_line.DefaultLogLine();
bool log_to_stderr = log_to_stderr_;
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
// On the Mac, all stderr output goes to the Console log and causes clutter.
// So in opt builds, don't log to stderr unless the user specifically sets
// a preference to do so.
CFStringRef key = CFStringCreateWithCString(
kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
if (key != nullptr && domain != nullptr) {
if (domain != nullptr) {
Boolean exists_and_is_valid;
Boolean should_log =
CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
Boolean should_log = CFPreferencesGetAppBooleanValue(
CFSTR("logToStdErr"), domain, &exists_and_is_valid);
// If the key doesn't exist or is invalid or is false, we will not log to
// stderr.
log_to_stderr = exists_and_is_valid && should_log;
}
if (key != nullptr) {
CFRelease(key);
}
#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
#if defined(WEBRTC_WIN)
// Always log to the debugger.
// Perhaps stderr should be controlled by a preference, as on Mac?
OutputDebugStringA(str.c_str());
OutputDebugStringA(msg_str.c_str());
if (log_to_stderr) {
// This handles dynamically allocated consoles, too.
if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
log_to_stderr = false;
DWORD written = 0;
::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
&written, 0);
::WriteFile(error_handle, msg_str.c_str(),
static_cast<DWORD>(msg_str.size()), &written, 0);
}
}
#endif // WEBRTC_WIN
@ -400,7 +395,7 @@ void LogMessage::OutputToDebug(const std::string& str,
// Also write to stderr which maybe available to executable started
// from the shell.
int prio;
switch (severity) {
switch (log_line.severity()) {
case LS_VERBOSE:
prio = ANDROID_LOG_VERBOSE;
break;
@ -417,27 +412,29 @@ void LogMessage::OutputToDebug(const std::string& str,
prio = ANDROID_LOG_UNKNOWN;
}
int size = str.size();
int line = 0;
int size = msg_str.size();
int current_line = 0;
int idx = 0;
const int max_lines = size / kMaxLogLineSize + 1;
if (max_lines == 1) {
__android_log_print(prio, tag, "%.*s", size, str.c_str());
__android_log_print(prio, log_line.tag().data(), "%.*s", size,
msg_str.c_str());
} else {
while (size > 0) {
const int len = std::min(size, kMaxLogLineSize);
// Use the size of the string in the format (str may have \0 in the
// Use the size of the string in the format (msg may have \0 in the
// middle).
__android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
str.c_str() + idx);
__android_log_print(prio, log_line.tag().data(), "[%d/%d] %.*s",
current_line + 1, max_lines, len,
msg_str.c_str() + idx);
idx += len;
size -= len;
++line;
++current_line;
}
}
#endif // WEBRTC_ANDROID
if (log_to_stderr) {
fprintf(stderr, "%s", str.c_str());
fprintf(stderr, "%s", msg_str.c_str());
fflush(stderr);
}
}
@ -481,7 +478,7 @@ void Log(const LogArgType* fmt, ...) {
}
#endif
default: {
RTC_NOTREACHED();
RTC_DCHECK_NOTREACHED();
va_end(args);
return;
}
@ -535,7 +532,7 @@ void Log(const LogArgType* fmt, ...) {
reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
break;
default:
RTC_NOTREACHED();
RTC_DCHECK_NOTREACHED();
va_end(args);
return;
}
@ -549,6 +546,16 @@ void Log(const LogArgType* fmt, ...) {
#endif
namespace rtc {
// Default implementation, override is recomended.
void LogSink::OnLogMessage(const LogLineRef& log_line) {
#if defined(WEBRTC_ANDROID)
OnLogMessage(log_line.DefaultLogLine(), log_line.severity(),
log_line.tag().data());
#else
OnLogMessage(log_line.DefaultLogLine(), log_line.severity());
#endif
}
// Inefficient default implementation, override is recommended.
void LogSink::OnLogMessage(const std::string& msg,
LoggingSeverity severity,
@ -560,4 +567,20 @@ void LogSink::OnLogMessage(const std::string& msg,
LoggingSeverity /* severity */) {
OnLogMessage(msg);
}
// Inefficient default implementation, override is recommended.
void LogSink::OnLogMessage(absl::string_view msg,
LoggingSeverity severity,
const char* tag) {
OnLogMessage(tag + (": " + std::string(msg)), severity);
}
void LogSink::OnLogMessage(absl::string_view msg,
LoggingSeverity /* severity */) {
OnLogMessage(msg);
}
void LogSink::OnLogMessage(absl::string_view msg) {
OnLogMessage(std::string(msg));
}
} // namespace rtc

View File

@ -21,9 +21,13 @@
// RTC_LOG(sev) logs the given stream at severity "sev", which must be a
// compile-time constant of the LoggingSeverity type, without the namespace
// prefix.
// RTC_LOG_IF(sev, condition) logs the given stream at severitye "sev" if
// "condition" is true.
// RTC_LOG_V(sev) Like RTC_LOG(), but sev is a run-time variable of the
// LoggingSeverity type (basically, it just doesn't prepend the namespace).
// RTC_LOG_F(sev) Like RTC_LOG(), but includes the name of the current function.
// RTC_LOG_IF_F(sev, condition), Like RTC_LOG_IF(), but includes the name of
// the current function.
// RTC_LOG_T(sev) Like RTC_LOG(), but includes the this pointer.
// RTC_LOG_T_F(sev) Like RTC_LOG_F(), but includes the this pointer.
// RTC_LOG_GLE(sev [, mod]) attempt to add a string description of the
@ -49,12 +53,15 @@
#include <atomic>
#include <sstream> // no-presubmit-check TODO(webrtc:8982)
#include <string>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/deprecation.h"
#include "absl/types/optional.h"
#include "api/units/timestamp.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/system/inline.h"
@ -73,9 +80,7 @@
namespace rtc {
//////////////////////////////////////////////////////////////////////
// Note that the non-standard LoggingSeverity aliases exist because they are
// still in broad use. The meanings of the levels are:
// The meanings of the levels are:
// LS_VERBOSE: This level is for data which we do not want to appear in the
// normal debug log, but should appear in diagnostic logs.
// LS_INFO: Chatty level used in debugging for all sorts of things, the default
@ -89,9 +94,6 @@ enum LoggingSeverity {
LS_WARNING,
LS_ERROR,
LS_NONE,
INFO = LS_INFO,
WARNING = LS_WARNING,
LERROR = LS_ERROR
};
// LogErrorContext assists in interpreting the meaning of an error value.
@ -106,6 +108,50 @@ enum LogErrorContext {
};
class LogMessage;
// LogLineRef encapsulates all the information required to generate a log line.
// It is used both internally to LogMessage but also as a parameter to
// LogSink::OnLogMessage, allowing custom LogSinks to format the log in
// the most flexible way.
class LogLineRef {
public:
absl::string_view message() const { return message_; }
absl::string_view filename() const { return filename_; }
int line() const { return line_; }
absl::optional<PlatformThreadId> thread_id() const { return thread_id_; }
webrtc::Timestamp timestamp() const { return timestamp_; }
absl::string_view tag() const { return tag_; }
LoggingSeverity severity() const { return severity_; }
#if RTC_LOG_ENABLED()
std::string DefaultLogLine() const;
#else
std::string DefaultLogLine() const { return ""; }
#endif
private:
friend class LogMessage;
void set_message(std::string message) { message_ = std::move(message); }
void set_filename(absl::string_view filename) { filename_ = filename; }
void set_line(int line) { line_ = line; }
void set_thread_id(absl::optional<PlatformThreadId> thread_id) {
thread_id_ = thread_id;
}
void set_timestamp(webrtc::Timestamp timestamp) { timestamp_ = timestamp; }
void set_tag(absl::string_view tag) { tag_ = tag; }
void set_severity(LoggingSeverity severity) { severity_ = severity; }
std::string message_;
absl::string_view filename_;
int line_ = 0;
absl::optional<PlatformThreadId> thread_id_;
webrtc::Timestamp timestamp_ = webrtc::Timestamp::MinusInfinity();
// The default Android debug output tag.
absl::string_view tag_ = "libjingle";
// The severity level of this message
LoggingSeverity severity_;
};
// Virtual sink interface that can receive log messages.
class LogSink {
public:
@ -118,6 +164,14 @@ class LogSink {
LoggingSeverity severity);
virtual void OnLogMessage(const std::string& message) = 0;
virtual void OnLogMessage(absl::string_view msg,
LoggingSeverity severity,
const char* tag);
virtual void OnLogMessage(absl::string_view message,
LoggingSeverity severity);
virtual void OnLogMessage(absl::string_view message);
virtual void OnLogMessage(const LogLineRef& line);
private:
friend class ::rtc::LogMessage;
#if RTC_LOG_ENABLED()
@ -276,8 +330,15 @@ inline Val<LogArgType::kLogMetadataTag, LogMetadataTag> MakeVal(
template <typename T, class = void>
struct has_to_log_string : std::false_type {};
template <typename T>
struct has_to_log_string<T, decltype(ToLogString(std::declval<T>()))>
: std::true_type {};
struct has_to_log_string<T,
absl::enable_if_t<std::is_convertible<
decltype(ToLogString(std::declval<T>())),
std::string>::value>> : std::true_type {};
template <typename T, absl::enable_if_t<has_to_log_string<T>::value>* = nullptr>
ToStringVal MakeVal(const T& x) {
return {ToLogString(x)};
}
// Handle arbitrary types other than the above by falling back to stringstream.
// TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need
@ -299,11 +360,6 @@ ToStringVal MakeVal(const T& x) {
return {os.str()};
}
template <typename T, absl::enable_if_t<has_to_log_string<T>::value>* = nullptr>
ToStringVal MakeVal(const T& x) {
return {ToLogString(x)};
}
#if RTC_LOG_ENABLED()
void Log(const LogArgType* fmt, ...);
#else
@ -431,16 +487,11 @@ class LogMessage {
#if defined(WEBRTC_ANDROID)
LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag);
#endif
// DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS.
// Android code should use the 'const char*' version since tags are static
// and we want to avoid allocating a std::string copy per log line.
RTC_DEPRECATED
LogMessage(const char* file,
int line,
LoggingSeverity sev,
const std::string& tag);
~LogMessage();
LogMessage(const LogMessage&) = delete;
LogMessage& operator=(const LogMessage&) = delete;
void AddTag(const char* tag);
rtc::StringBuilder& stream();
// Returns the time at which this function was called for the first time.
@ -449,7 +500,7 @@ class LogMessage {
// which case the logging start time will be the time of the first LogMessage
// instance is created.
static int64_t LogStartTime();
// Returns the wall clock equivalent of |LogStartTime|, in seconds from the
// Returns the wall clock equivalent of `LogStartTime`, in seconds from the
// epoch.
static uint32_t WallClockStartTime();
// LogThreads: Display the thread identifier of the current thread
@ -463,14 +514,14 @@ class LogMessage {
// Sets whether logs will be directed to stderr in debug mode.
static void SetLogToStderr(bool log_to_stderr);
// Stream: Any non-blocking stream interface.
// Installs the |stream| to collect logs with severtiy |min_sev| or higher.
// |stream| must live until deinstalled by RemoveLogToStream.
// If |stream| is the first stream added to the system, we might miss some
// Installs the `stream` to collect logs with severtiy `min_sev` or higher.
// `stream` must live until deinstalled by RemoveLogToStream.
// If `stream` is the first stream added to the system, we might miss some
// early concurrent log statement happening from another thread happening near
// this instant.
static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev);
// Removes the specified stream, without destroying it. When the method
// has completed, it's guaranteed that |stream| will receive no more logging
// has completed, it's guaranteed that `stream` will receive no more logging
// calls.
static void RemoveLogToStream(LogSink* stream);
// Returns the severity for the specified stream, of if none is specified,
@ -481,10 +532,10 @@ class LogMessage {
static int GetMinLogSeverity();
// Parses the provided parameter stream to configure the options above.
// Useful for configuring logging from the command line.
static void ConfigureLogging(const char* params);
// Checks the current global debug severity and if the |streams_| collection
// is empty. If |severity| is smaller than the global severity and if the
// |streams_| collection is empty, the LogMessage will be considered a noop
static void ConfigureLogging(absl::string_view params);
// Checks the current global debug severity and if the `streams_` collection
// is empty. If `severity` is smaller than the global severity and if the
// `streams_` collection is empty, the LogMessage will be considered a noop
// LogMessage.
static bool IsNoop(LoggingSeverity severity);
// Version of IsNoop that uses fewer instructions at the call site, since the
@ -505,14 +556,6 @@ class LogMessage {
LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag) {
}
#endif
// DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS.
// Android code should use the 'const char*' version since tags are static
// and we want to avoid allocating a std::string copy per log line.
RTC_DEPRECATED
LogMessage(const char* file,
int line,
LoggingSeverity sev,
const std::string& tag) {}
~LogMessage() = default;
inline void AddTag(const char* tag) {}
@ -530,7 +573,7 @@ class LogMessage {
inline static void RemoveLogToStream(LogSink* stream) {}
inline static int GetLogToStream(LogSink* stream = nullptr) { return 0; }
inline static int GetMinLogSeverity() { return 0; }
inline static void ConfigureLogging(const char* params) {}
inline static void ConfigureLogging(absl::string_view params) {}
static constexpr bool IsNoop(LoggingSeverity severity) { return true; }
template <LoggingSeverity S>
static constexpr bool IsNoop() {
@ -545,26 +588,14 @@ class LogMessage {
// Updates min_sev_ appropriately when debug sinks change.
static void UpdateMinLogSeverity();
// These write out the actual log messages.
#if defined(WEBRTC_ANDROID)
static void OutputToDebug(const std::string& msg,
LoggingSeverity severity,
const char* tag);
#else
static void OutputToDebug(const std::string& msg, LoggingSeverity severity);
#endif // defined(WEBRTC_ANDROID)
// This writes out the actual log messages.
static void OutputToDebug(const LogLineRef& log_line_ref);
// Called from the dtor (or from a test) to append optional extra error
// information to the log stream and a newline character.
void FinishPrintStream();
// The severity level of this message
LoggingSeverity severity_;
#if defined(WEBRTC_ANDROID)
// The default Android debug output tag.
const char* tag_ = "libjingle";
#endif
LogLineRef log_line_;
// String data generated in the constructor, that should be appended to
// the message before output.
@ -573,14 +604,15 @@ class LogMessage {
// The output streams and their associated severities
static LogSink* streams_;
// Holds true with high probability if |streams_| is empty, false with high
// Holds true with high probability if `streams_` is empty, false with high
// probability otherwise. Operated on with std::memory_order_relaxed because
// it's ok to lose or log some additional statements near the instant streams
// are added/removed.
static std::atomic<bool> streams_empty_;
// Flags for formatting options
static bool thread_, timestamp_;
// Flags for formatting options and their potential values.
static bool log_thread_;
static bool log_timestamp_;
// Determines if logs will be directed to stderr in debug mode.
static bool log_to_stderr_;
@ -588,11 +620,15 @@ class LogMessage {
// Next methods do nothing; no one will call these functions.
inline static void UpdateMinLogSeverity() {}
#if defined(WEBRTC_ANDROID)
inline static void OutputToDebug(const std::string& msg,
inline static void OutputToDebug(absl::string_view filename,
int line,
absl::string_view msg,
LoggingSeverity severity,
const char* tag) {}
#else
inline static void OutputToDebug(const std::string& msg,
inline static void OutputToDebug(absl::string_view filename,
int line,
absl::string_view msg,
LoggingSeverity severity) {}
#endif // defined(WEBRTC_ANDROID)
inline void FinishPrintStream() {}
@ -600,8 +636,6 @@ class LogMessage {
// The stringbuilder that buffers the formatted message before output
rtc::StringBuilder print_stream_;
RTC_DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
//////////////////////////////////////////////////////////////////////
@ -613,21 +647,29 @@ class LogMessage {
::rtc::webrtc_logging_impl::LogStreamer<>() \
<< ::rtc::webrtc_logging_impl::LogMetadata(file, line, sev)
#define RTC_LOG(sev) \
!rtc::LogMessage::IsNoop<::rtc::sev>() && \
#define RTC_LOG(sev) \
!::rtc::LogMessage::IsNoop<::rtc::sev>() && \
RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__)
#define RTC_LOG_IF(sev, condition) \
!::rtc::LogMessage::IsNoop<::rtc::sev>() && (condition) && \
RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__)
// The _V version is for when a variable is passed in.
#define RTC_LOG_V(sev) \
!rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__)
!::rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__)
// The _F version prefixes the message with the current function name.
#if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F)
#define RTC_LOG_F(sev) RTC_LOG(sev) << __PRETTY_FUNCTION__ << ": "
#define RTC_LOG_IF_F(sev, condition) \
RTC_LOG_IF(sev, condition) << __PRETTY_FUNCTION__ << ": "
#define RTC_LOG_T_F(sev) \
RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": "
#else
#define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": "
#define RTC_LOG_IF_F(sev, condition) \
RTC_LOG_IF(sev, condition) << __FUNCTION__ << ": "
#define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": "
#endif
@ -639,7 +681,7 @@ inline bool LogCheckLevel(LoggingSeverity sev) {
}
#define RTC_LOG_E(sev, ctx, err) \
!rtc::LogMessage::IsNoop<::rtc::sev>() && \
!::rtc::LogMessage::IsNoop<::rtc::sev>() && \
::rtc::webrtc_logging_impl::LogCall() & \
::rtc::webrtc_logging_impl::LogStreamer<>() \
<< ::rtc::webrtc_logging_impl::LogMetadataErr { \
@ -677,7 +719,7 @@ inline const char* AdaptString(const std::string& str) {
} // namespace webrtc_logging_impl
#define RTC_LOG_TAG(sev, tag) \
!rtc::LogMessage::IsNoop(sev) && \
!::rtc::LogMessage::IsNoop(sev) && \
::rtc::webrtc_logging_impl::LogCall() & \
::rtc::webrtc_logging_impl::LogStreamer<>() \
<< ::rtc::webrtc_logging_impl::LogMetadataTag { \
@ -695,16 +737,20 @@ inline const char* AdaptString(const std::string& str) {
// they only generate code in debug builds.
#if RTC_DLOG_IS_ON
#define RTC_DLOG(sev) RTC_LOG(sev)
#define RTC_DLOG_IF(sev, condition) RTC_LOG_IF(sev, condition)
#define RTC_DLOG_V(sev) RTC_LOG_V(sev)
#define RTC_DLOG_F(sev) RTC_LOG_F(sev)
#define RTC_DLOG_IF_F(sev, condition) RTC_LOG_IF_F(sev, condition)
#else
#define RTC_DLOG_EAT_STREAM_PARAMS() \
while (false) \
::rtc::webrtc_logging_impl::LogMessageVoidify() & \
(::rtc::webrtc_logging_impl::LogStreamer<>())
#define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS()
#define RTC_DLOG_IF(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS()
#define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS()
#define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS()
#define RTC_DLOG_IF_F(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS()
#endif
} // namespace rtc

View File

@ -21,24 +21,22 @@ rtc_library("aligned_malloc") {
}
# Test only utility.
# TODO: Tag with `testonly = true` once all depending targets are correctly
# tagged.
rtc_library("fifo_buffer") {
testonly = true
visibility = [
":unittests",
"..:rtc_base_tests_utils",
"..:rtc_base_unittests",
"../../p2p:rtc_p2p", # This needs to be fixed.
]
sources = [
"fifo_buffer.cc",
"fifo_buffer.h",
]
deps = [
"..:rtc_base",
"..:stream",
"..:threading",
"../../api/task_queue:pending_task_safety_flag",
"../synchronization:mutex",
"../task_utils:pending_task_safety_flag",
"../task_utils:to_queued_task",
]
}
@ -46,11 +44,18 @@ rtc_library("unittests") {
testonly = true
sources = [
"aligned_malloc_unittest.cc",
"always_valid_pointer_unittest.cc",
"fifo_buffer_unittest.cc",
]
deps = [
":aligned_malloc",
":always_valid_pointer",
":fifo_buffer",
"../../test:test_support",
]
}
rtc_source_set("always_valid_pointer") {
sources = [ "always_valid_pointer.h" ]
deps = [ "..:checks" ]
}

View File

@ -26,7 +26,7 @@
namespace webrtc {
uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
// The pointer should be aligned with |alignment| bytes. The - 1 guarantees
// The pointer should be aligned with `alignment` bytes. The - 1 guarantees
// that it is aligned towards the closest higher (right) address.
return (start_pos + alignment - 1) & ~(alignment - 1);
}

View File

@ -21,13 +21,13 @@
namespace webrtc {
// Returns a pointer to the first boundry of |alignment| bytes following the
// address of |ptr|.
// Returns a pointer to the first boundry of `alignment` bytes following the
// address of `ptr`.
// Note that there is no guarantee that the memory in question is available.
// |ptr| has no requirements other than it can't be NULL.
// `ptr` has no requirements other than it can't be NULL.
void* GetRightAlign(const void* ptr, size_t alignment);
// Allocates memory of |size| bytes aligned on an |alignment| boundry.
// Allocates memory of `size` bytes aligned on an `alignment` boundry.
// The return value is a pointer to the memory. Note that the memory must
// be de-allocated using AlignedFree.
void* AlignedMalloc(size_t size, size_t alignment);

View File

@ -1,5 +1,6 @@
base_sources = [
'checks.cc',
'containers/flat_tree.cc',
'event.cc',
'event_tracer.cc',
'experiments/field_trial_parser.cc',
@ -8,15 +9,16 @@ base_sources = [
'platform_thread.cc',
'platform_thread_types.cc',
'race_checker.cc',
'random.cc',
'string_encode.cc',
'string_to_number.cc',
'string_utils.cc',
'strings/string_builder.cc',
'synchronization/mutex.cc',
'synchronization/rw_lock_wrapper.cc',
'synchronization/sequence_checker_internal.cc',
'synchronization/yield.cc',
'synchronization/yield_policy.cc',
'system/file_wrapper.cc',
'system_time.cc',
'time_utils.cc',
'zero_memory.cc',
]
@ -24,8 +26,6 @@ base_sources = [
base_headers = [
[ '', 'arraysize.h' ],
[ '', 'checks.h' ],
[ '', 'constructor_magic.h' ],
[ '', 'deprecation.h' ],
[ '', 'ref_count.h' ],
[ '', 'type_traits.h' ],
[ 'numerics', 'safe_compare.h' ],
@ -34,16 +34,6 @@ base_headers = [
[ 'system', 'rtc_export.h' ],
]
if have_posix
base_sources += [
'synchronization/rw_lock_posix.cc',
]
elif have_win
base_sources += [
'synchronization/rw_lock_win.cc',
]
endif
foreach h : base_headers
install_headers(
join_paths(h[0], h[1]),
@ -64,6 +54,10 @@ elif host_system == 'ios'
'UIKit',
]
)
elif host_system == 'android'
base_sources += [
'system/warn_current_thread_is_deadlocked.cc',
]
endif
libbase = static_library('libbase',

View File

@ -0,0 +1,60 @@
/*
* Copyright 2019 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_NUMERICS_DIVIDE_ROUND_H_
#define RTC_BASE_NUMERICS_DIVIDE_ROUND_H_
#include <type_traits>
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_compare.h"
namespace webrtc {
template <typename Dividend, typename Divisor>
inline auto constexpr DivideRoundUp(Dividend dividend, Divisor divisor) {
static_assert(std::is_integral<Dividend>(), "");
static_assert(std::is_integral<Divisor>(), "");
RTC_DCHECK_GE(dividend, 0);
RTC_DCHECK_GT(divisor, 0);
auto quotient = dividend / divisor;
auto remainder = dividend % divisor;
return quotient + (remainder > 0 ? 1 : 0);
}
template <typename Dividend, typename Divisor>
inline auto constexpr DivideRoundToNearest(Dividend dividend, Divisor divisor) {
static_assert(std::is_integral<Dividend>(), "");
static_assert(std::is_integral<Divisor>(), "");
RTC_DCHECK_GT(divisor, 0);
if (dividend < Dividend{0}) {
auto half_of_divisor = divisor / 2;
auto quotient = dividend / divisor;
auto remainder = dividend % divisor;
if (rtc::SafeGt(-remainder, half_of_divisor)) {
--quotient;
}
return quotient;
}
auto half_of_divisor = (divisor - 1) / 2;
auto quotient = dividend / divisor;
auto remainder = dividend % divisor;
if (rtc::SafeGt(remainder, half_of_divisor)) {
++quotient;
}
return quotient;
}
} // namespace webrtc
#endif // RTC_BASE_NUMERICS_DIVIDE_ROUND_H_

View File

@ -63,12 +63,10 @@ inline constexpr Dst saturated_cast(Src value) {
// Should fail only on attempting to assign NaN to a saturated integer.
case internal::TYPE_INVALID:
FATAL();
return std::numeric_limits<Dst>::max();
RTC_CHECK_NOTREACHED();
}
FATAL();
return static_cast<Dst>(value);
RTC_CHECK_NOTREACHED();
}
} // namespace rtc

View File

@ -325,9 +325,9 @@ R2 SafeClamp(T x, L min, H max) {
static_assert(IsIntlike<L>::value || std::is_floating_point<L>::value,
"The third argument must be integral or floating-point");
RTC_DCHECK_LE(min, max);
return SafeLe(x, min)
? static_cast<R2>(min)
: SafeGe(x, max) ? static_cast<R2>(max) : static_cast<R2>(x);
return SafeLe(x, min) ? static_cast<R2>(min)
: SafeGe(x, max) ? static_cast<R2>(max)
: static_cast<R2>(x);
}
} // namespace rtc

View File

@ -10,131 +10,37 @@
#include "rtc_base/platform_thread.h"
#include <algorithm>
#include <memory>
#if !defined(WEBRTC_WIN)
#include <sched.h>
#endif
#include <stdint.h>
#include <time.h>
#include <algorithm>
#include "rtc_base/checks.h"
namespace rtc {
namespace {
#if !defined(WEBRTC_WIN)
struct ThreadAttributes {
ThreadAttributes() { pthread_attr_init(&attr); }
~ThreadAttributes() { pthread_attr_destroy(&attr); }
pthread_attr_t* operator&() { return &attr; }
pthread_attr_t attr;
};
#endif // defined(WEBRTC_WIN)
} // namespace
PlatformThread::PlatformThread(ThreadRunFunction func,
void* obj,
absl::string_view thread_name,
ThreadPriority priority /*= kNormalPriority*/)
: run_function_(func), priority_(priority), obj_(obj), name_(thread_name) {
RTC_DCHECK(func);
RTC_DCHECK(!name_.empty());
// TODO(tommi): Consider lowering the limit to 15 (limit on Linux).
RTC_DCHECK(name_.length() < 64);
spawned_thread_checker_.Detach();
}
PlatformThread::~PlatformThread() {
RTC_DCHECK(thread_checker_.IsCurrent());
#if defined(WEBRTC_WIN)
RTC_DCHECK(!thread_);
RTC_DCHECK(!thread_id_);
#endif // defined(WEBRTC_WIN)
}
#if defined(WEBRTC_WIN)
DWORD WINAPI PlatformThread::StartThread(void* param) {
// The GetLastError() function only returns valid results when it is called
// after a Win32 API function that returns a "failed" result. A crash dump
// contains the result from GetLastError() and to make sure it does not
// falsely report a Windows error we call SetLastError here.
::SetLastError(ERROR_SUCCESS);
static_cast<PlatformThread*>(param)->Run();
return 0;
int Win32PriorityFromThreadPriority(ThreadPriority priority) {
switch (priority) {
case ThreadPriority::kLow:
return THREAD_PRIORITY_BELOW_NORMAL;
case ThreadPriority::kNormal:
return THREAD_PRIORITY_NORMAL;
case ThreadPriority::kHigh:
return THREAD_PRIORITY_ABOVE_NORMAL;
case ThreadPriority::kRealtime:
return THREAD_PRIORITY_TIME_CRITICAL;
}
}
#else
void* PlatformThread::StartThread(void* param) {
static_cast<PlatformThread*>(param)->Run();
return 0;
}
#endif // defined(WEBRTC_WIN)
#endif
void PlatformThread::Start() {
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(!thread_) << "Thread already started?";
bool SetPriority(ThreadPriority priority) {
#if defined(WEBRTC_WIN)
// See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
// Set the reserved stack stack size to 1M, which is the default on Windows
// and Linux.
thread_ = ::CreateThread(nullptr, 1024 * 1024, &StartThread, this,
STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id_);
RTC_CHECK(thread_) << "CreateThread failed";
RTC_DCHECK(thread_id_);
#else
ThreadAttributes attr;
// Set the stack stack size to 1M.
pthread_attr_setstacksize(&attr, 1024 * 1024);
RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
#endif // defined(WEBRTC_WIN)
}
bool PlatformThread::IsRunning() const {
RTC_DCHECK(thread_checker_.IsCurrent());
#if defined(WEBRTC_WIN)
return thread_ != nullptr;
#else
return thread_ != 0;
#endif // defined(WEBRTC_WIN)
}
PlatformThreadRef PlatformThread::GetThreadRef() const {
#if defined(WEBRTC_WIN)
return thread_id_;
#else
return thread_;
#endif // defined(WEBRTC_WIN)
}
void PlatformThread::Stop() {
RTC_DCHECK(thread_checker_.IsCurrent());
if (!IsRunning())
return;
#if defined(WEBRTC_WIN)
WaitForSingleObject(thread_, INFINITE);
CloseHandle(thread_);
thread_ = nullptr;
thread_id_ = 0;
#else
RTC_CHECK_EQ(0, pthread_join(thread_, nullptr));
thread_ = 0;
#endif // defined(WEBRTC_WIN)
spawned_thread_checker_.Detach();
}
void PlatformThread::Run() {
// Attach the worker thread checker to this thread.
RTC_DCHECK(spawned_thread_checker_.IsCurrent());
rtc::SetCurrentThreadName(name_.c_str());
SetPriority(priority_);
run_function_(obj_);
}
bool PlatformThread::SetPriority(ThreadPriority priority) {
RTC_DCHECK(spawned_thread_checker_.IsCurrent());
#if defined(WEBRTC_WIN)
return SetThreadPriority(thread_, priority) != FALSE;
return SetThreadPriority(GetCurrentThread(),
Win32PriorityFromThreadPriority(priority)) != FALSE;
#elif defined(__native_client__) || defined(WEBRTC_FUCHSIA)
// Setting thread priorities is not supported in NaCl or Fuchsia.
return true;
@ -158,35 +64,148 @@ bool PlatformThread::SetPriority(ThreadPriority priority) {
const int top_prio = max_prio - 1;
const int low_prio = min_prio + 1;
switch (priority) {
case kLowPriority:
case ThreadPriority::kLow:
param.sched_priority = low_prio;
break;
case kNormalPriority:
case ThreadPriority::kNormal:
// The -1 ensures that the kHighPriority is always greater or equal to
// kNormalPriority.
param.sched_priority = (low_prio + top_prio - 1) / 2;
break;
case kHighPriority:
case ThreadPriority::kHigh:
param.sched_priority = std::max(top_prio - 2, low_prio);
break;
case kHighestPriority:
param.sched_priority = std::max(top_prio - 1, low_prio);
break;
case kRealtimePriority:
case ThreadPriority::kRealtime:
param.sched_priority = top_prio;
break;
}
return pthread_setschedparam(thread_, policy, &param) == 0;
return pthread_setschedparam(pthread_self(), policy, &param) == 0;
#endif // defined(WEBRTC_WIN)
}
#if defined(WEBRTC_WIN)
bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) {
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(IsRunning());
DWORD WINAPI RunPlatformThread(void* param) {
// The GetLastError() function only returns valid results when it is called
// after a Win32 API function that returns a "failed" result. A crash dump
// contains the result from GetLastError() and to make sure it does not
// falsely report a Windows error we call SetLastError here.
::SetLastError(ERROR_SUCCESS);
auto function = static_cast<std::function<void()>*>(param);
(*function)();
delete function;
return 0;
}
#else
void* RunPlatformThread(void* param) {
auto function = static_cast<std::function<void()>*>(param);
(*function)();
delete function;
return 0;
}
#endif // defined(WEBRTC_WIN)
return QueueUserAPC(function, thread_, data) != FALSE;
} // namespace
PlatformThread::PlatformThread(Handle handle, bool joinable)
: handle_(handle), joinable_(joinable) {}
PlatformThread::PlatformThread(PlatformThread&& rhs)
: handle_(rhs.handle_), joinable_(rhs.joinable_) {
rhs.handle_ = absl::nullopt;
}
PlatformThread& PlatformThread::operator=(PlatformThread&& rhs) {
Finalize();
handle_ = rhs.handle_;
joinable_ = rhs.joinable_;
rhs.handle_ = absl::nullopt;
return *this;
}
PlatformThread::~PlatformThread() {
Finalize();
}
PlatformThread PlatformThread::SpawnJoinable(
std::function<void()> thread_function,
absl::string_view name,
ThreadAttributes attributes) {
return SpawnThread(std::move(thread_function), name, attributes,
/*joinable=*/true);
}
PlatformThread PlatformThread::SpawnDetached(
std::function<void()> thread_function,
absl::string_view name,
ThreadAttributes attributes) {
return SpawnThread(std::move(thread_function), name, attributes,
/*joinable=*/false);
}
absl::optional<PlatformThread::Handle> PlatformThread::GetHandle() const {
return handle_;
}
#if defined(WEBRTC_WIN)
bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) {
RTC_DCHECK(handle_.has_value());
return handle_.has_value() ? QueueUserAPC(function, *handle_, data) != FALSE
: false;
}
#endif
void PlatformThread::Finalize() {
if (!handle_.has_value())
return;
#if defined(WEBRTC_WIN)
if (joinable_)
WaitForSingleObject(*handle_, INFINITE);
CloseHandle(*handle_);
#else
if (joinable_)
RTC_CHECK_EQ(0, pthread_join(*handle_, nullptr));
#endif
handle_ = absl::nullopt;
}
PlatformThread PlatformThread::SpawnThread(
std::function<void()> thread_function,
absl::string_view name,
ThreadAttributes attributes,
bool joinable) {
RTC_DCHECK(thread_function);
RTC_DCHECK(!name.empty());
// TODO(tommi): Consider lowering the limit to 15 (limit on Linux).
RTC_DCHECK(name.length() < 64);
auto start_thread_function_ptr =
new std::function<void()>([thread_function = std::move(thread_function),
name = std::string(name), attributes] {
rtc::SetCurrentThreadName(name.c_str());
SetPriority(attributes.priority);
thread_function();
});
#if defined(WEBRTC_WIN)
// See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
// Set the reserved stack stack size to 1M, which is the default on Windows
// and Linux.
DWORD thread_id = 0;
PlatformThread::Handle handle = ::CreateThread(
nullptr, 1024 * 1024, &RunPlatformThread, start_thread_function_ptr,
STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id);
RTC_CHECK(handle) << "CreateThread failed";
#else
pthread_attr_t attr;
pthread_attr_init(&attr);
// Set the stack stack size to 1M.
pthread_attr_setstacksize(&attr, 1024 * 1024);
pthread_attr_setdetachstate(
&attr, joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED);
PlatformThread::Handle handle;
RTC_CHECK_EQ(0, pthread_create(&handle, &attr, &RunPlatformThread,
start_thread_function_ptr));
pthread_attr_destroy(&attr);
#endif // defined(WEBRTC_WIN)
return PlatformThread(handle, joinable);
}
} // namespace rtc

View File

@ -11,92 +11,108 @@
#ifndef RTC_BASE_PLATFORM_THREAD_H_
#define RTC_BASE_PLATFORM_THREAD_H_
#ifndef WEBRTC_WIN
#include <functional>
#include <string>
#if !defined(WEBRTC_WIN)
#include <pthread.h>
#endif
#include <string>
#include "absl/strings/string_view.h"
#include "rtc_base/constructor_magic.h"
#include "absl/types/optional.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/thread_checker.h"
namespace rtc {
// Callback function that the spawned thread will enter once spawned.
typedef void (*ThreadRunFunction)(void*);
enum ThreadPriority {
#ifdef WEBRTC_WIN
kLowPriority = THREAD_PRIORITY_BELOW_NORMAL,
kNormalPriority = THREAD_PRIORITY_NORMAL,
kHighPriority = THREAD_PRIORITY_ABOVE_NORMAL,
kHighestPriority = THREAD_PRIORITY_HIGHEST,
kRealtimePriority = THREAD_PRIORITY_TIME_CRITICAL
#else
kLowPriority = 1,
kNormalPriority = 2,
kHighPriority = 3,
kHighestPriority = 4,
kRealtimePriority = 5
#endif
enum class ThreadPriority {
kLow = 1,
kNormal,
kHigh,
kRealtime,
};
// Represents a simple worker thread. The implementation must be assumed
// to be single threaded, meaning that all methods of the class, must be
// called from the same thread, including instantiation.
class PlatformThread {
struct ThreadAttributes {
ThreadPriority priority = ThreadPriority::kNormal;
ThreadAttributes& SetPriority(ThreadPriority priority_param) {
priority = priority_param;
return *this;
}
};
// Represents a simple worker thread.
class PlatformThread final {
public:
PlatformThread(ThreadRunFunction func,
void* obj,
absl::string_view thread_name,
ThreadPriority priority = kNormalPriority);
// Handle is the base platform thread handle.
#if defined(WEBRTC_WIN)
using Handle = HANDLE;
#else
using Handle = pthread_t;
#endif // defined(WEBRTC_WIN)
// This ctor creates the PlatformThread with an unset handle (returning true
// in empty()) and is provided for convenience.
// TODO(bugs.webrtc.org/12727) Look into if default and move support can be
// removed.
PlatformThread() = default;
// Moves `rhs` into this, storing an empty state in `rhs`.
// TODO(bugs.webrtc.org/12727) Look into if default and move support can be
// removed.
PlatformThread(PlatformThread&& rhs);
// Copies won't work since we'd have problems with joinable threads.
PlatformThread(const PlatformThread&) = delete;
PlatformThread& operator=(const PlatformThread&) = delete;
// Moves `rhs` into this, storing an empty state in `rhs`.
// TODO(bugs.webrtc.org/12727) Look into if default and move support can be
// removed.
PlatformThread& operator=(PlatformThread&& rhs);
// For a PlatformThread that's been spawned joinable, the destructor suspends
// the calling thread until the created thread exits unless the thread has
// already exited.
virtual ~PlatformThread();
const std::string& name() const { return name_; }
// Finalizes any allocated resources.
// For a PlatformThread that's been spawned joinable, Finalize() suspends
// the calling thread until the created thread exits unless the thread has
// already exited.
// empty() returns true after completion.
void Finalize();
// Spawns a thread and tries to set thread priority according to the priority
// from when CreateThread was called.
void Start();
// Returns true if default constructed, moved from, or Finalize()ed.
bool empty() const { return !handle_.has_value(); }
bool IsRunning() const;
// Creates a started joinable thread which will be joined when the returned
// PlatformThread destructs or Finalize() is called.
static PlatformThread SpawnJoinable(
std::function<void()> thread_function,
absl::string_view name,
ThreadAttributes attributes = ThreadAttributes());
// Returns an identifier for the worker thread that can be used to do
// thread checks.
PlatformThreadRef GetThreadRef() const;
// Creates a started detached thread. The caller has to use external
// synchronization as nothing is provided by the PlatformThread construct.
static PlatformThread SpawnDetached(
std::function<void()> thread_function,
absl::string_view name,
ThreadAttributes attributes = ThreadAttributes());
// Stops (joins) the spawned thread.
void Stop();
// Returns the base platform thread handle of this thread.
absl::optional<Handle> GetHandle() const;
protected:
#if defined(WEBRTC_WIN)
// Exposed to derived classes to allow for special cases specific to Windows.
// Queue a Windows APC function that runs when the thread is alertable.
bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data);
#endif
private:
void Run();
bool SetPriority(ThreadPriority priority);
PlatformThread(Handle handle, bool joinable);
static PlatformThread SpawnThread(std::function<void()> thread_function,
absl::string_view name,
ThreadAttributes attributes,
bool joinable);
ThreadRunFunction const run_function_ = nullptr;
const ThreadPriority priority_ = kNormalPriority;
void* const obj_;
// TODO(pbos): Make sure call sites use string literals and update to a const
// char* instead of a std::string.
const std::string name_;
rtc::ThreadChecker thread_checker_;
rtc::ThreadChecker spawned_thread_checker_;
#if defined(WEBRTC_WIN)
static DWORD WINAPI StartThread(void* param);
HANDLE thread_ = nullptr;
DWORD thread_id_ = 0;
#else
static void* StartThread(void* param);
pthread_t thread_ = 0;
#endif // defined(WEBRTC_WIN)
RTC_DISALLOW_COPY_AND_ASSIGN(PlatformThread);
absl::optional<Handle> handle_;
bool joinable_ = false;
};
} // namespace rtc

View File

@ -25,6 +25,13 @@ typedef HRESULT(WINAPI* RTC_SetThreadDescription)(HANDLE hThread,
PCWSTR lpThreadDescription);
#endif
#if defined(WEBRTC_FUCHSIA)
#include <string.h>
#include <zircon/syscalls.h>
#include "rtc_base/checks.h"
#endif
namespace rtc {
PlatformThreadId CurrentThreadId() {
@ -99,18 +106,20 @@ void SetCurrentThreadName(const char* name) {
#pragma warning(push)
#pragma warning(disable : 6320 6322)
#ifndef __MINGW32__
__try {
::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(ULONG_PTR),
reinterpret_cast<ULONG_PTR*>(&threadname_info));
} __except (EXCEPTION_EXECUTE_HANDLER) { // NOLINT
}
#endif
#pragma warning(pop)
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name)); // NOLINT
#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
pthread_setname_np(name);
#elif defined(WEBRTC_FUCHSIA)
zx_status_t status = zx_object_set_property(zx_thread_self(), ZX_PROP_NAME,
name, strlen(name));
RTC_DCHECK_EQ(status, ZX_OK);
#endif
}

View File

@ -25,7 +25,9 @@ RaceChecker::RaceChecker() {}
bool RaceChecker::Acquire() const {
const PlatformThreadRef current_thread = CurrentThreadRef();
// Set new accessing thread if this is a new use.
if (access_count_++ == 0)
const int current_access_count = access_count_;
access_count_ = access_count_ + 1;
if (current_access_count == 0)
accessing_thread_ = current_thread;
// If this is being used concurrently this check will fail for the second
// thread entering since it won't set the thread. Recursive use of checked
@ -35,7 +37,7 @@ bool RaceChecker::Acquire() const {
}
void RaceChecker::Release() const {
--access_count_;
access_count_ = access_count_ - 1;
}
namespace internal {

87
webrtc/rtc_base/random.cc Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/random.h"
#include <math.h>
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
Random::Random(uint64_t seed) {
RTC_DCHECK(seed != 0x0ull);
state_ = seed;
}
uint32_t Random::Rand(uint32_t t) {
// Casting the output to 32 bits will give an almost uniform number.
// Pr[x=0] = (2^32-1) / (2^64-1)
// Pr[x=k] = 2^32 / (2^64-1) for k!=0
// Uniform would be Pr[x=k] = 2^32 / 2^64 for all 32-bit integers k.
uint32_t x = NextOutput();
// If x / 2^32 is uniform on [0,1), then x / 2^32 * (t+1) is uniform on
// the interval [0,t+1), so the integer part is uniform on [0,t].
uint64_t result = x * (static_cast<uint64_t>(t) + 1);
result >>= 32;
return result;
}
uint32_t Random::Rand(uint32_t low, uint32_t high) {
RTC_DCHECK(low <= high);
return Rand(high - low) + low;
}
int32_t Random::Rand(int32_t low, int32_t high) {
RTC_DCHECK(low <= high);
const int64_t low_i64{low};
return rtc::dchecked_cast<int32_t>(
Rand(rtc::dchecked_cast<uint32_t>(high - low_i64)) + low_i64);
}
template <>
float Random::Rand<float>() {
double result = NextOutput() - 1;
result = result / static_cast<double>(0xFFFFFFFFFFFFFFFFull);
return static_cast<float>(result);
}
template <>
double Random::Rand<double>() {
double result = NextOutput() - 1;
result = result / static_cast<double>(0xFFFFFFFFFFFFFFFFull);
return result;
}
template <>
bool Random::Rand<bool>() {
return Rand(0, 1) == 1;
}
double Random::Gaussian(double mean, double standard_deviation) {
// Creating a Normal distribution variable from two independent uniform
// variables based on the Box-Muller transform, which is defined on the
// interval (0, 1]. Note that we rely on NextOutput to generate integers
// in the range [1, 2^64-1]. Normally this behavior is a bit frustrating,
// but here it is exactly what we need.
const double kPi = 3.14159265358979323846;
double u1 = static_cast<double>(NextOutput()) /
static_cast<double>(0xFFFFFFFFFFFFFFFFull);
double u2 = static_cast<double>(NextOutput()) /
static_cast<double>(0xFFFFFFFFFFFFFFFFull);
return mean + standard_deviation * sqrt(-2 * log(u1)) * cos(2 * kPi * u2);
}
double Random::Exponential(double lambda) {
double uniform = Rand<double>();
return -log(uniform) / lambda;
}
} // namespace webrtc

96
webrtc/rtc_base/random.h Normal file
View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_RANDOM_H_
#define RTC_BASE_RANDOM_H_
#include <stdint.h>
#include <limits>
#include "rtc_base/checks.h"
namespace webrtc {
class Random {
public:
// TODO(tommi): Change this so that the seed can be initialized internally,
// e.g. by offering two ways of constructing or offer a static method that
// returns a seed that's suitable for initialization.
// The problem now is that callers are calling clock_->TimeInMicroseconds()
// which calls TickTime::Now().Ticks(), which can return a very low value on
// Mac and can result in a seed of 0 after conversion to microseconds.
// Besides the quality of the random seed being poor, this also requires
// the client to take on extra dependencies to generate a seed.
// If we go for a static seed generator in Random, we can use something from
// webrtc/rtc_base and make sure that it works the same way across platforms.
// See also discussion here: https://codereview.webrtc.org/1623543002/
explicit Random(uint64_t seed);
Random() = delete;
Random(const Random&) = delete;
Random& operator=(const Random&) = delete;
// Return pseudo-random integer of the specified type.
// We need to limit the size to 32 bits to keep the output close to uniform.
template <typename T>
T Rand() {
static_assert(std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::radix == 2 &&
std::numeric_limits<T>::digits <= 32,
"Rand is only supported for built-in integer types that are "
"32 bits or smaller.");
return static_cast<T>(NextOutput());
}
// Uniformly distributed pseudo-random number in the interval [0, t].
uint32_t Rand(uint32_t t);
// Uniformly distributed pseudo-random number in the interval [low, high].
uint32_t Rand(uint32_t low, uint32_t high);
// Uniformly distributed pseudo-random number in the interval [low, high].
int32_t Rand(int32_t low, int32_t high);
// Normal Distribution.
double Gaussian(double mean, double standard_deviation);
// Exponential Distribution.
double Exponential(double lambda);
private:
// Outputs a nonzero 64-bit random number using Xorshift algorithm.
// https://en.wikipedia.org/wiki/Xorshift
uint64_t NextOutput() {
state_ ^= state_ >> 12;
state_ ^= state_ << 25;
state_ ^= state_ >> 27;
RTC_DCHECK(state_ != 0x0ULL);
return state_ * 2685821657736338717ull;
}
uint64_t state_;
};
// Return pseudo-random number in the interval [0.0, 1.0).
template <>
float Random::Rand<float>();
// Return pseudo-random number in the interval [0.0, 1.0).
template <>
double Random::Rand<double>();
// Return pseudo-random boolean value.
template <>
bool Random::Rand<bool>();
} // namespace webrtc
#endif // RTC_BASE_RANDOM_H_

View File

@ -10,10 +10,7 @@
#ifndef RTC_BASE_REF_COUNTED_OBJECT_H_
#define RTC_BASE_REF_COUNTED_OBJECT_H_
#include <type_traits>
#include <utility>
#include "rtc_base/constructor_magic.h"
#include "api/scoped_refptr.h"
#include "rtc_base/ref_count.h"
#include "rtc_base/ref_counter.h"
@ -24,6 +21,9 @@ class RefCountedObject : public T {
public:
RefCountedObject() {}
RefCountedObject(const RefCountedObject&) = delete;
RefCountedObject& operator=(const RefCountedObject&) = delete;
template <class P0>
explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}
@ -33,9 +33,9 @@ class RefCountedObject : public T {
std::forward<P1>(p1),
std::forward<Args>(args)...) {}
virtual void AddRef() const { ref_count_.IncRef(); }
void AddRef() const override { ref_count_.IncRef(); }
virtual RefCountReleaseStatus Release() const {
RefCountReleaseStatus Release() const override {
const auto status = ref_count_.DecRef();
if (status == RefCountReleaseStatus::kDroppedLastRef) {
delete this;
@ -52,11 +52,36 @@ class RefCountedObject : public T {
virtual bool HasOneRef() const { return ref_count_.HasOneRef(); }
protected:
virtual ~RefCountedObject() {}
~RefCountedObject() override {}
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
};
RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject);
template <class T>
class FinalRefCountedObject final : public T {
public:
using T::T;
// Above using declaration propagates a default move constructor
// FinalRefCountedObject(FinalRefCountedObject&& other), but we also need
// move construction from T.
explicit FinalRefCountedObject(T&& other) : T(std::move(other)) {}
FinalRefCountedObject(const FinalRefCountedObject&) = delete;
FinalRefCountedObject& operator=(const FinalRefCountedObject&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
const auto status = ref_count_.DecRef();
if (status == RefCountReleaseStatus::kDroppedLastRef) {
delete this;
}
return status;
}
bool HasOneRef() const { return ref_count_.HasOneRef(); }
private:
~FinalRefCountedObject() = default;
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
};
} // namespace rtc

View File

@ -12,6 +12,8 @@
#include <cstdio>
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
@ -49,18 +51,18 @@ size_t hex_encode_output_length(size_t srclen, char delimiter) {
}
// hex_encode shows the hex representation of binary data in ascii, with
// |delimiter| between bytes, or none if |delimiter| == 0.
// `delimiter` between bytes, or none if `delimiter` == 0.
void hex_encode_with_delimiter(char* buffer,
const char* csource,
size_t srclen,
absl::string_view source,
char delimiter) {
RTC_DCHECK(buffer);
// Init and check bounds.
const unsigned char* bsource =
reinterpret_cast<const unsigned char*>(csource);
reinterpret_cast<const unsigned char*>(source.data());
size_t srcpos = 0, bufpos = 0;
size_t srclen = source.length();
while (srcpos < srclen) {
unsigned char ch = bsource[srcpos++];
buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
@ -77,43 +79,30 @@ void hex_encode_with_delimiter(char* buffer,
} // namespace
std::string hex_encode(const std::string& str) {
return hex_encode(str.c_str(), str.size());
std::string hex_encode(absl::string_view str) {
return hex_encode_with_delimiter(str, 0);
}
std::string hex_encode(const char* source, size_t srclen) {
return hex_encode_with_delimiter(source, srclen, 0);
}
std::string hex_encode_with_delimiter(const char* source,
size_t srclen,
std::string hex_encode_with_delimiter(absl::string_view source,
char delimiter) {
std::string s(hex_encode_output_length(srclen, delimiter), 0);
hex_encode_with_delimiter(&s[0], source, srclen, delimiter);
std::string s(hex_encode_output_length(source.length(), delimiter), 0);
hex_encode_with_delimiter(&s[0], source, delimiter);
return s;
}
size_t hex_decode(char* cbuffer,
size_t buflen,
const char* source,
size_t srclen) {
return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
}
size_t hex_decode_with_delimiter(char* cbuffer,
size_t buflen,
const char* source,
size_t srclen,
size_t hex_decode_with_delimiter(ArrayView<char> cbuffer,
absl::string_view source,
char delimiter) {
RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
if (buflen == 0)
if (cbuffer.empty())
return 0;
// Init and bounds check.
unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer.data());
size_t srcpos = 0, bufpos = 0;
size_t srclen = source.length();
size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
if (buflen < needed)
if (cbuffer.size() < needed)
return 0;
while (srcpos < srclen) {
@ -141,18 +130,11 @@ size_t hex_decode_with_delimiter(char* cbuffer,
return bufpos;
}
size_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
return hex_decode_with_delimiter(buffer, buflen, source, 0);
}
size_t hex_decode_with_delimiter(char* buffer,
size_t buflen,
const std::string& source,
char delimiter) {
return hex_decode_with_delimiter(buffer, buflen, source.c_str(),
source.length(), delimiter);
size_t hex_decode(ArrayView<char> buffer, absl::string_view source) {
return hex_decode_with_delimiter(buffer, source, 0);
}
size_t tokenize(const std::string& source,
size_t tokenize(absl::string_view source,
char delimiter,
std::vector<std::string>* fields) {
fields->clear();
@ -160,146 +142,61 @@ size_t tokenize(const std::string& source,
for (size_t i = 0; i < source.length(); ++i) {
if (source[i] == delimiter) {
if (i != last) {
fields->push_back(source.substr(last, i - last));
fields->emplace_back(source.substr(last, i - last));
}
last = i + 1;
}
}
if (last != source.length()) {
fields->push_back(source.substr(last, source.length() - last));
fields->emplace_back(source.substr(last, source.length() - last));
}
return fields->size();
}
size_t tokenize_with_empty_tokens(const std::string& source,
char delimiter,
std::vector<std::string>* fields) {
fields->clear();
size_t last = 0;
for (size_t i = 0; i < source.length(); ++i) {
if (source[i] == delimiter) {
fields->push_back(source.substr(last, i - last));
last = i + 1;
}
}
fields->push_back(source.substr(last, source.length() - last));
return fields->size();
}
size_t tokenize_append(const std::string& source,
char delimiter,
std::vector<std::string>* fields) {
if (!fields)
return 0;
std::vector<std::string> new_fields;
tokenize(source, delimiter, &new_fields);
fields->insert(fields->end(), new_fields.begin(), new_fields.end());
return fields->size();
}
size_t tokenize(const std::string& source,
char delimiter,
char start_mark,
char end_mark,
std::vector<std::string>* fields) {
if (!fields)
return 0;
fields->clear();
std::string remain_source = source;
while (!remain_source.empty()) {
size_t start_pos = remain_source.find(start_mark);
if (std::string::npos == start_pos)
break;
std::string pre_mark;
if (start_pos > 0) {
pre_mark = remain_source.substr(0, start_pos - 1);
}
++start_pos;
size_t end_pos = remain_source.find(end_mark, start_pos);
if (std::string::npos == end_pos)
break;
// We have found the matching marks. First tokenize the pre-mask. Then add
// the marked part as a single field. Finally, loop back for the post-mark.
tokenize_append(pre_mark, delimiter, fields);
fields->push_back(remain_source.substr(start_pos, end_pos - start_pos));
remain_source = remain_source.substr(end_pos + 1);
}
return tokenize_append(remain_source, delimiter, fields);
}
bool tokenize_first(const std::string& source,
bool tokenize_first(absl::string_view source,
const char delimiter,
std::string* token,
std::string* rest) {
// Find the first delimiter
size_t left_pos = source.find(delimiter);
if (left_pos == std::string::npos) {
if (left_pos == absl::string_view::npos) {
return false;
}
// Look for additional occurrances of delimiter.
size_t right_pos = left_pos + 1;
while (source[right_pos] == delimiter) {
while (right_pos < source.size() && source[right_pos] == delimiter) {
right_pos++;
}
*token = source.substr(0, left_pos);
*rest = source.substr(right_pos);
*token = std::string(source.substr(0, left_pos));
*rest = std::string(source.substr(right_pos));
return true;
}
std::string join(const std::vector<std::string>& source, char delimiter) {
if (source.size() == 0) {
return std::string();
}
// Find length of the string to be returned to pre-allocate memory.
size_t source_string_length = 0;
for (size_t i = 0; i < source.size(); ++i) {
source_string_length += source[i].length();
}
// Build the joined string.
std::string joined_string;
joined_string.reserve(source_string_length + source.size() - 1);
for (size_t i = 0; i < source.size(); ++i) {
if (i != 0) {
joined_string += delimiter;
}
joined_string += source[i];
}
return joined_string;
}
size_t split(const std::string& source,
char delimiter,
std::vector<std::string>* fields) {
RTC_DCHECK(fields);
fields->clear();
std::vector<absl::string_view> split(absl::string_view source, char delimiter) {
std::vector<absl::string_view> fields;
size_t last = 0;
for (size_t i = 0; i < source.length(); ++i) {
if (source[i] == delimiter) {
fields->push_back(source.substr(last, i - last));
fields.push_back(source.substr(last, i - last));
last = i + 1;
}
}
fields->push_back(source.substr(last, source.length() - last));
return fields->size();
fields.push_back(source.substr(last));
return fields;
}
std::string ToString(const bool b) {
return b ? "true" : "false";
}
std::string ToString(const char* const s) {
std::string ToString(absl::string_view s) {
return std::string(s);
}
std::string ToString(const std::string s) {
return s;
std::string ToString(const char* s) {
return std::string(s);
}
std::string ToString(const short s) {
@ -372,7 +269,7 @@ std::string ToString(const void* const p) {
return std::string(&buf[0], len);
}
bool FromString(const std::string& s, bool* b) {
bool FromString(absl::string_view s, bool* b) {
if (s == "false") {
*b = false;
return true;

View File

@ -17,7 +17,9 @@
#include <type_traits>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/string_to_number.h"
@ -27,79 +29,36 @@ namespace rtc {
// String Encoding Utilities
//////////////////////////////////////////////////////////////////////
std::string hex_encode(const std::string& str);
std::string hex_encode(const char* source, size_t srclen);
std::string hex_encode_with_delimiter(const char* source,
size_t srclen,
char delimiter);
std::string hex_encode(absl::string_view str);
std::string hex_encode_with_delimiter(absl::string_view source, char delimiter);
// hex_decode converts ascii hex to binary.
size_t hex_decode(char* buffer,
size_t buflen,
const char* source,
size_t srclen);
size_t hex_decode(ArrayView<char> buffer, absl::string_view source);
// hex_decode, assuming that there is a delimiter between every byte
// pair.
// |delimiter| == 0 means no delimiter
// `delimiter` == 0 means no delimiter
// If the buffer is too short or the data is invalid, we return 0.
size_t hex_decode_with_delimiter(char* buffer,
size_t buflen,
const char* source,
size_t srclen,
size_t hex_decode_with_delimiter(ArrayView<char> buffer,
absl::string_view source,
char delimiter);
// Helper functions for hex_decode.
size_t hex_decode(char* buffer, size_t buflen, const std::string& source);
size_t hex_decode_with_delimiter(char* buffer,
size_t buflen,
const std::string& source,
char delimiter);
// Joins the source vector of strings into a single string, with each
// field in source being separated by delimiter. No trailing delimiter is added.
std::string join(const std::vector<std::string>& source, char delimiter);
// Splits the source string into multiple fields separated by delimiter,
// with duplicates of delimiter creating empty fields.
size_t split(const std::string& source,
char delimiter,
std::vector<std::string>* fields);
// with duplicates of delimiter creating empty fields. Empty input produces a
// single, empty, field.
std::vector<absl::string_view> split(absl::string_view source, char delimiter);
// Splits the source string into multiple fields separated by delimiter,
// with duplicates of delimiter ignored. Trailing delimiter ignored.
size_t tokenize(const std::string& source,
size_t tokenize(absl::string_view source,
char delimiter,
std::vector<std::string>* fields);
// Tokenize, including the empty tokens.
size_t tokenize_with_empty_tokens(const std::string& source,
char delimiter,
std::vector<std::string>* fields);
// Tokenize and append the tokens to fields. Return the new size of fields.
size_t tokenize_append(const std::string& source,
char delimiter,
std::vector<std::string>* fields);
// Splits the source string into multiple fields separated by delimiter, with
// duplicates of delimiter ignored. Trailing delimiter ignored. A substring in
// between the start_mark and the end_mark is treated as a single field. Return
// the size of fields. For example, if source is "filename
// \"/Library/Application Support/media content.txt\"", delimiter is ' ', and
// the start_mark and end_mark are '"', this method returns two fields:
// "filename" and "/Library/Application Support/media content.txt".
size_t tokenize(const std::string& source,
char delimiter,
char start_mark,
char end_mark,
std::vector<std::string>* fields);
// Extract the first token from source as separated by delimiter, with
// duplicates of delimiter ignored. Return false if the delimiter could not be
// found, otherwise return true.
bool tokenize_first(const std::string& source,
const char delimiter,
bool tokenize_first(absl::string_view source,
char delimiter,
std::string* token,
std::string* rest);
@ -107,8 +66,10 @@ bool tokenize_first(const std::string& source,
// TODO(jonasolsson): Remove these when absl::StrCat becomes available.
std::string ToString(bool b);
std::string ToString(absl::string_view s);
// The const char* overload is needed for correct overload resolution because of
// the const void* version of ToString() below.
std::string ToString(const char* s);
std::string ToString(std::string t);
std::string ToString(short s);
std::string ToString(unsigned short s);
@ -128,7 +89,7 @@ template <typename T,
typename std::enable_if<std::is_arithmetic<T>::value &&
!std::is_same<T, bool>::value,
int>::type = 0>
static bool FromString(const std::string& s, T* t) {
static bool FromString(absl::string_view s, T* t) {
RTC_DCHECK(t);
absl::optional<T> result = StringToNumber<T>(s);
@ -138,10 +99,10 @@ static bool FromString(const std::string& s, T* t) {
return result.has_value();
}
bool FromString(const std::string& s, bool* b);
bool FromString(absl::string_view s, bool* b);
template <typename T>
static inline T FromString(const std::string& str) {
static inline T FromString(absl::string_view str) {
T val;
FromString(str, &val);
return val;

View File

@ -20,30 +20,41 @@
namespace rtc {
namespace string_to_number_internal {
absl::optional<signed_type> ParseSigned(const char* str, int base) {
RTC_DCHECK(str);
if (isdigit(str[0]) || str[0] == '-') {
absl::optional<signed_type> ParseSigned(absl::string_view str, int base) {
if (str.empty())
return absl::nullopt;
if (isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-') {
std::string str_str(str);
char* end = nullptr;
errno = 0;
const signed_type value = std::strtoll(str, &end, base);
if (end && *end == '\0' && errno == 0) {
const signed_type value = std::strtoll(str_str.c_str(), &end, base);
// Check for errors and also make sure that there were no embedded nuls in
// the input string.
if (end == str_str.c_str() + str_str.size() && errno == 0) {
return value;
}
}
return absl::nullopt;
}
absl::optional<unsigned_type> ParseUnsigned(const char* str, int base) {
RTC_DCHECK(str);
if (isdigit(str[0]) || str[0] == '-') {
absl::optional<unsigned_type> ParseUnsigned(absl::string_view str, int base) {
if (str.empty())
return absl::nullopt;
if (isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-') {
std::string str_str(str);
// Explicitly discard negative values. std::strtoull parsing causes unsigned
// wraparound. We cannot just reject values that start with -, though, since
// -0 is perfectly fine, as is -0000000000000000000000000000000.
const bool is_negative = str[0] == '-';
char* end = nullptr;
errno = 0;
const unsigned_type value = std::strtoull(str, &end, base);
if (end && *end == '\0' && errno == 0 && (value == 0 || !is_negative)) {
const unsigned_type value = std::strtoull(str_str.c_str(), &end, base);
// Check for errors and also make sure that there were no embedded nuls in
// the input string.
if (end == str_str.c_str() + str_str.size() && errno == 0 &&
(value == 0 || !is_negative)) {
return value;
}
}
@ -69,22 +80,25 @@ inline long double StrToT(const char* str, char** str_end) {
}
template <typename T>
absl::optional<T> ParseFloatingPoint(const char* str) {
RTC_DCHECK(str);
if (*str == '\0')
absl::optional<T> ParseFloatingPoint(absl::string_view str) {
if (str.empty())
return absl::nullopt;
if (str[0] == '\0')
return absl::nullopt;
std::string str_str(str);
char* end = nullptr;
errno = 0;
const T value = StrToT<T>(str, &end);
if (end && *end == '\0' && errno == 0) {
const T value = StrToT<T>(str_str.c_str(), &end);
if (end == str_str.c_str() + str_str.size() && errno == 0) {
return value;
}
return absl::nullopt;
}
template absl::optional<float> ParseFloatingPoint(const char* str);
template absl::optional<double> ParseFloatingPoint(const char* str);
template absl::optional<long double> ParseFloatingPoint(const char* str);
template absl::optional<float> ParseFloatingPoint(absl::string_view str);
template absl::optional<double> ParseFloatingPoint(absl::string_view str);
template absl::optional<long double> ParseFloatingPoint(absl::string_view str);
} // namespace string_to_number_internal
} // namespace rtc

View File

@ -15,6 +15,7 @@
#include <string>
#include <type_traits>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
namespace rtc {
@ -25,10 +26,9 @@ namespace rtc {
// functions (std::stoi, etc.) indicate errors by throwing exceptions, which
// are disabled in WebRTC.
//
// Integers are parsed using one of the following functions:
// absl::optional<int-type> StringToNumber(const char* str, int base = 10);
// absl::optional<int-type> StringToNumber(const std::string& str,
// int base = 10);
// Integers are parsed using:
// absl::optional<int-type> StringToNumber(absl::string_view str,
// int base = 10);
//
// These functions parse a value from the beginning of a string into one of the
// fundamental integer types, or returns an empty Optional if parsing
@ -38,26 +38,23 @@ namespace rtc {
// By setting base to 0, one of octal, decimal or hexadecimal will be
// detected from the string's prefix (0, nothing or 0x, respectively).
// If non-zero, base can be set to a value between 2 and 36 inclusively.
//
// If desired, this interface could be extended with support for floating-point
// types.
namespace string_to_number_internal {
// These must be (unsigned) long long, to match the signature of strto(u)ll.
using unsigned_type = unsigned long long; // NOLINT(runtime/int)
using signed_type = long long; // NOLINT(runtime/int)
absl::optional<signed_type> ParseSigned(const char* str, int base);
absl::optional<unsigned_type> ParseUnsigned(const char* str, int base);
absl::optional<signed_type> ParseSigned(absl::string_view str, int base);
absl::optional<unsigned_type> ParseUnsigned(absl::string_view str, int base);
template <typename T>
absl::optional<T> ParseFloatingPoint(const char* str);
absl::optional<T> ParseFloatingPoint(absl::string_view str);
} // namespace string_to_number_internal
template <typename T>
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value,
absl::optional<T>>::type
StringToNumber(const char* str, int base = 10) {
StringToNumber(absl::string_view str, int base = 10) {
using string_to_number_internal::signed_type;
static_assert(
std::numeric_limits<T>::max() <=
@ -78,7 +75,7 @@ template <typename T>
typename std::enable_if<std::is_integral<T>::value &&
std::is_unsigned<T>::value,
absl::optional<T>>::type
StringToNumber(const char* str, int base = 10) {
StringToNumber(absl::string_view str, int base = 10) {
using string_to_number_internal::unsigned_type;
static_assert(std::numeric_limits<T>::max() <=
std::numeric_limits<unsigned_type>::max(),
@ -95,7 +92,7 @@ StringToNumber(const char* str, int base = 10) {
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value,
absl::optional<T>>::type
StringToNumber(const char* str, int base = 10) {
StringToNumber(absl::string_view str, int base = 10) {
static_assert(
std::numeric_limits<T>::max() <= std::numeric_limits<long double>::max(),
"StringToNumber only supports floating-point numbers as large "
@ -103,14 +100,6 @@ StringToNumber(const char* str, int base = 10) {
return string_to_number_internal::ParseFloatingPoint<T>(str);
}
// The std::string overloads only exists if there is a matching const char*
// version.
template <typename T>
auto StringToNumber(const std::string& str, int base = 10)
-> decltype(StringToNumber<T>(str.c_str(), base)) {
return StringToNumber<T>(str.c_str(), base);
}
} // namespace rtc
#endif // RTC_BASE_STRING_TO_NUMBER_H_

View File

@ -10,39 +10,23 @@
#include "rtc_base/string_utils.h"
#include "absl/strings/string_view.h"
namespace rtc {
size_t strcpyn(char* buffer,
size_t buflen,
const char* source,
size_t srclen /* = SIZE_UNKNOWN */) {
size_t strcpyn(char* buffer, size_t buflen, absl::string_view source) {
if (buflen <= 0)
return 0;
if (srclen == SIZE_UNKNOWN) {
srclen = strlen(source);
}
size_t srclen = source.length();
if (srclen >= buflen) {
srclen = buflen - 1;
}
memcpy(buffer, source, srclen);
memcpy(buffer, source.data(), srclen);
buffer[srclen] = 0;
return srclen;
}
static const char kWhitespace[] = " \n\r\t";
std::string string_trim(const std::string& s) {
std::string::size_type first = s.find_first_not_of(kWhitespace);
std::string::size_type last = s.find_last_not_of(kWhitespace);
if (first == std::string::npos || last == std::string::npos) {
return std::string("");
}
return s.substr(first, last - first + 1);
}
std::string ToHex(const int i) {
char buffer[50];
snprintf(buffer, sizeof(buffer), "%x", i);

View File

@ -11,11 +11,11 @@
#ifndef RTC_BASE_STRING_UTILS_H_
#define RTC_BASE_STRING_UTILS_H_
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "absl/strings/string_view.h"
#if defined(WEBRTC_WIN)
#include <malloc.h>
#include <wchar.h>
@ -30,15 +30,26 @@
#include <string>
#include "absl/strings/string_view.h"
namespace rtc {
const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
// An absl::string_view comparator functor for use with container types such as
// std::map that support heterogenous lookup.
//
// Example usage:
// std::map<std::string, int, rtc::AbslStringViewCmp> my_map;
struct AbslStringViewCmp {
using is_transparent = void;
bool operator()(absl::string_view a, absl::string_view b) const {
return a < b;
}
};
// Safe version of strncpy that always nul-terminate.
size_t strcpyn(char* buffer,
size_t buflen,
const char* source,
size_t srclen = SIZE_UNKNOWN);
size_t strcpyn(char* buffer, size_t buflen, absl::string_view source);
///////////////////////////////////////////////////////////////////////////////
// UTF helpers (Windows only)
@ -57,7 +68,7 @@ inline std::wstring ToUtf16(const char* utf8, size_t len) {
return ws;
}
inline std::wstring ToUtf16(const std::string& str) {
inline std::wstring ToUtf16(absl::string_view str) {
return ToUtf16(str.data(), str.length());
}
@ -82,11 +93,45 @@ inline std::string ToUtf8(const std::wstring& wstr) {
#endif // WEBRTC_WIN
// Remove leading and trailing whitespaces.
std::string string_trim(const std::string& s);
// TODO(jonasolsson): replace with absl::Hex when that becomes available.
std::string ToHex(const int i);
std::string ToHex(int i);
// CompileTimeString comprises of a string-like object which can be used as a
// regular const char* in compile time and supports concatenation. Useful for
// concatenating constexpr strings in for example macro declarations.
namespace rtc_base_string_utils_internal {
template <int NPlus1>
struct CompileTimeString {
char string[NPlus1] = {0};
constexpr CompileTimeString() = default;
template <int MPlus1>
explicit constexpr CompileTimeString(const char (&chars)[MPlus1]) {
char* chars_pointer = string;
for (auto c : chars)
*chars_pointer++ = c;
}
template <int MPlus1>
constexpr auto Concat(CompileTimeString<MPlus1> b) {
CompileTimeString<NPlus1 + MPlus1 - 1> result;
char* chars_pointer = result.string;
for (auto c : string)
*chars_pointer++ = c;
chars_pointer = result.string + NPlus1 - 1;
for (auto c : b.string)
*chars_pointer++ = c;
result.string[NPlus1 + MPlus1 - 2] = 0;
return result;
}
constexpr operator const char*() { return string; }
};
} // namespace rtc_base_string_utils_internal
// Makes a constexpr CompileTimeString<X> without having to specify X
// explicitly.
template <int N>
constexpr auto MakeCompileTimeString(const char (&a)[N]) {
return rtc_base_string_utils_internal::CompileTimeString<N>(a);
}
} // namespace rtc

View File

@ -15,6 +15,7 @@
#include <cstdio>
#include <cstring>
#include "absl/strings/string_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_minmax.h"
@ -26,16 +27,20 @@ SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView<char> buffer)
RTC_DCHECK(IsConsistent());
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(const char* str) {
return Append(str, strlen(str));
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) {
return Append(&ch, 1);
return operator<<(absl::string_view(&ch, 1));
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(const std::string& str) {
return Append(str.c_str(), str.length());
SimpleStringBuilder& SimpleStringBuilder::operator<<(absl::string_view str) {
RTC_DCHECK_LT(size_ + str.length(), buffer_.size())
<< "Buffer size was insufficient";
const size_t chars_added =
rtc::SafeMin(str.length(), buffer_.size() - size_ - 1);
memcpy(&buffer_[size_], str.data(), chars_added);
size_ += chars_added;
buffer_[size_] = '\0';
RTC_DCHECK(IsConsistent());
return *this;
}
// Numeric conversion routines.
@ -98,7 +103,7 @@ SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) {
} else {
// This should never happen, but we're paranoid, so re-write the
// terminator in case vsnprintf() overwrote it.
RTC_NOTREACHED();
RTC_DCHECK_NOTREACHED();
buffer_[size_] = '\0';
}
va_end(args);
@ -106,18 +111,6 @@ SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) {
return *this;
}
SimpleStringBuilder& SimpleStringBuilder::Append(const char* str,
size_t length) {
RTC_DCHECK_LT(size_ + length, buffer_.size())
<< "Buffer size was insufficient";
const size_t chars_added = rtc::SafeMin(length, buffer_.size() - size_ - 1);
memcpy(&buffer_[size_], str, chars_added);
size_ += chars_added;
buffer_[size_] = '\0';
RTC_DCHECK(IsConsistent());
return *this;
}
StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) {
va_list args, copy;
va_start(args, fmt);

View File

@ -25,16 +25,15 @@ namespace rtc {
// when you might otherwise be tempted to use a stringstream (discouraged for
// anything except logging). It uses a fixed-size buffer provided by the caller
// and concatenates strings and numbers into it, allowing the results to be
// read via |str()|.
// read via `str()`.
class SimpleStringBuilder {
public:
explicit SimpleStringBuilder(rtc::ArrayView<char> buffer);
SimpleStringBuilder(const SimpleStringBuilder&) = delete;
SimpleStringBuilder& operator=(const SimpleStringBuilder&) = delete;
SimpleStringBuilder& operator<<(const char* str);
SimpleStringBuilder& operator<<(char ch);
SimpleStringBuilder& operator<<(const std::string& str);
SimpleStringBuilder& operator<<(absl::string_view str);
SimpleStringBuilder& operator<<(int i);
SimpleStringBuilder& operator<<(unsigned i);
SimpleStringBuilder& operator<<(long i); // NOLINT
@ -45,12 +44,12 @@ class SimpleStringBuilder {
SimpleStringBuilder& operator<<(double f);
SimpleStringBuilder& operator<<(long double f);
// Returns a pointer to the built string. The name |str()| is borrowed for
// Returns a pointer to the built string. The name `str()` is borrowed for
// compatibility reasons as we replace usage of stringstream throughout the
// code base.
const char* str() const { return buffer_.data(); }
// Returns the length of the string. The name |size()| is picked for STL
// Returns the length of the string. The name `size()` is picked for STL
// compatibility reasons.
size_t size() const { return size_; }
@ -61,10 +60,6 @@ class SimpleStringBuilder {
SimpleStringBuilder&
AppendFormat(const char* fmt, ...);
// An alternate way from operator<<() to append a string. This variant is
// slightly more efficient when the length of the string to append, is known.
SimpleStringBuilder& Append(const char* str, size_t length);
private:
bool IsConsistent() const {
return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0';

View File

@ -17,8 +17,8 @@
#include <utility>
#include <vector>
#include "absl/base/attributes.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/unused.h"
namespace webrtc {
@ -127,7 +127,7 @@ class SwapQueue {
// When specified, the T given in *input must pass the ItemVerifier() test.
// The contents of *input after the call are then also guaranteed to pass the
// ItemVerifier() test.
bool Insert(T* input) RTC_WARN_UNUSED_RESULT {
ABSL_MUST_USE_RESULT bool Insert(T* input) {
RTC_DCHECK(input);
RTC_DCHECK(queue_item_verifier_(*input));
@ -168,7 +168,7 @@ class SwapQueue {
// empty). When specified, The T given in *output must pass the ItemVerifier()
// test and the contents of *output after the call are then also guaranteed to
// pass the ItemVerifier() test.
bool Remove(T* output) RTC_WARN_UNUSED_RESULT {
ABSL_MUST_USE_RESULT bool Remove(T* output) {
RTC_DCHECK(output);
RTC_DCHECK(queue_item_verifier_(*output));

View File

@ -20,9 +20,8 @@ rtc_library("yield") {
deps = []
}
rtc_library("mutex") {
rtc_source_set("mutex") {
sources = [
"mutex.cc",
"mutex.h",
"mutex_critical_section.h",
"mutex_pthread.h",
@ -36,7 +35,7 @@ rtc_library("mutex") {
"..:checks",
"..:macromagic",
"..:platform_thread_types",
"../system:unused",
"../system:no_unique_address",
]
absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ]
if (rtc_use_absl_mutex) {
@ -44,33 +43,15 @@ rtc_library("mutex") {
}
}
rtc_library("rw_lock_wrapper") {
public = [ "rw_lock_wrapper.h" ]
sources = [ "rw_lock_wrapper.cc" ]
deps = [ "..:macromagic" ]
if (is_win) {
sources += [
"rw_lock_win.cc",
"rw_lock_win.h",
]
deps += [ "..:logging" ]
} else {
sources += [
"rw_lock_posix.cc",
"rw_lock_posix.h",
]
}
}
rtc_library("sequence_checker") {
rtc_library("sequence_checker_internal") {
visibility = [ "../../api:sequence_checker" ]
sources = [
"sequence_checker.cc",
"sequence_checker.h",
"sequence_checker_internal.cc",
"sequence_checker_internal.h",
]
deps = [
":mutex",
"..:checks",
"..:criticalsection",
"..:macromagic",
"..:platform_thread_types",
"..:stringutils",
@ -91,7 +72,7 @@ rtc_library("yield_policy") {
]
}
if (rtc_include_tests) {
if (rtc_include_tests && rtc_enable_google_benchmarks) {
rtc_library("synchronization_unittests") {
testonly = true
sources = [
@ -104,8 +85,9 @@ if (rtc_include_tests) {
":yield_policy",
"..:checks",
"..:macromagic",
"..:rtc_base",
"..:platform_thread",
"..:rtc_event",
"..:threading",
"../../test:test_support",
"//third_party/google_benchmark",
]
@ -120,19 +102,4 @@ if (rtc_include_tests) {
"//third_party/google_benchmark",
]
}
rtc_library("sequence_checker_unittests") {
testonly = true
sources = [ "sequence_checker_unittest.cc" ]
deps = [
":sequence_checker",
"..:checks",
"..:rtc_base_approved",
"..:task_queue_for_test",
"../../api:function_view",
"../../test:test_main",
"../../test:test_support",
]
}
}

View File

@ -1,39 +0,0 @@
/*
* 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

View File

@ -13,9 +13,9 @@
#include <atomic>
#include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/unused.h"
#include "rtc_base/thread_annotations.h"
#if defined(WEBRTC_ABSL_MUTEX)
@ -38,15 +38,15 @@ class RTC_LOCKABLE Mutex final {
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
impl_.Lock();
}
RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { impl_.Lock(); }
ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return impl_.TryLock();
}
void Unlock() RTC_UNLOCK_FUNCTION() {
impl_.Unlock();
}
// Return immediately if this thread holds the mutex, or RTC_DCHECK_IS_ON==0.
// Otherwise, may report an error (typically by crashing with a diagnostic),
// or may return immediately.
void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { impl_.AssertHeld(); }
void Unlock() RTC_UNLOCK_FUNCTION() { impl_.Unlock(); }
private:
MutexImpl impl_;
@ -68,41 +68,6 @@ class RTC_SCOPED_LOCKABLE MutexLock final {
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(mutex_);
~GlobalMutexLock() RTC_UNLOCK_FUNCTION();
private:
GlobalMutex* mutex_;
};
#endif // if defined(WEBRTC_ABSL_MUTEX)
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_

View File

@ -23,6 +23,7 @@
#include <sal.h> // must come after windows headers.
// clang-format on
#include "absl/base/attributes.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
@ -37,9 +38,10 @@ class RTC_LOCKABLE MutexImpl final {
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
EnterCriticalSection(&critical_section_);
}
RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return TryEnterCriticalSection(&critical_section_) != FALSE;
}
void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() {}
void Unlock() RTC_UNLOCK_FUNCTION() {
LeaveCriticalSection(&critical_section_);
}

View File

@ -18,6 +18,8 @@
#include <pthread_spis.h>
#endif
#include "absl/base/attributes.h"
#include "rtc_base/system/no_unique_address.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
@ -38,14 +40,60 @@ class RTC_LOCKABLE MutexImpl final {
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 Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
pthread_mutex_lock(&mutex_);
owner_.SetOwner();
}
ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
if (pthread_mutex_trylock(&mutex_) != 0) {
return false;
}
owner_.SetOwner();
return true;
}
void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { owner_.AssertOwned(); }
void Unlock() RTC_UNLOCK_FUNCTION() {
owner_.ClearOwner();
pthread_mutex_unlock(&mutex_);
}
void Unlock() RTC_UNLOCK_FUNCTION() { pthread_mutex_unlock(&mutex_); }
private:
class OwnerRecord {
public:
#if !RTC_DCHECK_IS_ON
void SetOwner() {}
void ClearOwner() {}
void AssertOwned() const {}
#else
void SetOwner() {
latest_owner_ = pthread_self();
is_owned_ = true;
}
void ClearOwner() { is_owned_ = false; }
void AssertOwned() const {
RTC_CHECK(is_owned_);
RTC_CHECK(pthread_equal(latest_owner_, pthread_self()));
}
private:
// Use two separate primitive types, rather than absl::optional, since the
// data race described below might invalidate absl::optional invariants.
bool is_owned_ = false;
pthread_t latest_owner_ = pthread_self();
#endif
};
pthread_mutex_t mutex_;
// This record is modified only with the mutex held, and hence, calls to
// AssertHeld where mutex is held are race-free and will always succeed.
//
// The failure case is more subtle: If AssertHeld is called from some thread
// not holding the mutex, and RTC_DCHECK_IS_ON==1, we have a data race. It is
// highly likely that the calling thread will see `is_owned_` false or
// `latest_owner_` different from itself, and crash. But it may fail to crash,
// and invoke some other undefined behavior (still, this race can happen only
// when RTC_DCHECK_IS_ON==1).
RTC_NO_UNIQUE_ADDRESS OwnerRecord owner_;
};
} // namespace webrtc

View File

@ -1,52 +0,0 @@
/*
* Copyright (c) 2011 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/rw_lock_posix.h"
#include <stddef.h>
namespace webrtc {
RWLockPosix::RWLockPosix() : lock_() {}
RWLockPosix::~RWLockPosix() {
pthread_rwlock_destroy(&lock_);
}
RWLockPosix* RWLockPosix::Create() {
RWLockPosix* ret_val = new RWLockPosix();
if (!ret_val->Init()) {
delete ret_val;
return NULL;
}
return ret_val;
}
bool RWLockPosix::Init() {
return pthread_rwlock_init(&lock_, 0) == 0;
}
void RWLockPosix::AcquireLockExclusive() {
pthread_rwlock_wrlock(&lock_);
}
void RWLockPosix::ReleaseLockExclusive() {
pthread_rwlock_unlock(&lock_);
}
void RWLockPosix::AcquireLockShared() {
pthread_rwlock_rdlock(&lock_);
}
void RWLockPosix::ReleaseLockShared() {
pthread_rwlock_unlock(&lock_);
}
} // namespace webrtc

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2011 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_RW_LOCK_POSIX_H_
#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_
#include <pthread.h>
#include "rtc_base/synchronization/rw_lock_wrapper.h"
namespace webrtc {
class RWLockPosix : public RWLockWrapper {
public:
static RWLockPosix* Create();
~RWLockPosix() override;
void AcquireLockExclusive() override;
void ReleaseLockExclusive() override;
void AcquireLockShared() override;
void ReleaseLockShared() override;
private:
RWLockPosix();
bool Init();
pthread_rwlock_t lock_;
};
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_

View File

@ -1,41 +0,0 @@
/*
* Copyright (c) 2012 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/rw_lock_win.h"
#include "rtc_base/logging.h"
namespace webrtc {
RWLockWin::RWLockWin() {
InitializeSRWLock(&lock_);
}
RWLockWin* RWLockWin::Create() {
return new RWLockWin();
}
void RWLockWin::AcquireLockExclusive() {
AcquireSRWLockExclusive(&lock_);
}
void RWLockWin::ReleaseLockExclusive() {
ReleaseSRWLockExclusive(&lock_);
}
void RWLockWin::AcquireLockShared() {
AcquireSRWLockShared(&lock_);
}
void RWLockWin::ReleaseLockShared() {
ReleaseSRWLockShared(&lock_);
}
} // namespace webrtc

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2012 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_RW_LOCK_WIN_H_
#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_
#include <windows.h>
#include "rtc_base/synchronization/rw_lock_wrapper.h"
namespace webrtc {
class RWLockWin : public RWLockWrapper {
public:
static RWLockWin* Create();
void AcquireLockExclusive() override;
void ReleaseLockExclusive() override;
void AcquireLockShared() override;
void ReleaseLockShared() override;
private:
RWLockWin();
SRWLOCK lock_;
};
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2011 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_RW_LOCK_WRAPPER_H_
#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_
#include "rtc_base/thread_annotations.h"
// Note, Windows pre-Vista version of RW locks are not supported natively. For
// these OSs regular critical sections have been used to approximate RW lock
// functionality and will therefore have worse performance.
namespace webrtc {
class RTC_LOCKABLE RWLockWrapper {
public:
static RWLockWrapper* CreateRWLock();
virtual ~RWLockWrapper() {}
virtual void AcquireLockExclusive() RTC_EXCLUSIVE_LOCK_FUNCTION() = 0;
virtual void ReleaseLockExclusive() RTC_UNLOCK_FUNCTION() = 0;
virtual void AcquireLockShared() RTC_SHARED_LOCK_FUNCTION() = 0;
virtual void ReleaseLockShared() RTC_UNLOCK_FUNCTION() = 0;
};
// RAII extensions of the RW lock. Prevents Acquire/Release missmatches and
// provides more compact locking syntax.
class RTC_SCOPED_LOCKABLE ReadLockScoped {
public:
explicit ReadLockScoped(RWLockWrapper& rw_lock)
RTC_SHARED_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockShared();
}
~ReadLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockShared(); }
private:
RWLockWrapper& rw_lock_;
};
class RTC_SCOPED_LOCKABLE WriteLockScoped {
public:
explicit WriteLockScoped(RWLockWrapper& rw_lock)
RTC_EXCLUSIVE_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockExclusive();
}
~WriteLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockExclusive(); }
private:
RWLockWrapper& rw_lock_;
};
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_

View File

@ -1,187 +0,0 @@
/*
* Copyright 2019 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_SEQUENCE_CHECKER_H_
#define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
#include <type_traits>
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// Real implementation of SequenceChecker, for use in debug mode, or
// for temporary use in release mode (e.g. to RTC_CHECK on a threading issue
// seen only in the wild).
//
// Note: You should almost always use the SequenceChecker class to get the
// right version for your build configuration.
class RTC_EXPORT SequenceCheckerImpl {
public:
SequenceCheckerImpl();
~SequenceCheckerImpl();
bool IsCurrent() const;
// Changes the task queue or thread that is checked for in IsCurrent. This can
// be useful when an object may be created on one task queue / thread and then
// 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:
mutable Mutex lock_;
// These are mutable so that IsCurrent can set them.
mutable bool attached_ RTC_GUARDED_BY(lock_);
mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_);
mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_);
mutable const void* valid_system_queue_ RTC_GUARDED_BY(lock_);
};
// Do nothing implementation, for use in release mode.
//
// Note: You should almost always use the SequenceChecker class to get the
// right version for your build configuration.
class SequenceCheckerDoNothing {
public:
bool IsCurrent() const { return true; }
void Detach() {}
};
// SequenceChecker is a helper class used to help verify that some methods
// of a class are called on the same task queue or thread. A
// SequenceChecker is bound to a a task queue if the object is
// created on a task queue, or a thread otherwise.
//
//
// Example:
// class MyClass {
// public:
// void Foo() {
// RTC_DCHECK_RUN_ON(sequence_checker_);
// ... (do stuff) ...
// }
//
// private:
// SequenceChecker sequence_checker_;
// }
//
// In Release mode, IsCurrent will always return true.
#if RTC_DCHECK_IS_ON
class RTC_LOCKABLE SequenceChecker : public SequenceCheckerImpl {};
#else
class RTC_LOCKABLE SequenceChecker : public SequenceCheckerDoNothing {};
#endif // RTC_ENABLE_THREAD_CHECKER
namespace webrtc_seq_check_impl {
// Helper class used by RTC_DCHECK_RUN_ON (see example usage below).
class RTC_SCOPED_LOCKABLE SequenceCheckerScope {
public:
template <typename ThreadLikeObject>
explicit SequenceCheckerScope(const ThreadLikeObject* thread_like_object)
RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
SequenceCheckerScope(const SequenceCheckerScope&) = delete;
SequenceCheckerScope& operator=(const SequenceCheckerScope&) = delete;
~SequenceCheckerScope() RTC_UNLOCK_FUNCTION() {}
template <typename ThreadLikeObject>
static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
return thread_like_object->IsCurrent();
}
};
} // namespace webrtc_seq_check_impl
} // namespace webrtc
// RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate
// variables are accessed from same thread/task queue.
// Using tools designed to check mutexes, it checks at compile time everywhere
// variable is access, there is a run-time dcheck thread/task queue is correct.
//
// class ThreadExample {
// public:
// void NeedVar1() {
// RTC_DCHECK_RUN_ON(network_thread_);
// transport_->Send();
// }
//
// private:
// rtc::Thread* network_thread_;
// int transport_ RTC_GUARDED_BY(network_thread_);
// };
//
// class SequenceCheckerExample {
// public:
// int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) {
// return var2_;
// }
//
// void CallMeFromPacer() {
// RTC_DCHECK_RUN_ON(&pacer_sequence_checker_)
// << "Should be called from pacer";
// CalledFromPacer();
// }
//
// private:
// int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_);
// SequenceChecker pacer_sequence_checker_;
// };
//
// class TaskQueueExample {
// public:
// class Encoder {
// public:
// rtc::TaskQueue* Queue() { return encoder_queue_; }
// void Encode() {
// RTC_DCHECK_RUN_ON(encoder_queue_);
// DoSomething(var_);
// }
//
// private:
// rtc::TaskQueue* const encoder_queue_;
// Frame var_ RTC_GUARDED_BY(encoder_queue_);
// };
//
// void Encode() {
// // Will fail at runtime when DCHECK is enabled:
// // encoder_->Encode();
// // Will work:
// rtc::scoped_refptr<Encoder> encoder = encoder_;
// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
// }
//
// private:
// rtc::scoped_refptr<Encoder> encoder_;
// }
// Document if a function expected to be called from same thread/task queue.
#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()) << webrtc::ExpectationToString(x)
#endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_

View File

@ -7,61 +7,39 @@
* 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/sequence_checker.h"
#include "rtc_base/synchronization/sequence_checker_internal.h"
#if defined(WEBRTC_MAC)
#include <dispatch/dispatch.h>
#endif
#include <string>
#include "rtc_base/checks.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
namespace {
// On Mac, returns the label of the current dispatch queue; elsewhere, return
// null.
const void* GetSystemQueueRef() {
#if defined(WEBRTC_MAC)
return dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
#else
return nullptr;
#endif
}
namespace webrtc_sequence_checker_internal {
} // namespace
std::string ExpectationToString(const webrtc::SequenceChecker* checker) {
#if RTC_DCHECK_IS_ON
return checker->ExpectationToString();
#endif
return std::string();
}
SequenceCheckerImpl::SequenceCheckerImpl()
: attached_(true),
SequenceCheckerImpl::SequenceCheckerImpl(bool attach_to_current_thread)
: attached_(attach_to_current_thread),
valid_thread_(rtc::CurrentThreadRef()),
valid_queue_(TaskQueueBase::Current()),
valid_system_queue_(GetSystemQueueRef()) {}
valid_queue_(TaskQueueBase::Current()) {}
SequenceCheckerImpl::~SequenceCheckerImpl() = default;
SequenceCheckerImpl::SequenceCheckerImpl(TaskQueueBase* attached_queue)
: attached_(attached_queue != nullptr),
valid_thread_(rtc::PlatformThreadRef()),
valid_queue_(attached_queue) {}
bool SequenceCheckerImpl::IsCurrent() const {
const TaskQueueBase* const current_queue = TaskQueueBase::Current();
const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef();
const void* const current_system_queue = GetSystemQueueRef();
MutexLock scoped_lock(&lock_);
if (!attached_) { // Previously detached.
attached_ = true;
valid_thread_ = current_thread;
valid_queue_ = current_queue;
valid_system_queue_ = current_system_queue;
return true;
}
if (valid_queue_ || current_queue) {
if (valid_queue_) {
return valid_queue_ == current_queue;
}
if (valid_system_queue_ && valid_system_queue_ == current_system_queue) {
return true;
}
return rtc::IsThreadRefEqual(valid_thread_, current_thread);
}
@ -76,7 +54,6 @@ void SequenceCheckerImpl::Detach() {
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();
MutexLock scoped_lock(&lock_);
if (!attached_)
return "Checker currently not attached.";
@ -90,17 +67,13 @@ std::string SequenceCheckerImpl::ExpectationToString() const {
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));
"# Expected: TQ: %p Thread: %p\n"
"# Actual: TQ: %p Thread: %p\n",
valid_queue_, reinterpret_cast<const void*>(valid_thread_), current_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";
}
@ -109,4 +82,5 @@ std::string SequenceCheckerImpl::ExpectationToString() const {
}
#endif // RTC_DCHECK_IS_ON
} // namespace webrtc_sequence_checker_internal
} // namespace webrtc

View File

@ -0,0 +1,90 @@
/*
* 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_SEQUENCE_CHECKER_INTERNAL_H_
#define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_
#include <string>
#include <type_traits>
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
namespace webrtc_sequence_checker_internal {
// Real implementation of SequenceChecker, for use in debug mode, or
// for temporary use in release mode (e.g. to RTC_CHECK on a threading issue
// seen only in the wild).
//
// Note: You should almost always use the SequenceChecker class to get the
// right version for your build configuration.
class RTC_EXPORT SequenceCheckerImpl {
public:
explicit SequenceCheckerImpl(bool attach_to_current_thread);
explicit SequenceCheckerImpl(TaskQueueBase* attached_queue);
~SequenceCheckerImpl() = default;
bool IsCurrent() const;
// Changes the task queue or thread that is checked for in IsCurrent. This can
// be useful when an object may be created on one task queue / thread and then
// 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:
mutable Mutex lock_;
// These are mutable so that IsCurrent can set them.
mutable bool attached_ RTC_GUARDED_BY(lock_);
mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_);
mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_);
};
// Do nothing implementation, for use in release mode.
//
// Note: You should almost always use the SequenceChecker class to get the
// right version for your build configuration.
class SequenceCheckerDoNothing {
public:
explicit SequenceCheckerDoNothing(bool attach_to_current_thread) {}
explicit SequenceCheckerDoNothing(TaskQueueBase* attached_queue) {}
bool IsCurrent() const { return true; }
void Detach() {}
};
template <typename ThreadLikeObject>
std::enable_if_t<std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>,
std::string>
ExpectationToString(const ThreadLikeObject* checker) {
#if RTC_DCHECK_IS_ON
return checker->ExpectationToString();
#else
return std::string();
#endif
}
// Catch-all implementation for types other than explicitly supported above.
template <typename ThreadLikeObject>
std::enable_if_t<!std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>,
std::string>
ExpectationToString(const ThreadLikeObject*) {
return std::string();
}
} // namespace webrtc_sequence_checker_internal
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_

View File

@ -0,0 +1,111 @@
# Copyright (c) 2018 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.
import("../../webrtc.gni")
if (is_android) {
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
}
rtc_source_set("arch") {
sources = [ "arch.h" ]
}
rtc_source_set("asm_defines") {
sources = [ "asm_defines.h" ]
}
rtc_library("file_wrapper") {
sources = [
"file_wrapper.cc",
"file_wrapper.h",
]
deps = [
"..:checks",
"..:criticalsection",
"..:safe_conversions",
]
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
}
if (rtc_include_tests) {
rtc_library("file_wrapper_unittests") {
testonly = true
sources = [ "file_wrapper_unittest.cc" ]
deps = [
":file_wrapper",
"//rtc_base:checks",
"//test:fileutils",
"//test:test_support",
]
}
}
rtc_source_set("ignore_warnings") {
sources = [ "ignore_warnings.h" ]
}
rtc_source_set("inline") {
sources = [ "inline.h" ]
}
rtc_source_set("unused") {
sources = [ "unused.h" ]
}
rtc_source_set("assume") {
sources = [ "assume.h" ]
}
rtc_source_set("rtc_export") {
sources = [
"rtc_export.h",
"rtc_export_template.h",
]
}
rtc_source_set("no_unique_address") {
sources = [ "no_unique_address.h" ]
}
rtc_source_set("no_cfi_icall") {
sources = [ "no_cfi_icall.h" ]
deps = [ "..:sanitizer" ]
}
if (is_mac || is_ios) {
rtc_library("cocoa_threading") {
sources = [
"cocoa_threading.h",
"cocoa_threading.mm",
]
deps = [ "..:checks" ]
frameworks = [ "Foundation.framework" ]
}
rtc_library("gcd_helpers") {
sources = [
"gcd_helpers.h",
"gcd_helpers.m",
]
include_dirs = [ "../.." ]
}
}
rtc_source_set("warn_current_thread_is_deadlocked") {
sources = [ "warn_current_thread_is_deadlocked.h" ]
deps = []
if (is_android && !build_with_chromium) {
sources += [ "warn_current_thread_is_deadlocked.cc" ]
deps += [
"..:logging",
"../../sdk/android:native_api_stacktrace",
]
}
}

View File

@ -73,6 +73,16 @@
#elif defined(__riscv) && __riscv_xlen == 32
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__loongarch32)
#define WEBRTC_ARCH_LOONG_FAMILY
#define WEBRTC_ARCH_LOONG32
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__loongarch64)
#define WEBRTC_ARCH_LOONG_FAMILY
#define WEBRTC_ARCH_LOONG64
#define WEBRTC_ARCH_64_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__pnacl__)
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN

View File

@ -9,28 +9,37 @@
*/
#include "rtc_base/system/file_wrapper.h"
#include "rtc_base/numerics/safe_conversions.h"
#include <stddef.h>
#include <cerrno>
#include <cstdint>
#include <string>
#include "absl/strings/string_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#ifdef _WIN32
#include <windows.h>
#include <Windows.h>
#else
#include <string.h>
#endif
#include <utility>
namespace webrtc {
namespace {
FILE* FileOpen(const char* file_name_utf8, bool read_only, int* error) {
FILE* FileOpen(absl::string_view file_name_utf8, bool read_only, int* error) {
RTC_CHECK_EQ(file_name_utf8.find_first_of('\0'), absl::string_view::npos)
<< "Invalid filename, containing NUL character";
std::string file_name(file_name_utf8);
#if defined(_WIN32)
int len = MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, nullptr, 0);
int len = MultiByteToWideChar(CP_UTF8, 0, file_name.c_str(), -1, nullptr, 0);
std::wstring wstr(len, 0);
MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, &wstr[0], len);
MultiByteToWideChar(CP_UTF8, 0, file_name.c_str(), -1, &wstr[0], len);
FILE* file = _wfopen(wstr.c_str(), read_only ? L"rb" : L"wb");
#else
FILE* file = fopen(file_name_utf8, read_only ? "rb" : "wb");
FILE* file = fopen(file_name.c_str(), read_only ? "rb" : "wb");
#endif
if (!file && error) {
*error = errno;
@ -38,36 +47,19 @@ FILE* FileOpen(const char* file_name_utf8, bool read_only, int* error) {
return file;
}
const char* GetCstrCheckNoEmbeddedNul(const std::string& s) {
const char* p = s.c_str();
RTC_CHECK_EQ(strlen(p), s.size())
<< "Invalid filename, containing NUL character";
return p;
}
} // namespace
// static
FileWrapper FileWrapper::OpenReadOnly(const char* file_name_utf8) {
FileWrapper FileWrapper::OpenReadOnly(absl::string_view file_name_utf8) {
return FileWrapper(FileOpen(file_name_utf8, true, nullptr));
}
// static
FileWrapper FileWrapper::OpenReadOnly(const std::string& file_name_utf8) {
return OpenReadOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8));
}
// static
FileWrapper FileWrapper::OpenWriteOnly(const char* file_name_utf8,
FileWrapper FileWrapper::OpenWriteOnly(absl::string_view file_name_utf8,
int* error /*=nullptr*/) {
return FileWrapper(FileOpen(file_name_utf8, false, error));
}
// static
FileWrapper FileWrapper::OpenWriteOnly(const std::string& file_name_utf8,
int* error /*=nullptr*/) {
return OpenWriteOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8), error);
}
FileWrapper::FileWrapper(FileWrapper&& other) {
operator=(std::move(other));
}
@ -89,6 +81,22 @@ bool FileWrapper::SeekTo(int64_t position) {
return fseek(file_, rtc::checked_cast<long>(position), SEEK_SET) == 0;
}
long FileWrapper::FileSize() {
if (file_ == nullptr)
return -1;
long original_position = ftell(file_);
if (original_position < 0)
return -1;
int seek_error = fseek(file_, 0, SEEK_END);
if (seek_error)
return -1;
long file_size = ftell(file_);
seek_error = fseek(file_, original_position, SEEK_SET);
if (seek_error)
return -1;
return file_size;
}
bool FileWrapper::Flush() {
RTC_DCHECK(file_);
return fflush(file_) == 0;

View File

@ -12,11 +12,14 @@
#define RTC_BASE_SYSTEM_FILE_WRAPPER_H_
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdint.h>
#include <string>
#include "absl/strings/string_view.h"
// Implementation that can read (exclusive) or write from/to a file.
namespace webrtc {
@ -33,20 +36,16 @@ class FileWrapper final {
public:
// Opens a file, in read or write mode. Use the is_open() method on the
// returned object to check if the open operation was successful. On failure,
// and if |error| is non-null, the system errno value is stored at |*error|.
// and if `error` is non-null, the system errno value is stored at |*error|.
// The file is closed by the destructor.
static FileWrapper OpenReadOnly(const char* file_name_utf8);
static FileWrapper OpenReadOnly(const std::string& file_name_utf8);
static FileWrapper OpenWriteOnly(const char* file_name_utf8,
int* error = nullptr);
static FileWrapper OpenWriteOnly(const std::string& file_name_utf8,
static FileWrapper OpenReadOnly(absl::string_view file_name_utf8);
static FileWrapper OpenWriteOnly(absl::string_view file_name_utf8,
int* error = nullptr);
FileWrapper() = default;
// Takes over ownership of |file|, closing it on destruction. Calling with
// null |file| is allowed, and results in a FileWrapper with is_open() false.
// Takes over ownership of `file`, closing it on destruction. Calling with
// null `file` is allowed, and results in a FileWrapper with is_open() false.
explicit FileWrapper(FILE* file) : file_(file) {}
~FileWrapper() { Close(); }
@ -88,6 +87,11 @@ class FileWrapper final {
// Seek to given position.
bool SeekTo(int64_t position);
// Returns the file size or -1 if a size could not be determined.
// (A file size might not exists for non-seekable files or file-like
// objects, for example /dev/tty on unix.)
long FileSize();
// Returns number of bytes read. Short count indicates EOF or error.
size_t Read(void* buf, size_t length);

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 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_SYSTEM_NO_UNIQUE_ADDRESS_H_
#define RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_
// RTC_NO_UNIQUE_ADDRESS is a portable annotation to tell the compiler that
// a data member need not have an address distinct from all other non-static
// data members of its class.
// It allows empty types to actually occupy zero bytes as class members,
// instead of occupying at least one byte just so that they get their own
// address. There is almost never any reason not to use it on class members
// that could possibly be empty.
// The macro expands to [[no_unique_address]] if the compiler supports the
// attribute, it expands to nothing otherwise.
// Clang should supports this attribute since C++11, while other compilers
// should add support for it starting from C++20. Among clang compilers,
// clang-cl doesn't support it yet and support is unclear also when the target
// platform is iOS.
#ifndef __has_cpp_attribute
#define __has_cpp_attribute(x) 0
#endif
#if __has_cpp_attribute(no_unique_address)
// NOLINTNEXTLINE(whitespace/braces)
#define RTC_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define RTC_NO_UNIQUE_ADDRESS
#endif
#endif // RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_

View File

@ -11,29 +11,18 @@
#ifndef RTC_BASE_SYSTEM_UNUSED_H_
#define RTC_BASE_SYSTEM_UNUSED_H_
// Annotate a function indicating the caller must examine the return value.
// Use like:
// int foo() RTC_WARN_UNUSED_RESULT;
// To explicitly ignore a result, cast to void.
// TODO(kwiberg): Remove when we can use [[nodiscard]] from C++17.
#if defined(__clang__)
#define RTC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
#elif defined(__GNUC__)
// gcc has a __warn_unused_result__ attribute, but you can't quiet it by
// casting to void, so we don't use it.
#define RTC_WARN_UNUSED_RESULT
#else
#define RTC_WARN_UNUSED_RESULT
#endif
// Prevent the compiler from warning about an unused variable. For example:
// int result = DoSomething();
// assert(result == 17);
// RTC_DCHECK(result == 17);
// RTC_UNUSED(result);
// Note: In most cases it is better to remove the unused variable rather than
// suppressing the compiler warning.
#ifndef RTC_UNUSED
#ifdef __cplusplus
#define RTC_UNUSED(x) static_cast<void>(x)
#else
#define RTC_UNUSED(x) (void)(x)
#endif
#endif // RTC_UNUSED
#endif // RTC_BASE_SYSTEM_UNUSED_H_

View File

@ -0,0 +1,28 @@
/*
* Copyright 2019 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/system/warn_current_thread_is_deadlocked.h"
#include "rtc_base/logging.h"
#if 0
# commented out to prevent pulling in extra android files
#include "sdk/android/native_api/stacktrace/stacktrace.h"
#endif
namespace webrtc {
void WarnThatTheCurrentThreadIsProbablyDeadlocked() {
RTC_LOG(LS_WARNING) << "Probable deadlock:";
#if 0
RTC_LOG(LS_WARNING) << StackTraceToString(GetStackTrace());
#endif
}
} // namespace webrtc

View File

@ -14,11 +14,7 @@
namespace webrtc {
#if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
/* webrtc-audio-processing:
* We don't support the Android SDK integration for this, so stub out
void WarnThatTheCurrentThreadIsProbablyDeadlocked();
*/
inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {}
#else
inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {}
#endif

View File

@ -0,0 +1,102 @@
/*
* Copyright 2021 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.
*/
// If WEBRTC_EXCLUDE_SYSTEM_TIME is set, an implementation of
// rtc::SystemTimeNanos() must be provided externally.
#ifndef WEBRTC_EXCLUDE_SYSTEM_TIME
#include <stdint.h>
#include <limits>
#if defined(WEBRTC_POSIX)
#include <sys/time.h>
#if defined(WEBRTC_MAC)
#include <mach/mach_time.h>
#endif
#endif
#if defined(WEBRTC_WIN)
// clang-format off
// clang formatting would put <windows.h> last,
// which leads to compilation failure.
#include <windows.h>
#include <mmsystem.h>
#include <sys/timeb.h>
// clang-format on
#endif
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/system_time.h"
#include "rtc_base/time_utils.h"
namespace rtc {
int64_t SystemTimeNanos() {
int64_t ticks;
#if defined(WEBRTC_MAC)
static mach_timebase_info_data_t timebase;
if (timebase.denom == 0) {
// Get the timebase if this is the first time we run.
// Recommended by Apple's QA1398.
if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
RTC_DCHECK_NOTREACHED();
}
}
// Use timebase to convert absolute time tick units into nanoseconds.
const auto mul = [](uint64_t a, uint32_t b) -> int64_t {
RTC_DCHECK_NE(b, 0);
RTC_DCHECK_LE(a, std::numeric_limits<int64_t>::max() / b)
<< "The multiplication " << a << " * " << b << " overflows";
return rtc::dchecked_cast<int64_t>(a * b);
};
ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom;
#elif defined(WEBRTC_POSIX)
struct timespec ts;
// TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not
// supported?
clock_gettime(CLOCK_MONOTONIC, &ts);
ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
static_cast<int64_t>(ts.tv_nsec);
#elif defined(WINUWP)
ticks = WinUwpSystemTimeNanos();
#elif defined(WEBRTC_WIN)
// TODO(webrtc:14601): Fix the volatile increment instead of suppressing the
// warning.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-volatile"
static volatile LONG last_timegettime = 0;
static volatile int64_t num_wrap_timegettime = 0;
volatile LONG* last_timegettime_ptr = &last_timegettime;
DWORD now = timeGetTime();
// Atomically update the last gotten time
DWORD old = InterlockedExchange(last_timegettime_ptr, now);
if (now < old) {
// If now is earlier than old, there may have been a race between threads.
// 0x0fffffff ~3.1 days, the code will not take that long to execute
// so it must have been a wrap around.
if (old > 0xf0000000 && now < 0x0fffffff) {
num_wrap_timegettime++;
}
}
ticks = now + (num_wrap_timegettime << 32);
// TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
// just wasting a multiply and divide when doing Time() on Windows.
ticks = ticks * kNumNanosecsPerMillisec;
#pragma clang diagnostic pop
#else
#error Unsupported platform.
#endif
return ticks;
}
} // namespace rtc
#endif // WEBRTC_EXCLUDE_SYSTEM_TIME

View File

@ -0,0 +1,24 @@
/*
* Copyright 2021 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_SYSTEM_TIME_H_
#define RTC_BASE_SYSTEM_TIME_H_
#include <cstdint>
namespace rtc {
// Returns the actual system time, even if a clock is set for testing.
// Useful for timeouts while using a test clock, or for logging.
int64_t SystemTimeNanos();
} // namespace rtc
#endif // RTC_BASE_SYSTEM_TIME_H_

View File

@ -88,6 +88,9 @@
#define RTC_UNLOCK_FUNCTION(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
#define RTC_ASSERT_EXCLUSIVE_LOCK(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
// An escape hatch for thread safety analysis to ignore the annotated function.
#define RTC_NO_THREAD_SAFETY_ANALYSIS \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

View File

@ -1,27 +0,0 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/threading/thread_checker.h.
#ifndef RTC_BASE_THREAD_CHECKER_H_
#define RTC_BASE_THREAD_CHECKER_H_
#include "rtc_base/deprecation.h"
#include "rtc_base/synchronization/sequence_checker.h"
namespace rtc {
// TODO(srte): Replace usages of this with SequenceChecker.
class ThreadChecker : public webrtc::SequenceChecker {
public:
RTC_DEPRECATED bool CalledOnValidThread() const { return IsCurrent(); }
RTC_DEPRECATED void DetachFromThread() { Detach(); }
};
} // namespace rtc
#endif // RTC_BASE_THREAD_CHECKER_H_

View File

@ -12,27 +12,29 @@
#if defined(WEBRTC_POSIX)
#include <sys/time.h>
#if defined(WEBRTC_MAC)
#include <mach/mach_time.h>
#endif
#endif
#if defined(WEBRTC_WIN)
// clang-format off
// clang formatting would put <windows.h> last,
// which leads to compilation failure.
#include <windows.h>
#include <mmsystem.h>
#include <sys/timeb.h>
// clang-format on
#endif
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/system_time.h"
#include "rtc_base/time_utils.h"
#if defined(WEBRTC_WIN)
#include "rtc_base/win32.h"
#endif
#if defined(WEBRTC_WIN)
#include <minwinbase.h>
#endif
namespace rtc {
#if defined(WEBRTC_WIN) || defined(WINUWP)
// FileTime (January 1st 1601) to Unix time (January 1st 1970)
// offset in units of 100ns.
static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
116444736000000000ULL;
static constexpr uint64_t kFileTimeToMicroSeconds = 10LL;
#endif
ClockInterface* g_clock = nullptr;
ClockInterface* SetClockForTesting(ClockInterface* clock) {
@ -123,8 +125,6 @@ class TimeHelper final {
}
private:
static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
116444736000000000ULL;
static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L;
// The number of nanoseconds since unix system epoch
@ -141,61 +141,12 @@ void SyncWithNtp(int64_t time_from_ntp_server_ms) {
TimeHelper::SyncWithNtp(time_from_ntp_server_ms);
}
#endif // defined(WINUWP)
int64_t SystemTimeNanos() {
int64_t ticks;
#if defined(WEBRTC_MAC)
static mach_timebase_info_data_t timebase;
if (timebase.denom == 0) {
// Get the timebase if this is the first time we run.
// Recommended by Apple's QA1398.
if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
RTC_NOTREACHED();
}
}
// Use timebase to convert absolute time tick units into nanoseconds.
const auto mul = [](uint64_t a, uint32_t b) -> int64_t {
RTC_DCHECK_NE(b, 0);
RTC_DCHECK_LE(a, std::numeric_limits<int64_t>::max() / b)
<< "The multiplication " << a << " * " << b << " overflows";
return rtc::dchecked_cast<int64_t>(a * b);
};
ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom;
#elif defined(WEBRTC_POSIX)
struct timespec ts;
// TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not
// supported?
clock_gettime(CLOCK_MONOTONIC, &ts);
ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
static_cast<int64_t>(ts.tv_nsec);
#elif defined(WINUWP)
ticks = TimeHelper::TicksNs();
#elif defined(WEBRTC_WIN)
static volatile LONG last_timegettime = 0;
static volatile int64_t num_wrap_timegettime = 0;
volatile LONG* last_timegettime_ptr = &last_timegettime;
DWORD now = timeGetTime();
// Atomically update the last gotten time
DWORD old = InterlockedExchange(last_timegettime_ptr, now);
if (now < old) {
// If now is earlier than old, there may have been a race between threads.
// 0x0fffffff ~3.1 days, the code will not take that long to execute
// so it must have been a wrap around.
if (old > 0xf0000000 && now < 0x0fffffff) {
num_wrap_timegettime++;
}
}
ticks = now + (num_wrap_timegettime << 32);
// TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
// just wasting a multiply and divide when doing Time() on Windows.
ticks = ticks * kNumNanosecsPerMillisec;
#else
#error Unsupported platform.
#endif
return ticks;
int64_t WinUwpSystemTimeNanos() {
return TimeHelper::TicksNs();
}
#endif // defined(WINUWP)
int64_t SystemTimeMillis() {
return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec);
}
@ -232,28 +183,6 @@ int64_t TimeDiff(int64_t later, int64_t earlier) {
return later - earlier;
}
TimestampWrapAroundHandler::TimestampWrapAroundHandler()
: last_ts_(0), num_wrap_(-1) {}
int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) {
if (num_wrap_ == -1) {
last_ts_ = ts;
num_wrap_ = 0;
return ts;
}
if (ts < last_ts_) {
if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff)
++num_wrap_;
} else if ((ts - last_ts_) > 0xf0000000) {
// Backwards wrap. Unwrap with last wrap count and don't update last_ts_.
return ts + (num_wrap_ - 1) * (int64_t{1} << 32);
}
last_ts_ = ts;
return ts + (num_wrap_ << 32);
}
int64_t TmToSeconds(const tm& tm) {
static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151,
@ -289,11 +218,11 @@ int64_t TmToSeconds(const tm& tm) {
// We will have added one day too much above if expiration is during a leap
// year, and expiration is in January or February.
if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based.
if (expiry_in_leap_year && month <= 2 - 1) // `month` is zero based.
day -= 1;
// Combine all variables into seconds from 1970-01-01 00:00 (except |month|
// which was accumulated into |day| above).
// Combine all variables into seconds from 1970-01-01 00:00 (except `month`
// which was accumulated into `day` above).
return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 +
min) *
60 +
@ -310,13 +239,15 @@ int64_t TimeUTCMicros() {
// Convert from second (1.0) and microsecond (1e-6).
return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec +
time.tv_usec);
#elif defined(WEBRTC_WIN)
struct _timeb time;
_ftime(&time);
// Convert from second (1.0) and milliseconds (1e-3).
return (static_cast<int64_t>(time.time) * rtc::kNumMicrosecsPerSec +
static_cast<int64_t>(time.millitm) * rtc::kNumMicrosecsPerMillisec);
FILETIME ft;
// This will give us system file in UTC format in multiples of 100ns.
GetSystemTimeAsFileTime(&ft);
LARGE_INTEGER li;
li.HighPart = ft.dwHighDateTime;
li.LowPart = ft.dwLowDateTime;
return (li.QuadPart - kFileTimeToUnixTimeEpochOffset) /
kFileTimeToMicroSeconds;
#endif
}

View File

@ -16,6 +16,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/system_time.h"
namespace rtc {
@ -30,6 +31,12 @@ static const int64_t kNumNanosecsPerMillisec =
static const int64_t kNumNanosecsPerMicrosec =
kNumNanosecsPerSec / kNumMicrosecsPerSec;
// Elapsed milliseconds between NTP base, 1900 January 1 00:00 GMT
// (see https://tools.ietf.org/html/rfc868), and January 1 00:00 GMT 1970
// epoch. This is useful when converting between the NTP time base and the
// time base used in RTCP reports.
constexpr int64_t kNtpJan1970Millisecs = 2'208'988'800 * kNumMillisecsPerSec;
// TODO(honghaiz): Define a type for the time value specifically.
class ClockInterface {
@ -61,11 +68,16 @@ RTC_EXPORT ClockInterface* GetClockForTesting();
// Synchronizes the current clock based upon an NTP server's epoch in
// milliseconds.
void SyncWithNtp(int64_t time_from_ntp_server_ms);
// Returns the current time in nanoseconds. The clock is synchonized with the
// system wall clock time upon instatiation. It may also be synchronized using
// the SyncWithNtp() function above. Please note that the clock will most likely
// drift away from the system wall clock time as time goes by.
int64_t WinUwpSystemTimeNanos();
#endif // defined(WINUWP)
// Returns the actual system time, even if a clock is set for testing.
// Useful for timeouts while using a test clock, or for logging.
int64_t SystemTimeNanos();
int64_t SystemTimeMillis();
// Returns the current time in milliseconds in 32 bits.
@ -102,17 +114,6 @@ inline int64_t TimeUntil(int64_t later) {
return later - TimeMillis();
}
class TimestampWrapAroundHandler {
public:
TimestampWrapAroundHandler();
int64_t Unwrap(uint32_t ts);
private:
uint32_t last_ts_;
int64_t num_wrap_;
};
// Convert from tm, which is relative to 1900-01-01 00:00 to number of
// seconds from 1970-01-01 00:00 ("epoch"). Don't return time_t since that
// is still 32 bits on many systems.

File diff suppressed because it is too large Load Diff

View File

@ -10,13 +10,14 @@ import("../../webrtc.gni")
rtc_source_set("unit_base") {
visibility = [
"../../api/units:*",
":*",
"../../api/units:*",
]
sources = [ "unit_base.h" ]
deps = [
"../../rtc_base:checks",
"../../rtc_base:divide_round",
"../../rtc_base:safe_conversions",
]
}

View File

@ -18,6 +18,7 @@
#include <type_traits>
#include "rtc_base/checks.h"
#include "rtc_base/numerics/divide_round.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
@ -50,22 +51,22 @@ class UnitBase {
return value_ == MinusInfinityVal();
}
constexpr bool operator==(const Unit_T& other) const {
constexpr bool operator==(const UnitBase<Unit_T>& other) const {
return value_ == other.value_;
}
constexpr bool operator!=(const Unit_T& other) const {
constexpr bool operator!=(const UnitBase<Unit_T>& other) const {
return value_ != other.value_;
}
constexpr bool operator<=(const Unit_T& other) const {
constexpr bool operator<=(const UnitBase<Unit_T>& other) const {
return value_ <= other.value_;
}
constexpr bool operator>=(const Unit_T& other) const {
constexpr bool operator>=(const UnitBase<Unit_T>& other) const {
return value_ >= other.value_;
}
constexpr bool operator>(const Unit_T& other) const {
constexpr bool operator>(const UnitBase<Unit_T>& other) const {
return value_ > other.value_;
}
constexpr bool operator<(const Unit_T& other) const {
constexpr bool operator<(const UnitBase<Unit_T>& other) const {
return value_ < other.value_;
}
constexpr Unit_T RoundTo(const Unit_T& resolution) const {
@ -140,10 +141,9 @@ class UnitBase {
template <typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
ToValue() const {
return IsPlusInfinity()
? std::numeric_limits<T>::infinity()
: IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
: value_;
return IsPlusInfinity() ? std::numeric_limits<T>::infinity()
: IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
: value_;
}
template <typename T>
constexpr T ToValueOr(T fallback_value) const {
@ -154,12 +154,7 @@ class UnitBase {
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
ToFraction() const {
RTC_DCHECK(IsFinite());
if (Unit_T::one_sided) {
return rtc::dchecked_cast<T>(
DivRoundPositiveToNearest(value_, Denominator));
} else {
return rtc::dchecked_cast<T>(DivRoundToNearest(value_, Denominator));
}
return rtc::dchecked_cast<T>(DivideRoundToNearest(value_, Denominator));
}
template <int64_t Denominator, typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
@ -169,9 +164,7 @@ class UnitBase {
template <int64_t Denominator>
constexpr int64_t ToFractionOr(int64_t fallback_value) const {
return IsFinite() ? Unit_T::one_sided
? DivRoundPositiveToNearest(value_, Denominator)
: DivRoundToNearest(value_, Denominator)
return IsFinite() ? DivideRoundToNearest(value_, Denominator)
: fallback_value;
}
@ -205,14 +198,6 @@ class UnitBase {
constexpr const Unit_T& AsSubClassRef() const {
return static_cast<const Unit_T&>(*this);
}
// Assumes that n >= 0 and d > 0.
static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) {
return (n + d / 2) / d;
}
// Assumes that d > 0.
static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) {
return (n + (n >= 0 ? d / 2 : -d / 2)) / d;
}
int64_t value_;
};
@ -266,14 +251,18 @@ class RelativeUnit : public UnitBase<Unit_T> {
return UnitBase<Unit_T>::template ToValue<double>() /
other.template ToValue<double>();
}
template <typename T>
constexpr typename std::enable_if<std::is_arithmetic<T>::value, Unit_T>::type
operator/(const T& scalar) const {
return UnitBase<Unit_T>::FromValue(
std::round(UnitBase<Unit_T>::template ToValue<int64_t>() / scalar));
template <typename T,
typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
constexpr Unit_T operator/(T scalar) const {
return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() / scalar));
}
template <typename T,
typename std::enable_if_t<std::is_integral_v<T>>* = nullptr>
constexpr Unit_T operator/(T scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() / scalar);
}
constexpr Unit_T operator*(double scalar) const {
return UnitBase<Unit_T>::FromValue(std::round(this->ToValue() * scalar));
return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() * scalar));
}
constexpr Unit_T operator*(int64_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
@ -281,6 +270,9 @@ class RelativeUnit : public UnitBase<Unit_T> {
constexpr Unit_T operator*(int32_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
constexpr Unit_T operator*(size_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
protected:
using UnitBase<Unit_T>::UnitBase;
@ -298,6 +290,19 @@ template <class Unit_T>
inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator*(size_t scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator-(RelativeUnit<Unit_T> other) {
if (other.IsPlusInfinity())
return UnitBase<Unit_T>::MinusInfinity();
if (other.IsMinusInfinity())
return UnitBase<Unit_T>::PlusInfinity();
return -1 * other;
}
} // namespace rtc_units_impl

View File

@ -20,11 +20,10 @@
#define NOMINMAX
#endif
// clang-format off
// clang formating would change include order.
#include <winsock2.h> // must come first
#include <winsock2.h>
// Must be after winsock2.h.
#include <windows.h>
// clang-format on
typedef int socklen_t;
@ -39,66 +38,11 @@ typedef struct _TOKEN_MANDATORY_LABEL {
#undef SetPort
#include <string>
namespace rtc {
const char* win32_inet_ntop(int af, const void* src, char* dst, socklen_t size);
int win32_inet_pton(int af, const char* src, void* dst);
enum WindowsMajorVersions {
kWindows2000 = 5,
kWindowsVista = 6,
kWindows10 = 10,
};
#if !defined(WINUWP)
bool GetOsVersion(int* major, int* minor, int* build);
inline bool IsWindowsVistaOrLater() {
int major;
return (GetOsVersion(&major, nullptr, nullptr) && major >= kWindowsVista);
}
inline bool IsWindowsXpOrLater() {
int major, minor;
return (GetOsVersion(&major, &minor, nullptr) &&
(major >= kWindowsVista || (major == kWindows2000 && minor >= 1)));
}
inline bool IsWindows8OrLater() {
int major, minor;
return (GetOsVersion(&major, &minor, nullptr) &&
(major > kWindowsVista || (major == kWindowsVista && minor >= 2)));
}
inline bool IsWindows10OrLater() {
int major;
return (GetOsVersion(&major, nullptr, nullptr) && (major >= kWindows10));
}
#else
// When targetting WinUWP the OS must be Windows 10 (or greater) as lesser
// Windows OS targets are not supported.
inline bool IsWindowsVistaOrLater() {
return true;
}
inline bool IsWindowsXpOrLater() {
return true;
}
inline bool IsWindows8OrLater() {
return true;
}
inline bool IsWindows10OrLater() {
return true;
}
#endif // !defined(WINUWP)
} // namespace rtc
#endif // RTC_BASE_WIN32_H_