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:
File diff suppressed because it is too large
Load Diff
@ -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_
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<>()
|
||||
|
56
webrtc/rtc_base/containers/BUILD.gn
Normal file
56
webrtc/rtc_base/containers/BUILD.gn
Normal 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" ]
|
||||
}
|
178
webrtc/rtc_base/containers/flat_set.h
Normal file
178
webrtc/rtc_base/containers/flat_set.h
Normal 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_
|
@ -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
|
1099
webrtc/rtc_base/containers/flat_tree.h
Normal file
1099
webrtc/rtc_base/containers/flat_tree.h
Normal file
File diff suppressed because it is too large
Load Diff
36
webrtc/rtc_base/containers/identity.h
Normal file
36
webrtc/rtc_base/containers/identity.h
Normal 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_
|
@ -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_
|
@ -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_);
|
||||
|
@ -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_
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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>;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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" ]
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
|
60
webrtc/rtc_base/numerics/divide_round.h
Normal file
60
webrtc/rtc_base/numerics/divide_round.h
Normal 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_
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, ¶m) == 0;
|
||||
return pthread_setschedparam(pthread_self(), policy, ¶m) == 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
87
webrtc/rtc_base/random.cc
Normal 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
96
webrtc/rtc_base/random.h
Normal 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_
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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_
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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';
|
||||
|
@ -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));
|
||||
|
@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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_
|
||||
|
@ -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_);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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_
|
@ -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
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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
|
90
webrtc/rtc_base/synchronization/sequence_checker_internal.h
Normal file
90
webrtc/rtc_base/synchronization/sequence_checker_internal.h
Normal 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_
|
111
webrtc/rtc_base/system/BUILD.gn
Normal file
111
webrtc/rtc_base/system/BUILD.gn
Normal 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",
|
||||
]
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
37
webrtc/rtc_base/system/no_unique_address.h
Normal file
37
webrtc/rtc_base/system/no_unique_address.h
Normal 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_
|
@ -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_
|
||||
|
28
webrtc/rtc_base/system/warn_current_thread_is_deadlocked.cc
Normal file
28
webrtc/rtc_base/system/warn_current_thread_is_deadlocked.cc
Normal 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
|
@ -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
|
||||
|
102
webrtc/rtc_base/system_time.cc
Normal file
102
webrtc/rtc_base/system_time.cc
Normal 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
|
24
webrtc/rtc_base/system_time.h
Normal file
24
webrtc/rtc_base/system_time.h
Normal 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_
|
@ -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)
|
||||
|
@ -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_
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
@ -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",
|
||||
]
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_
|
||||
|
Reference in New Issue
Block a user