Update to current webrtc library

This is from the upstream library commit id
3326535126e435f1ba647885ce43a8f0f3d317eb, corresponding to Chromium
88.0.4290.1.
This commit is contained in:
Arun Raghavan
2020-10-12 18:08:02 -04:00
parent b1b02581d3
commit bcec8b0b21
859 changed files with 76187 additions and 49580 deletions

1482
webrtc/rtc_base/BUILD.gn Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
/*
* 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_ARRAYSIZE_H_
#define RTC_BASE_ARRAYSIZE_H_
#include <stddef.h>
// This file defines the arraysize() macro and is derived from Chromium's
// base/macros.h.
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
#endif // RTC_BASE_ARRAYSIZE_H_

View File

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

437
webrtc/rtc_base/buffer.h Normal file
View File

@ -0,0 +1,437 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_BUFFER_H_
#define RTC_BASE_BUFFER_H_
#include <stdint.h>
#include <algorithm>
#include <cstring>
#include <memory>
#include <type_traits>
#include <utility>
#include "api/array_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/type_traits.h"
#include "rtc_base/zero_memory.h"
namespace rtc {
namespace internal {
// (Internal; please don't use outside this file.) Determines if elements of
// type U are compatible with a BufferT<T>. For most types, we just ignore
// top-level const and forbid top-level volatile and require T and U to be
// otherwise equal, but all byte-sized integers (notably char, int8_t, and
// uint8_t) are compatible with each other. (Note: We aim to get rid of this
// behavior, and treat all types the same.)
template <typename T, typename U>
struct BufferCompat {
static constexpr bool value =
!std::is_volatile<U>::value &&
((std::is_integral<T>::value && sizeof(T) == 1)
? (std::is_integral<U>::value && sizeof(U) == 1)
: (std::is_same<T, typename std::remove_const<U>::type>::value));
};
} // namespace internal
// Basic buffer class, can be grown and shrunk dynamically.
// Unlike std::string/vector, does not initialize data when increasing size.
// If "ZeroOnFree" is true, any memory is explicitly cleared before releasing.
// The type alias "ZeroOnFreeBuffer" below should be used instead of setting
// "ZeroOnFree" in the template manually to "true".
template <typename T, bool ZeroOnFree = false>
class BufferT {
// We want T's destructor and default constructor to be trivial, i.e. perform
// no action, so that we don't have to touch the memory we allocate and
// deallocate. And we want T to be trivially copyable, so that we can copy T
// instances with std::memcpy. This is precisely the definition of a trivial
// type.
static_assert(std::is_trivial<T>::value, "T must be a trivial type.");
// This class relies heavily on being able to mutate its data.
static_assert(!std::is_const<T>::value, "T may not be const");
public:
using value_type = T;
using const_iterator = const T*;
// An empty BufferT.
BufferT() : size_(0), capacity_(0), data_(nullptr) {
RTC_DCHECK(IsConsistent());
}
// Disable copy construction and copy assignment, since copying a buffer is
// expensive enough that we want to force the user to be explicit about it.
BufferT(const BufferT&) = delete;
BufferT& operator=(const BufferT&) = delete;
BufferT(BufferT&& buf)
: size_(buf.size()),
capacity_(buf.capacity()),
data_(std::move(buf.data_)) {
RTC_DCHECK(IsConsistent());
buf.OnMovedFrom();
}
// Construct a buffer with the specified number of uninitialized elements.
explicit BufferT(size_t size) : BufferT(size, size) {}
BufferT(size_t size, size_t capacity)
: size_(size),
capacity_(std::max(size, capacity)),
data_(capacity_ > 0 ? new T[capacity_] : nullptr) {
RTC_DCHECK(IsConsistent());
}
// Construct a buffer and copy the specified number of elements into it.
template <typename U,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
BufferT(const U* data, size_t size) : BufferT(data, size, size) {}
template <typename U,
typename std::enable_if<
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));
}
// Construct a buffer from the contents of an array.
template <typename U,
size_t N,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
BufferT(U (&array)[N]) : BufferT(array, N) {}
~BufferT() { MaybeZeroCompleteBuffer(); }
// 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.
template <typename U = T,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
const U* data() const {
RTC_DCHECK(IsConsistent());
return reinterpret_cast<U*>(data_.get());
}
template <typename U = T,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
U* data() {
RTC_DCHECK(IsConsistent());
return reinterpret_cast<U*>(data_.get());
}
bool empty() const {
RTC_DCHECK(IsConsistent());
return size_ == 0;
}
size_t size() const {
RTC_DCHECK(IsConsistent());
return size_;
}
size_t capacity() const {
RTC_DCHECK(IsConsistent());
return capacity_;
}
BufferT& operator=(BufferT&& buf) {
RTC_DCHECK(buf.IsConsistent());
MaybeZeroCompleteBuffer();
size_ = buf.size_;
capacity_ = buf.capacity_;
using std::swap;
swap(data_, buf.data_);
buf.data_.reset();
buf.OnMovedFrom();
return *this;
}
bool operator==(const BufferT& buf) const {
RTC_DCHECK(IsConsistent());
if (size_ != buf.size_) {
return false;
}
if (std::is_integral<T>::value) {
// Optimization.
return std::memcmp(data_.get(), buf.data_.get(), size_ * sizeof(T)) == 0;
}
for (size_t i = 0; i < size_; ++i) {
if (data_[i] != buf.data_[i]) {
return false;
}
}
return true;
}
bool operator!=(const BufferT& buf) const { return !(*this == buf); }
T& operator[](size_t index) {
RTC_DCHECK_LT(index, size_);
return data()[index];
}
T operator[](size_t index) const {
RTC_DCHECK_LT(index, size_);
return data()[index];
}
T* begin() { return data(); }
T* end() { return data() + size(); }
const T* begin() const { return data(); }
const T* end() const { return data() + size(); }
const T* cbegin() const { return data(); }
const T* cend() const { return data() + size(); }
// The SetData functions replace the contents of the buffer. They accept the
// same input types as the constructors.
template <typename U,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
void SetData(const U* data, size_t size) {
RTC_DCHECK(IsConsistent());
const size_t old_size = size_;
size_ = 0;
AppendData(data, size);
if (ZeroOnFree && size_ < old_size) {
ZeroTrailingData(old_size - size_);
}
}
template <typename U,
size_t N,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
void SetData(const U (&array)[N]) {
SetData(array, N);
}
template <typename W,
typename std::enable_if<
HasDataAndSize<const W, const T>::value>::type* = nullptr>
void SetData(const W& w) {
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:
//
// 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
// 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,
typename F,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
size_t SetData(size_t max_elements, F&& setter) {
RTC_DCHECK(IsConsistent());
const size_t old_size = size_;
size_ = 0;
const size_t written = AppendData<U>(max_elements, std::forward<F>(setter));
if (ZeroOnFree && size_ < old_size) {
ZeroTrailingData(old_size - size_);
}
return written;
}
// The AppendData functions add data to the end of the buffer. They accept
// the same input types as the constructors.
template <typename U,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
void AppendData(const U* data, size_t size) {
RTC_DCHECK(IsConsistent());
const size_t new_size = size_ + size;
EnsureCapacityWithHeadroom(new_size, true);
static_assert(sizeof(T) == sizeof(U), "");
std::memcpy(data_.get() + size_, data, size * sizeof(U));
size_ = new_size;
RTC_DCHECK(IsConsistent());
}
template <typename U,
size_t N,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
void AppendData(const U (&array)[N]) {
AppendData(array, N);
}
template <typename W,
typename std::enable_if<
HasDataAndSize<const W, const T>::value>::type* = nullptr>
void AppendData(const W& w) {
AppendData(w.data(), w.size());
}
template <typename U,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
void AppendData(const U& item) {
AppendData(&item, 1);
}
// 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
// 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,
typename F,
typename std::enable_if<
internal::BufferCompat<T, U>::value>::type* = nullptr>
size_t AppendData(size_t max_elements, F&& setter) {
RTC_DCHECK(IsConsistent());
const size_t old_size = size_;
SetSize(old_size + max_elements);
U* base_ptr = data<U>() + old_size;
size_t written_elements = setter(rtc::ArrayView<U>(base_ptr, max_elements));
RTC_CHECK_LE(written_elements, max_elements);
size_ = old_size + written_elements;
RTC_DCHECK(IsConsistent());
return written_elements;
}
// Sets the size of the buffer. If the new size is smaller than the old, the
// buffer contents will be kept but truncated; if the new size is greater,
// the existing contents will be kept and the new space will be
// uninitialized.
void SetSize(size_t size) {
const size_t old_size = size_;
EnsureCapacityWithHeadroom(size, true);
size_ = size;
if (ZeroOnFree && size_ < old_size) {
ZeroTrailingData(old_size - size_);
}
}
// Ensure that the buffer size can be increased to at least capacity without
// further reallocation. (Of course, this operation might need to reallocate
// the buffer.)
void EnsureCapacity(size_t capacity) {
// Don't allocate extra headroom, since the user is asking for a specific
// capacity.
EnsureCapacityWithHeadroom(capacity, false);
}
// Resets the buffer to zero size without altering capacity. Works even if the
// buffer has been moved from.
void Clear() {
MaybeZeroCompleteBuffer();
size_ = 0;
RTC_DCHECK(IsConsistent());
}
// Swaps two buffers. Also works for buffers that have been moved from.
friend void swap(BufferT& a, BufferT& b) {
using std::swap;
swap(a.size_, b.size_);
swap(a.capacity_, b.capacity_);
swap(a.data_, b.data_);
}
private:
void EnsureCapacityWithHeadroom(size_t capacity, bool extra_headroom) {
RTC_DCHECK(IsConsistent());
if (capacity <= capacity_)
return;
// If the caller asks for extra headroom, ensure that the new capacity is
// >= 1.5 times the old capacity. Any constant > 1 is sufficient to prevent
// quadratic behavior; as to why we pick 1.5 in particular, see
// https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md and
// http://www.gahcep.com/cpp-internals-stl-vector-part-1/.
const size_t new_capacity =
extra_headroom ? std::max(capacity, capacity_ + capacity_ / 2)
: capacity;
std::unique_ptr<T[]> new_data(new T[new_capacity]);
if (data_ != nullptr) {
std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T));
}
MaybeZeroCompleteBuffer();
data_ = std::move(new_data);
capacity_ = new_capacity;
RTC_DCHECK(IsConsistent());
}
// Zero the complete buffer if template argument "ZeroOnFree" is true.
void MaybeZeroCompleteBuffer() {
if (ZeroOnFree && capacity_ > 0) {
// It would be sufficient to only zero "size_" elements, as all other
// methods already ensure that the unused capacity contains no sensitive
// data---but better safe than sorry.
ExplicitZeroMemory(data_.get(), capacity_ * sizeof(T));
}
}
// Zero the first "count" elements of unused capacity.
void ZeroTrailingData(size_t count) {
RTC_DCHECK(IsConsistent());
RTC_DCHECK_LE(count, capacity_ - size_);
ExplicitZeroMemory(data_.get() + size_, count * sizeof(T));
}
// Precondition for all methods except Clear, operator= and the destructor.
// Postcondition for all methods except move construction and move
// assignment, which leave the moved-from object in a possibly inconsistent
// state.
bool IsConsistent() const {
return (data_ || capacity_ == 0) && capacity_ >= size_;
}
// Called when *this has been moved from. Conceptually it's a no-op, but we
// can mutate the state slightly to help subsequent sanity checks catch bugs.
void OnMovedFrom() {
RTC_DCHECK(!data_); // Our heap block should have been stolen.
#if RTC_DCHECK_IS_ON
// Ensure that *this is always inconsistent, to provoke bugs.
size_ = 1;
capacity_ = 0;
#else
// Make *this consistent and empty. Shouldn't be necessary, but better safe
// than sorry.
size_ = 0;
capacity_ = 0;
#endif
}
size_t size_;
size_t capacity_;
std::unique_ptr<T[]> data_;
};
// By far the most common sort of buffer.
using Buffer = BufferT<uint8_t>;
// A buffer that zeros memory before releasing it.
template <typename T>
using ZeroOnFreeBuffer = BufferT<T, true>;
} // namespace rtc
#endif // RTC_BASE_BUFFER_H_

207
webrtc/rtc_base/checks.cc Normal file
View File

@ -0,0 +1,207 @@
/*
* Copyright 2006 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.
*/
// Most of this was borrowed (with minor modifications) from V8's and Chromium's
// src/base/logging.cc.
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#if defined(WEBRTC_ANDROID)
#define RTC_LOG_TAG_ANDROID "rtc"
#include <android/log.h> // NOLINT
#endif
#if defined(WEBRTC_WIN)
#include <windows.h>
#endif
#if defined(WEBRTC_WIN)
#define LAST_SYSTEM_ERROR (::GetLastError())
#elif defined(__native_client__) && __native_client__
#define LAST_SYSTEM_ERROR (0)
#elif defined(WEBRTC_POSIX)
#include <errno.h>
#define LAST_SYSTEM_ERROR (errno)
#endif // WEBRTC_WIN
#include "rtc_base/checks.h"
namespace {
#if defined(__GNUC__)
__attribute__((__format__(__printf__, 2, 3)))
#endif
void AppendFormat(std::string* s, const char* fmt, ...) {
va_list args, copy;
va_start(args, fmt);
va_copy(copy, args);
const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
va_end(copy);
if (predicted_length > 0) {
const size_t size = s->size();
s->resize(size + predicted_length);
// Pass "+ 1" to vsnprintf to include space for the '\0'.
std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args);
}
va_end(args);
}
} // namespace
namespace rtc {
namespace webrtc_checks_impl {
#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.
bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) {
if (**fmt == CheckArgType::kEnd)
return false;
switch (**fmt) {
case CheckArgType::kInt:
AppendFormat(s, "%d", va_arg(*args, int));
break;
case CheckArgType::kLong:
AppendFormat(s, "%ld", va_arg(*args, long));
break;
case CheckArgType::kLongLong:
AppendFormat(s, "%lld", va_arg(*args, long long));
break;
case CheckArgType::kUInt:
AppendFormat(s, "%u", va_arg(*args, unsigned));
break;
case CheckArgType::kULong:
AppendFormat(s, "%lu", va_arg(*args, unsigned long));
break;
case CheckArgType::kULongLong:
AppendFormat(s, "%llu", va_arg(*args, unsigned long long));
break;
case CheckArgType::kDouble:
AppendFormat(s, "%g", va_arg(*args, double));
break;
case CheckArgType::kLongDouble:
AppendFormat(s, "%Lg", va_arg(*args, long double));
break;
case CheckArgType::kCharP:
s->append(va_arg(*args, const char*));
break;
case CheckArgType::kStdString:
s->append(*va_arg(*args, const std::string*));
break;
case CheckArgType::kStringView: {
const absl::string_view sv = *va_arg(*args, const absl::string_view*);
s->append(sv.data(), sv.size());
break;
}
case CheckArgType::kVoidP:
AppendFormat(s, "%p", va_arg(*args, const void*));
break;
default:
s->append("[Invalid CheckArgType]");
return false;
}
(*fmt)++;
return true;
}
RTC_NORETURN void FatalLog(const char* file,
int line,
const char* message,
const CheckArgType* fmt,
...) {
va_list args;
va_start(args, fmt);
std::string s;
AppendFormat(&s,
"\n\n"
"#\n"
"# Fatal error in: %s, line %d\n"
"# last system error: %u\n"
"# Check failed: %s",
file, line, LAST_SYSTEM_ERROR, message);
if (*fmt == CheckArgType::kCheckOp) {
// This log message was generated by RTC_CHECK_OP, so we have to complete
// the error message using the operands that have been passed as the first
// two arguments.
fmt++;
std::string s1, s2;
if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2))
AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str());
} else {
s.append("\n# ");
}
// Append all the user-supplied arguments to the message.
while (ParseArg(&args, &fmt, &s))
;
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();
}
#else // RTC_CHECK_MSG_ENABLED
RTC_NORETURN void FatalLog(const char* file, int line) {
std::string s;
AppendFormat(&s,
"\n\n"
"#\n"
"# Fatal error in: %s, line %d\n"
"# last system error: %u\n"
"# 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();
}
#endif // RTC_CHECK_MSG_ENABLED
} // namespace webrtc_checks_impl
} // namespace rtc
// Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros.
RTC_NORETURN void rtc_FatalMessage(const char* file,
int line,
const char* msg) {
#if RTC_CHECK_MSG_ENABLED
static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = {
rtc::webrtc_checks_impl::CheckArgType::kEnd};
rtc::webrtc_checks_impl::FatalLog(file, line, msg, t);
#else
rtc::webrtc_checks_impl::FatalLog(file, line);
#endif
}

485
webrtc/rtc_base/checks.h Normal file
View File

@ -0,0 +1,485 @@
/*
* Copyright 2006 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_CHECKS_H_
#define RTC_BASE_CHECKS_H_
// If you for some reson need to know if DCHECKs are on, test the value of
// RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be
// defined, to either a true or a false value.)
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
#define RTC_DCHECK_IS_ON 1
#else
#define RTC_DCHECK_IS_ON 0
#endif
// Annotate a function that will not return control flow to the caller.
#if defined(_MSC_VER)
#define RTC_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define RTC_NORETURN __attribute__((__noreturn__))
#else
#define RTC_NORETURN
#endif
#ifdef __cplusplus
extern "C" {
#endif
RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef RTC_DISABLE_CHECK_MSG
#define RTC_CHECK_MSG_ENABLED 0
#else
#define RTC_CHECK_MSG_ENABLED 1
#endif
#if RTC_CHECK_MSG_ENABLED
#define RTC_CHECK_EVAL_MESSAGE(message) message
#else
#define RTC_CHECK_EVAL_MESSAGE(message) ""
#endif
#ifdef __cplusplus
// C++ version.
#include <string>
#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
#include "rtc_base/numerics/safe_compare.h"
#include "rtc_base/system/inline.h"
#include "rtc_base/system/rtc_export.h"
// The macros here print a message to stderr and abort under various
// conditions. All will accept additional stream messages. For example:
// RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar.";
//
// - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't,
// it's better to terminate the process than to continue. During development,
// the reason that it's better to terminate might simply be that the error
// handling code isn't in place yet; in production, the reason might be that
// the author of the code truly believes that x will always be true, but that
// they recognizes that if they are wrong, abrupt and unpleasant process
// termination is still better than carrying on with the assumption violated.
//
// RTC_CHECK always evaluates its argument, so it's OK for x to have side
// effects.
//
// - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always
// true---except that x will only be evaluated in debug builds; in production
// builds, x is simply assumed to be true. This is useful if evaluating x is
// expensive and the expected cost of failing to detect the violated
// assumption is acceptable. You should not handle cases where a production
// build fails to spot a violated condition, even those that would result in
// crashes. If the code needs to cope with the error, make it cope, but don't
// call RTC_DCHECK; if the condition really can't occur, but you'd sleep
// better at night knowing that the process will suicide instead of carrying
// on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK.
//
// RTC_DCHECK only evaluates its argument in debug builds, so if x has visible
// side effects, you need to write e.g.
// bool w = x; RTC_DCHECK(w);
//
// - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are
// specialized variants of RTC_CHECK and RTC_DCHECK that print prettier
// messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and
// RTC_DCHECK.
//
// - FATAL() aborts unconditionally.
namespace rtc {
namespace webrtc_checks_impl {
enum class CheckArgType : int8_t {
kEnd = 0,
kInt,
kLong,
kLongLong,
kUInt,
kULong,
kULongLong,
kDouble,
kLongDouble,
kCharP,
kStdString,
kStringView,
kVoidP,
// kCheckOp doesn't represent an argument type. Instead, it is sent as the
// first argument from RTC_CHECK_OP to make FatalLog use the next two
// arguments to build the special CHECK_OP error message
// (the "a == b (1 vs. 2)" bit).
kCheckOp,
};
#if RTC_CHECK_MSG_ENABLED
RTC_NORETURN RTC_EXPORT void FatalLog(const char* file,
int line,
const char* message,
const CheckArgType* fmt,
...);
#else
RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line);
#endif
// Wrapper for log arguments. Only ever make values of this type with the
// MakeVal() functions.
template <CheckArgType N, typename T>
struct Val {
static constexpr CheckArgType Type() { return N; }
T GetVal() const { return val; }
T val;
};
// Case for when we need to construct a temp string and then print that.
// (We can't use Val<CheckArgType::kStdString, const std::string*>
// because we need somewhere to store the temp string.)
struct ToStringVal {
static constexpr CheckArgType Type() { return CheckArgType::kStdString; }
const std::string* GetVal() const { return &val; }
std::string val;
};
inline Val<CheckArgType::kInt, int> MakeVal(int x) {
return {x};
}
inline Val<CheckArgType::kLong, long> MakeVal(long x) {
return {x};
}
inline Val<CheckArgType::kLongLong, long long> MakeVal(long long x) {
return {x};
}
inline Val<CheckArgType::kUInt, unsigned int> MakeVal(unsigned int x) {
return {x};
}
inline Val<CheckArgType::kULong, unsigned long> MakeVal(unsigned long x) {
return {x};
}
inline Val<CheckArgType::kULongLong, unsigned long long> MakeVal(
unsigned long long x) {
return {x};
}
inline Val<CheckArgType::kDouble, double> MakeVal(double x) {
return {x};
}
inline Val<CheckArgType::kLongDouble, long double> MakeVal(long double x) {
return {x};
}
inline Val<CheckArgType::kCharP, const char*> MakeVal(const char* x) {
return {x};
}
inline Val<CheckArgType::kStdString, const std::string*> MakeVal(
const std::string& x) {
return {&x};
}
inline Val<CheckArgType::kStringView, const absl::string_view*> MakeVal(
const absl::string_view& x) {
return {&x};
}
inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) {
return {x};
}
// The enum class types are not implicitly convertible to arithmetic types.
template <typename T,
absl::enable_if_t<std::is_enum<T>::value &&
!std::is_arithmetic<T>::value>* = nullptr>
inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal(
T x) {
return {static_cast<absl::underlying_type_t<T>>(x)};
}
template <typename T, decltype(ToLogString(std::declval<T>()))* = nullptr>
ToStringVal MakeVal(const T& x) {
return {ToLogString(x)};
}
// Ephemeral type that represents the result of the logging << operator.
template <typename... Ts>
class LogStreamer;
// Base case: Before the first << argument.
template <>
class LogStreamer<> final {
public:
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<std::is_arithmetic<U>::value ||
std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const {
return LogStreamer<V>(MakeVal(arg), this);
}
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<!std::is_arithmetic<U>::value &&
!std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const {
return LogStreamer<V>(MakeVal(arg), this);
}
#if RTC_CHECK_MSG_ENABLED
template <typename... Us>
RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file,
const int line,
const char* message,
const Us&... args) {
static constexpr CheckArgType t[] = {Us::Type()..., CheckArgType::kEnd};
FatalLog(file, line, message, t, args.GetVal()...);
}
template <typename... Us>
RTC_NORETURN RTC_FORCE_INLINE static void CallCheckOp(const char* file,
const int line,
const char* message,
const Us&... args) {
static constexpr CheckArgType t[] = {CheckArgType::kCheckOp, Us::Type()...,
CheckArgType::kEnd};
FatalLog(file, line, message, t, args.GetVal()...);
}
#else
template <typename... Us>
RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file,
const int line) {
FatalLog(file, line);
}
#endif
};
// Inductive case: We've already seen at least one << argument. The most recent
// one had type `T`, and the earlier ones had types `Ts`.
template <typename T, typename... Ts>
class LogStreamer<T, Ts...> final {
public:
RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
: arg_(arg), prior_(prior) {}
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<std::is_arithmetic<U>::value ||
std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(U arg) const {
return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
}
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<!std::is_arithmetic<U>::value &&
!std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(const U& arg) const {
return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
}
#if RTC_CHECK_MSG_ENABLED
template <typename... Us>
RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file,
const int line,
const char* message,
const Us&... args) const {
prior_->Call(file, line, message, arg_, args...);
}
template <typename... Us>
RTC_NORETURN RTC_FORCE_INLINE void CallCheckOp(const char* file,
const int line,
const char* message,
const Us&... args) const {
prior_->CallCheckOp(file, line, message, arg_, args...);
}
#else
template <typename... Us>
RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file,
const int line) const {
prior_->Call(file, line);
}
#endif
private:
// The most recent argument.
T arg_;
// Earlier arguments.
const LogStreamer<Ts...>* prior_;
};
template <bool isCheckOp>
class FatalLogCall final {
public:
FatalLogCall(const char* file, int line, const char* message)
: file_(file), line_(line), message_(message) {}
// This can be any binary operator with precedence lower than <<.
template <typename... Ts>
RTC_NORETURN RTC_FORCE_INLINE void operator&(
const LogStreamer<Ts...>& streamer) {
#if RTC_CHECK_MSG_ENABLED
isCheckOp ? streamer.CallCheckOp(file_, line_, message_)
: streamer.Call(file_, line_, message_);
#else
streamer.Call(file_, line_);
#endif
}
private:
const char* file_;
int line_;
const char* message_;
};
} // namespace webrtc_checks_impl
// 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
// condition being unused).
#define RTC_EAT_STREAM_PARAMETERS(ignored) \
(true ? true : ((void)(ignored), true)) \
? static_cast<void>(0) \
: ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
::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.
#define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \
RTC_EAT_STREAM_PARAMETERS(((void)::rtc::Safe##op(a, b)))
// RTC_CHECK dies with a fatal error if condition is not true. It is *not*
// 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
// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
//
// RTC_CHECK_OP is a helper macro for binary operators.
// Don't use this macro directly in your code, use RTC_CHECK_EQ et al below.
#if RTC_CHECK_MSG_ENABLED
#define RTC_CHECK(condition) \
(condition) ? static_cast<void>(0) \
: ::rtc::webrtc_checks_impl::FatalLogCall<false>( \
__FILE__, __LINE__, #condition) & \
::rtc::webrtc_checks_impl::LogStreamer<>()
#define RTC_CHECK_OP(name, op, val1, val2) \
::rtc::Safe##name((val1), (val2)) \
? static_cast<void>(0) \
: ::rtc::webrtc_checks_impl::FatalLogCall<true>( \
__FILE__, __LINE__, #val1 " " #op " " #val2) & \
::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<>()
#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<>()
#endif
#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2)
#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(Ne, !=, val1, val2)
#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(Le, <=, val1, val2)
#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(Lt, <, val1, val2)
#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(Ge, >=, val1, val2)
#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(Gt, >, val1, val2)
// The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates
// code in debug builds. It does reference the condition parameter in all cases,
// though, so callers won't risk getting warnings about unused variables.
#if RTC_DCHECK_IS_ON
#define RTC_DCHECK(condition) RTC_CHECK(condition)
#define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2)
#define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2)
#define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2)
#define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2)
#define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2)
#define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2)
#else
#define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition)
#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Eq, v1, v2)
#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ne, v1, v2)
#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Le, v1, v2)
#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Lt, v1, v2)
#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ge, v1, v2)
#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Gt, v1, v2)
#endif
#define RTC_UNREACHABLE_CODE_HIT false
#define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
// TODO(bugs.webrtc.org/8454): Add an RTC_ prefix or rename differently.
#define FATAL() \
::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
"FATAL()") & \
::rtc::webrtc_checks_impl::LogStreamer<>()
// Performs the integer division a/b and returns the result. CHECKs that the
// remainder is zero.
template <typename T>
inline T CheckedDivExact(T a, T b) {
RTC_CHECK_EQ(a % b, 0) << a << " is not evenly divisible by " << b;
return a / b;
}
} // namespace rtc
#else // __cplusplus not defined
// C version. Lacks many features compared to the C++ version, but usage
// guidelines are the same.
#define RTC_CHECK(condition) \
do { \
if (!(condition)) { \
rtc_FatalMessage(__FILE__, __LINE__, \
RTC_CHECK_EVAL_MESSAGE("CHECK failed: " #condition)); \
} \
} while (0)
#define RTC_CHECK_EQ(a, b) RTC_CHECK((a) == (b))
#define RTC_CHECK_NE(a, b) RTC_CHECK((a) != (b))
#define RTC_CHECK_LE(a, b) RTC_CHECK((a) <= (b))
#define RTC_CHECK_LT(a, b) RTC_CHECK((a) < (b))
#define RTC_CHECK_GE(a, b) RTC_CHECK((a) >= (b))
#define RTC_CHECK_GT(a, b) RTC_CHECK((a) > (b))
#define RTC_DCHECK(condition) \
do { \
if (RTC_DCHECK_IS_ON && !(condition)) { \
rtc_FatalMessage(__FILE__, __LINE__, \
RTC_CHECK_EVAL_MESSAGE("DCHECK failed: " #condition)); \
} \
} while (0)
#define RTC_DCHECK_EQ(a, b) RTC_DCHECK((a) == (b))
#define RTC_DCHECK_NE(a, b) RTC_DCHECK((a) != (b))
#define RTC_DCHECK_LE(a, b) RTC_DCHECK((a) <= (b))
#define RTC_DCHECK_LT(a, b) RTC_DCHECK((a) < (b))
#define RTC_DCHECK_GE(a, b) RTC_DCHECK((a) >= (b))
#define RTC_DCHECK_GT(a, b) RTC_DCHECK((a) > (b))
#endif // __cplusplus
#endif // RTC_BASE_CHECKS_H_

View File

@ -0,0 +1,25 @@
/*
* 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_COMPILE_ASSERT_C_H_
#define RTC_BASE_COMPILE_ASSERT_C_H_
// Use this macro to verify at compile time that certain restrictions are met.
// The argument is the boolean expression to evaluate.
// Example:
// RTC_COMPILE_ASSERT(sizeof(foo) < 128);
// Note: In C++, use static_assert instead!
#define RTC_COMPILE_ASSERT(expression) \
switch (0) { \
case 0: \
case expression:; \
}
#endif // RTC_BASE_COMPILE_ASSERT_C_H_

View File

@ -0,0 +1,20 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_CONSTRUCTOR_MAGIC_H_
#define RTC_BASE_CONSTRUCTOR_MAGIC_H_
// A macro to disallow the copy constructor and operator= functions. This should
// be used in the declarations for a class.
#define RTC_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
TypeName& operator=(const TypeName&) = delete
#endif // RTC_BASE_CONSTRUCTOR_MAGIC_H_

View File

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

203
webrtc/rtc_base/event.cc Normal file
View File

@ -0,0 +1,203 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/event.h"
#if defined(WEBRTC_WIN)
#include <windows.h>
#elif defined(WEBRTC_POSIX)
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#else
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
#endif
#include "absl/types/optional.h"
#include "rtc_base/checks.h"
#include "rtc_base/synchronization/yield_policy.h"
#include "rtc_base/system/warn_current_thread_is_deadlocked.h"
namespace rtc {
Event::Event() : Event(false, false) {}
#if defined(WEBRTC_WIN)
Event::Event(bool manual_reset, bool initially_signaled) {
event_handle_ = ::CreateEvent(nullptr, // Security attributes.
manual_reset, initially_signaled,
nullptr); // Name.
RTC_CHECK(event_handle_);
}
Event::~Event() {
CloseHandle(event_handle_);
}
void Event::Set() {
SetEvent(event_handle_);
}
void Event::Reset() {
ResetEvent(event_handle_);
}
bool Event::Wait(const int give_up_after_ms, int /*warn_after_ms*/) {
ScopedYieldPolicy::YieldExecution();
const DWORD ms = give_up_after_ms == kForever ? INFINITE : give_up_after_ms;
return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
}
#elif defined(WEBRTC_POSIX)
// On MacOS, clock_gettime is available from version 10.12, and on
// iOS, from version 10.0. So we can't use it yet.
#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
#define USE_CLOCK_GETTIME 0
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
// On Android, pthread_condattr_setclock is available from version 21. By
// default, we target a new enough version for 64-bit platforms but not for
// 32-bit platforms. For older versions, use
// pthread_cond_timedwait_monotonic_np.
#elif defined(WEBRTC_ANDROID) && (__ANDROID_API__ < 21)
#define USE_CLOCK_GETTIME 1
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 1
#else
#define USE_CLOCK_GETTIME 1
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
#endif
Event::Event(bool manual_reset, bool initially_signaled)
: is_manual_reset_(manual_reset), event_status_(initially_signaled) {
RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0);
pthread_condattr_t cond_attr;
RTC_CHECK(pthread_condattr_init(&cond_attr) == 0);
#if USE_CLOCK_GETTIME && !USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
RTC_CHECK(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0);
#endif
RTC_CHECK(pthread_cond_init(&event_cond_, &cond_attr) == 0);
pthread_condattr_destroy(&cond_attr);
}
Event::~Event() {
pthread_mutex_destroy(&event_mutex_);
pthread_cond_destroy(&event_cond_);
}
void Event::Set() {
pthread_mutex_lock(&event_mutex_);
event_status_ = true;
pthread_cond_broadcast(&event_cond_);
pthread_mutex_unlock(&event_mutex_);
}
void Event::Reset() {
pthread_mutex_lock(&event_mutex_);
event_status_ = false;
pthread_mutex_unlock(&event_mutex_);
}
namespace {
timespec GetTimespec(const int milliseconds_from_now) {
timespec ts;
// Get the current time.
#if USE_CLOCK_GETTIME
clock_gettime(CLOCK_MONOTONIC, &ts);
#else
timeval tv;
gettimeofday(&tv, nullptr);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
#endif
// Add the specified number of milliseconds to it.
ts.tv_sec += (milliseconds_from_now / 1000);
ts.tv_nsec += (milliseconds_from_now % 1000) * 1000000;
// Normalize.
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
return ts;
}
} // namespace
bool Event::Wait(const int give_up_after_ms, const int warn_after_ms) {
// 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)
? absl::nullopt
: absl::make_optional(GetTimespec(warn_after_ms));
// 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
? absl::nullopt
: absl::make_optional(GetTimespec(give_up_after_ms));
ScopedYieldPolicy::YieldExecution();
pthread_mutex_lock(&event_mutex_);
// Wait for `event_cond_` to trigger and `event_status_` to be set, with the
// given timeout (or without a timeout if none is given).
const auto wait = [&](const absl::optional<timespec> timeout_ts) {
int error = 0;
while (!event_status_ && error == 0) {
if (timeout_ts == absl::nullopt) {
error = pthread_cond_wait(&event_cond_, &event_mutex_);
} else {
#if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
error = pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_,
&*timeout_ts);
#else
error =
pthread_cond_timedwait(&event_cond_, &event_mutex_, &*timeout_ts);
#endif
}
}
return error;
};
int error;
if (warn_ts == absl::nullopt) {
error = wait(give_up_ts);
} else {
error = wait(warn_ts);
if (error == ETIMEDOUT) {
webrtc::WarnThatTheCurrentThreadIsProbablyDeadlocked();
error = wait(give_up_ts);
}
}
// NOTE(liulk): Exactly one thread will auto-reset this event. All
// the other threads will think it's unsignaled. This seems to be
// consistent with auto-reset events in WEBRTC_WIN
if (error == 0 && !is_manual_reset_)
event_status_ = false;
pthread_mutex_unlock(&event_mutex_);
return (error == 0);
}
#endif
} // namespace rtc

86
webrtc/rtc_base/event.h Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_EVENT_H_
#define RTC_BASE_EVENT_H_
#if defined(WEBRTC_WIN)
#include <windows.h>
#elif defined(WEBRTC_POSIX)
#include <pthread.h>
#else
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
#endif
namespace rtc {
class Event {
public:
static const int kForever = -1;
Event();
Event(bool manual_reset, bool initially_signaled);
Event(const Event&) = delete;
Event& operator=(const Event&) = delete;
~Event();
void Set();
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.
//
// 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);
// 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);
}
private:
#if defined(WEBRTC_WIN)
HANDLE event_handle_;
#elif defined(WEBRTC_POSIX)
pthread_mutex_t event_mutex_;
pthread_cond_t event_cond_;
const bool is_manual_reset_;
bool event_status_;
#endif
};
// These classes are provided for compatibility with Chromium.
// The rtc::Event implementation is overriden inside of Chromium for the
// purposes of detecting when threads are blocked that shouldn't be as well as
// to use the more accurate event implementation that's there than is provided
// by default on some platforms (e.g. Windows).
// When building with standalone WebRTC, this class is a noop.
// For further information, please see the
// ScopedAllowBaseSyncPrimitives(ForTesting) classes in Chromium.
class ScopedAllowBaseSyncPrimitives {
public:
ScopedAllowBaseSyncPrimitives() {}
~ScopedAllowBaseSyncPrimitives() {}
};
class ScopedAllowBaseSyncPrimitivesForTesting {
public:
ScopedAllowBaseSyncPrimitivesForTesting() {}
~ScopedAllowBaseSyncPrimitivesForTesting() {}
};
} // namespace rtc
#endif // RTC_BASE_EVENT_H_

View File

@ -0,0 +1,412 @@
/*
* 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/event_tracer.h"
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
#include "rtc_base/logging.h"
#include "rtc_base/platform_thread.h"
#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"
// This is a guesstimate that should be enough in most cases.
static const size_t kEventLoggerArgsStrBufferInitialSize = 256;
static const size_t kTraceArgBufferLength = 32;
namespace webrtc {
namespace {
GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr;
AddTraceEventPtr g_add_trace_event_ptr = nullptr;
} // namespace
void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
AddTraceEventPtr add_trace_event_ptr) {
g_get_category_enabled_ptr = get_category_enabled_ptr;
g_add_trace_event_ptr = add_trace_event_ptr;
}
const unsigned char* EventTracer::GetCategoryEnabled(const char* name) {
if (g_get_category_enabled_ptr)
return g_get_category_enabled_ptr(name);
// A string with null terminator means category is disabled.
return reinterpret_cast<const unsigned char*>("\0");
}
// Arguments to this function (phase, etc.) are as defined in
// webrtc/rtc_base/trace_event.h.
void EventTracer::AddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags) {
if (g_add_trace_event_ptr) {
g_add_trace_event_ptr(phase, category_enabled, name, id, num_args,
arg_names, arg_types, arg_values, flags);
}
}
} // namespace webrtc
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;
// 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,
const unsigned char* category_enabled,
char phase,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
uint64_t timestamp,
int pid,
rtc::PlatformThreadId thread_id) {
std::vector<TraceArg> args(num_args);
for (int i = 0; i < num_args; ++i) {
TraceArg& arg = args[i];
arg.name = arg_names[i];
arg.type = arg_types[i];
arg.value.as_uint = arg_values[i];
// Value is a pointer to a temporary string, so we have to make a copy.
if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
// Space for the string and for the terminating null character.
size_t str_length = strlen(arg.value.as_string) + 1;
char* str_copy = new char[str_length];
memcpy(str_copy, arg.value.as_string, str_length);
arg.value.as_string = str_copy;
}
}
webrtc::MutexLock lock(&mutex_);
trace_events_.push_back(
{name, category_enabled, phase, args, timestamp, 1, thread_id});
}
// The TraceEvent format is documented here:
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
void Log() {
RTC_DCHECK(output_file_);
static const int kLoggingIntervalMs = 100;
fprintf(output_file_, "{ \"traceEvents\": [\n");
bool has_logged_event = false;
while (true) {
bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs);
std::vector<TraceEvent> events;
{
webrtc::MutexLock lock(&mutex_);
trace_events_.swap(events);
}
std::string args_str;
args_str.reserve(kEventLoggerArgsStrBufferInitialSize);
for (TraceEvent& e : events) {
args_str.clear();
if (!e.args.empty()) {
args_str += ", \"args\": {";
bool is_first_argument = true;
for (TraceArg& arg : e.args) {
if (!is_first_argument)
args_str += ",";
is_first_argument = false;
args_str += " \"";
args_str += arg.name;
args_str += "\": ";
args_str += TraceArgValueAsString(arg);
// Delete our copy of the string.
if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
delete[] arg.value.as_string;
arg.value.as_string = nullptr;
}
}
args_str += " }";
}
fprintf(output_file_,
"%s{ \"name\": \"%s\""
", \"cat\": \"%s\""
", \"ph\": \"%c\""
", \"ts\": %" PRIu64
", \"pid\": %d"
#if defined(WEBRTC_WIN)
", \"tid\": %lu"
#else
", \"tid\": %d"
#endif // defined(WEBRTC_WIN)
"%s"
"}\n",
has_logged_event ? "," : " ", e.name, e.category_enabled,
e.phase, e.timestamp, e.pid, e.tid, args_str.c_str());
has_logged_event = true;
}
if (shutting_down)
break;
}
fprintf(output_file_, "]}\n");
if (output_file_owned_)
fclose(output_file_);
output_file_ = nullptr;
}
void Start(FILE* file, bool owned) {
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(file);
RTC_DCHECK(!output_file_);
output_file_ = file;
output_file_owned_ = owned;
{
webrtc::MutexLock lock(&mutex_);
// Since the atomic fast-path for adding events to the queue can be
// bypassed while the logging thread is shutting down there may be some
// stale events in the queue, hence the vector needs to be cleared to not
// log events from a previous logging session (which may be days old).
trace_events_.clear();
}
// 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));
// Finally start, everything should be set up now.
logging_thread_.Start();
TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start");
}
void Stop() {
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)
return;
// Wake up logging thread to finish writing.
shutdown_event_.Set();
// Join the logging thread.
logging_thread_.Stop();
}
private:
struct TraceArg {
const char* name;
unsigned char type;
// Copied from webrtc/rtc_base/trace_event.h TraceValueUnion.
union TraceArgValue {
bool as_bool;
unsigned long long as_uint;
long long as_int;
double as_double;
const void* as_pointer;
const char* as_string;
} value;
// Assert that the size of the union is equal to the size of the as_uint
// field since we are assigning to arbitrary types using it.
static_assert(sizeof(TraceArgValue) == sizeof(unsigned long long),
"Size of TraceArg value union is not equal to the size of "
"the uint field of that union.");
};
struct TraceEvent {
const char* name;
const unsigned char* category_enabled;
char phase;
std::vector<TraceArg> args;
uint64_t timestamp;
int pid;
rtc::PlatformThreadId tid;
};
static std::string TraceArgValueAsString(TraceArg arg) {
std::string output;
if (arg.type == TRACE_VALUE_TYPE_STRING ||
arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
// Space for every character to be an espaced character + two for
// quatation marks.
output.reserve(strlen(arg.value.as_string) * 2 + 2);
output += '\"';
const char* c = arg.value.as_string;
do {
if (*c == '"' || *c == '\\') {
output += '\\';
output += *c;
} else {
output += *c;
}
} while (*++c);
output += '\"';
} else {
output.resize(kTraceArgBufferLength);
size_t print_length = 0;
switch (arg.type) {
case TRACE_VALUE_TYPE_BOOL:
if (arg.value.as_bool) {
strcpy(&output[0], "true");
print_length = 4;
} else {
strcpy(&output[0], "false");
print_length = 5;
}
break;
case TRACE_VALUE_TYPE_UINT:
print_length = snprintf(&output[0], kTraceArgBufferLength, "%llu",
arg.value.as_uint);
break;
case TRACE_VALUE_TYPE_INT:
print_length = snprintf(&output[0], kTraceArgBufferLength, "%lld",
arg.value.as_int);
break;
case TRACE_VALUE_TYPE_DOUBLE:
print_length = snprintf(&output[0], kTraceArgBufferLength, "%f",
arg.value.as_double);
break;
case TRACE_VALUE_TYPE_POINTER:
print_length = snprintf(&output[0], kTraceArgBufferLength, "\"%p\"",
arg.value.as_pointer);
break;
}
size_t output_length = print_length < kTraceArgBufferLength
? print_length
: kTraceArgBufferLength - 1;
// This will hopefully be very close to nop. On most implementations, it
// just writes null byte and sets the length field of the string.
output.resize(output_length);
}
return output;
}
webrtc::Mutex mutex_;
std::vector<TraceEvent> trace_events_ RTC_GUARDED_BY(mutex_);
rtc::PlatformThread logging_thread_;
rtc::Event shutdown_event_;
rtc::ThreadChecker 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 const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT("");
const unsigned char* InternalGetCategoryEnabled(const char* name) {
const char* prefix_ptr = &kDisabledTracePrefix[0];
const char* name_ptr = name;
// Check whether name contains the default-disabled prefix.
while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') {
++prefix_ptr;
++name_ptr;
}
return reinterpret_cast<const unsigned char*>(*prefix_ptr == '\0' ? ""
: name);
}
void InternalAddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
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)
return;
g_event_logger->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 StartInternalCaptureToFile(FILE* file) {
if (g_event_logger) {
g_event_logger->Start(file, false);
}
}
bool StartInternalCapture(const char* filename) {
if (!g_event_logger)
return false;
FILE* file = fopen(filename, "w");
if (!file) {
RTC_LOG(LS_ERROR) << "Failed to open trace file '" << filename
<< "' for writing.";
return false;
}
g_event_logger->Start(file, true);
return true;
}
void StopInternalCapture() {
if (g_event_logger) {
g_event_logger->Stop();
}
}
void ShutdownInternalTracer() {
StopInternalCapture();
EventLogger* old_logger = rtc::AtomicOps::AcquireLoadPtr(&g_event_logger);
RTC_DCHECK(old_logger);
RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
&g_event_logger, old_logger,
static_cast<EventLogger*>(nullptr)) == old_logger);
delete old_logger;
webrtc::SetupEventTracer(nullptr, nullptr);
}
} // namespace tracing
} // namespace rtc

View File

@ -0,0 +1,82 @@
/*
* 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.
*/
// This file defines the interface for event tracing in WebRTC.
//
// Event log handlers are set through SetupEventTracer(). User of this API will
// provide two function pointers to handle event tracing calls.
//
// * GetCategoryEnabledPtr
// Event tracing system calls this function to determine if a particular
// event category is enabled.
//
// * AddTraceEventPtr
// Adds a tracing event. It is the user's responsibility to log the data
// provided.
//
// Parameters for the above two functions are described in trace_event.h.
#ifndef RTC_BASE_EVENT_TRACER_H_
#define RTC_BASE_EVENT_TRACER_H_
#include <stdio.h>
namespace webrtc {
typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name);
typedef void (*AddTraceEventPtr)(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags);
// User of WebRTC can call this method to setup event tracing.
//
// This method must be called before any WebRTC methods. Functions
// provided should be thread-safe.
void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
AddTraceEventPtr add_trace_event_ptr);
// This class defines interface for the event tracing system to call
// internally. Do not call these methods directly.
class EventTracer {
public:
static const unsigned char* GetCategoryEnabled(const char* name);
static void AddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags);
};
} // namespace webrtc
namespace rtc {
namespace tracing {
// Set up internal event tracer.
void SetupInternalTracer();
bool StartInternalCapture(const char* filename);
void StartInternalCaptureToFile(FILE* file);
void StopInternalCapture();
// Make sure we run this, this will tear down the internal tracing.
void ShutdownInternalTracer();
} // namespace tracing
} // namespace rtc
#endif // RTC_BASE_EVENT_TRACER_H_

View File

@ -0,0 +1,247 @@
/*
* 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/experiments/field_trial_parser.h"
#include <inttypes.h>
#include <algorithm>
#include <map>
#include <type_traits>
#include <utility>
#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)
: key_(key) {}
FieldTrialParameterInterface::~FieldTrialParameterInterface() {
RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_
<< "' never used.";
}
void ParseFieldTrial(
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string trial_string) {
std::map<std::string, FieldTrialParameterInterface*> field_map;
FieldTrialParameterInterface* keyless_field = nullptr;
for (FieldTrialParameterInterface* field : fields) {
field->MarkAsUsed();
if (!field->sub_parameters_.empty()) {
for (FieldTrialParameterInterface* sub_field : field->sub_parameters_) {
RTC_DCHECK(!sub_field->key_.empty());
sub_field->MarkAsUsed();
field_map[sub_field->key_] = sub_field;
}
continue;
}
if (field->key_.empty()) {
RTC_DCHECK(!keyless_field);
keyless_field = field;
} else {
field_map[field->key_] = field;
}
}
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::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;
auto field = field_map.find(key);
if (field != field_map.end()) {
if (!field->second->Parse(std::move(opt_value))) {
RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
<< "' in trial: \"" << trial_string << "\"";
}
} else if (!opt_value && keyless_field && !key.empty()) {
if (!keyless_field->Parse(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 += ", ";
}
RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys;
}
}
for (FieldTrialParameterInterface* field : fields) {
field->ParseDone();
}
}
template <>
absl::optional<bool> ParseTypedParameter<bool>(std::string str) {
if (str == "true" || str == "1") {
return true;
} else if (str == "false" || str == "0") {
return false;
}
return absl::nullopt;
}
template <>
absl::optional<double> ParseTypedParameter<double>(std::string str) {
double value;
char unit[2]{0, 0};
if (sscanf(str.c_str(), "%lf%1s", &value, unit) >= 1) {
if (unit[0] == '%')
return value / 100;
return value;
} else {
return absl::nullopt;
}
}
template <>
absl::optional<int> ParseTypedParameter<int>(std::string str) {
int64_t value;
if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) {
if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) {
return static_cast<int>(value);
}
}
return absl::nullopt;
}
template <>
absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str) {
int64_t value;
if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) {
if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) {
return static_cast<unsigned>(value);
}
}
return absl::nullopt;
}
template <>
absl::optional<std::string> ParseTypedParameter<std::string>(std::string str) {
return std::move(str);
}
template <>
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
std::string str) {
return ParseOptionalParameter<bool>(str);
}
template <>
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
std::string str) {
return ParseOptionalParameter<int>(str);
}
template <>
absl::optional<absl::optional<unsigned>>
ParseTypedParameter<absl::optional<unsigned>>(std::string str) {
return ParseOptionalParameter<unsigned>(str);
}
template <>
absl::optional<absl::optional<double>>
ParseTypedParameter<absl::optional<double>>(std::string str) {
return ParseOptionalParameter<double>(str);
}
FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {}
FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value)
: FieldTrialParameterInterface(key), value_(default_value) {}
bool FieldTrialFlag::Get() const {
return value_;
}
webrtc::FieldTrialFlag::operator bool() const {
return value_;
}
bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
// Only set the flag if there is no argument provided.
if (str_value) {
absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
if (!opt_value)
return false;
value_ = *opt_value;
} else {
value_ = true;
}
return true;
}
AbstractFieldTrialEnum::AbstractFieldTrialEnum(
std::string key,
int default_value,
std::map<std::string, int> mapping)
: FieldTrialParameterInterface(key),
value_(default_value),
enum_mapping_(mapping) {
for (auto& key_val : enum_mapping_)
valid_values_.insert(key_val.second);
}
AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) =
default;
AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default;
bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) {
if (str_value) {
auto it = enum_mapping_.find(*str_value);
if (it != enum_mapping_.end()) {
value_ = it->second;
return true;
}
absl::optional<int> value = ParseTypedParameter<int>(*str_value);
if (value.has_value() &&
(valid_values_.find(*value) != valid_values_.end())) {
value_ = *value;
return true;
}
}
return false;
}
template class FieldTrialParameter<bool>;
template class FieldTrialParameter<double>;
template class FieldTrialParameter<int>;
template class FieldTrialParameter<unsigned>;
template class FieldTrialParameter<std::string>;
template class FieldTrialConstrained<double>;
template class FieldTrialConstrained<int>;
template class FieldTrialConstrained<unsigned>;
template class FieldTrialOptional<double>;
template class FieldTrialOptional<int>;
template class FieldTrialOptional<unsigned>;
template class FieldTrialOptional<bool>;
template class FieldTrialOptional<std::string>;
} // namespace webrtc

View File

@ -0,0 +1,288 @@
/*
* Copyright 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.
*/
#ifndef RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
#include <stdint.h>
#include <initializer_list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "absl/types/optional.h"
// Field trial parser functionality. Provides funcitonality to parse field trial
// argument strings in key:value format. Each parameter is described using
// key:value, parameters are separated with a ,. Values can't include the comma
// character, since there's no quote facility. For most types, white space is
// ignored. Parameters are declared with a given type for which an
// implementation of ParseTypedParameter should be provided. The
// ParseTypedParameter implementation is given whatever is between the : and the
// ,. If the key is provided without : a FieldTrialOptional will use nullopt.
// Example string: "my_optional,my_int:3,my_string:hello"
// For further description of usage and behavior, see the examples in the unit
// tests.
namespace webrtc {
class FieldTrialParameterInterface {
public:
virtual ~FieldTrialParameterInterface();
std::string key() const { return key_; }
protected:
// Protected to allow implementations to provide assignment and copy.
FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
default;
explicit FieldTrialParameterInterface(std::string key);
friend void ParseFieldTrial(
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string raw_string);
void MarkAsUsed() { used_ = true; }
virtual bool Parse(absl::optional<std::string> str_value) = 0;
virtual void ParseDone() {}
std::vector<FieldTrialParameterInterface*> sub_parameters_;
private:
std::string key_;
bool used_ = false;
};
// ParseFieldTrial function parses the given string and fills the given fields
// with extracted values if available.
void ParseFieldTrial(
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string raw_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);
// 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)
: FieldTrialParameterInterface(key), value_(default_value) {}
T Get() const { return value_; }
operator T() const { return Get(); }
const T* operator->() const { return &value_; }
void SetForTest(T value) { value_ = value; }
protected:
bool Parse(absl::optional<std::string> str_value) override {
if (str_value) {
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
if (value.has_value()) {
value_ = value.value();
return true;
}
}
return false;
}
private:
T value_;
};
// This class uses the ParseTypedParameter function to implement a parameter
// implementation with an enforced default value and a range constraint. Values
// outside the configured range will be ignored.
template <typename T>
class FieldTrialConstrained : public FieldTrialParameterInterface {
public:
FieldTrialConstrained(std::string key,
T default_value,
absl::optional<T> lower_limit,
absl::optional<T> upper_limit)
: FieldTrialParameterInterface(key),
value_(default_value),
lower_limit_(lower_limit),
upper_limit_(upper_limit) {}
T Get() const { return value_; }
operator T() const { return Get(); }
const T* operator->() const { return &value_; }
protected:
bool Parse(absl::optional<std::string> str_value) override {
if (str_value) {
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
if (value && (!lower_limit_ || *value >= *lower_limit_) &&
(!upper_limit_ || *value <= *upper_limit_)) {
value_ = *value;
return true;
}
}
return false;
}
private:
T value_;
absl::optional<T> lower_limit_;
absl::optional<T> upper_limit_;
};
class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
public:
AbstractFieldTrialEnum(std::string key,
int default_value,
std::map<std::string, int> mapping);
~AbstractFieldTrialEnum() override;
AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
protected:
bool Parse(absl::optional<std::string> str_value) override;
protected:
int value_;
std::map<std::string, int> enum_mapping_;
std::set<int> valid_values_;
};
// The FieldTrialEnum class can be used to quickly define a parser for a
// specific enum. It handles values provided as integers and as strings if a
// mapping is provided.
template <typename T>
class FieldTrialEnum : public AbstractFieldTrialEnum {
public:
FieldTrialEnum(std::string key,
T default_value,
std::map<std::string, T> mapping)
: AbstractFieldTrialEnum(key,
static_cast<int>(default_value),
ToIntMap(mapping)) {}
T Get() const { return static_cast<T>(value_); }
operator T() const { return Get(); }
private:
static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
std::map<std::string, int> res;
for (const auto& it : mapping)
res[it.first] = static_cast<int>(it.second);
return res;
}
};
// This class uses the ParseTypedParameter function to implement an optional
// parameter implementation that can default to absl::nullopt.
template <typename T>
class FieldTrialOptional : public FieldTrialParameterInterface {
public:
explicit FieldTrialOptional(std::string key)
: FieldTrialParameterInterface(key) {}
FieldTrialOptional(std::string 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(); }
const T& operator*() const { return value_.value(); }
const T* operator->() const { return &value_.value(); }
explicit operator bool() const { return value_.has_value(); }
protected:
bool Parse(absl::optional<std::string> str_value) override {
if (str_value) {
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
if (!value.has_value())
return false;
value_ = value.value();
} else {
value_ = absl::nullopt;
}
return true;
}
private:
absl::optional<T> value_;
};
// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
// are present. If key is missing, evaluates to false. If key is present, but no
// 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);
bool Get() const;
operator bool() const;
protected:
bool Parse(absl::optional<std::string> str_value) override;
private:
bool value_;
};
template <typename T>
absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) {
if (str.empty())
return absl::optional<T>();
auto parsed = ParseTypedParameter<T>(str);
if (parsed.has_value())
return parsed;
return absl::nullopt;
}
template <>
absl::optional<bool> ParseTypedParameter<bool>(std::string str);
template <>
absl::optional<double> ParseTypedParameter<double>(std::string str);
template <>
absl::optional<int> ParseTypedParameter<int>(std::string str);
template <>
absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str);
template <>
absl::optional<std::string> ParseTypedParameter<std::string>(std::string str);
template <>
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
std::string str);
template <>
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
std::string str);
template <>
absl::optional<absl::optional<unsigned>>
ParseTypedParameter<absl::optional<unsigned>>(std::string str);
template <>
absl::optional<absl::optional<double>>
ParseTypedParameter<absl::optional<double>>(std::string str);
// Accepts true, false, else parsed with sscanf %i, true if != 0.
extern template class FieldTrialParameter<bool>;
// Interpreted using sscanf %lf.
extern template class FieldTrialParameter<double>;
// Interpreted using sscanf %i.
extern template class FieldTrialParameter<int>;
// Interpreted using sscanf %u.
extern template class FieldTrialParameter<unsigned>;
// Using the given value as is.
extern template class FieldTrialParameter<std::string>;
extern template class FieldTrialConstrained<double>;
extern template class FieldTrialConstrained<int>;
extern template class FieldTrialConstrained<unsigned>;
extern template class FieldTrialOptional<double>;
extern template class FieldTrialOptional<int>;
extern template class FieldTrialOptional<unsigned>;
extern template class FieldTrialOptional<bool>;
extern template class FieldTrialOptional<std::string>;
} // namespace webrtc
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_

View File

@ -0,0 +1,38 @@
/*
* 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_GTEST_PROD_UTIL_H_
#define RTC_BASE_GTEST_PROD_UTIL_H_
// Define our own version of FRIEND_TEST here rather than including
// gtest_prod.h to avoid depending on any part of GTest in production code.
#define FRIEND_TEST_WEBRTC(test_case_name, test_name) \
friend class test_case_name##_##test_name##_Test
// This file is a plain copy of Chromium's base/gtest_prod_util.h.
//
// This is a wrapper for gtest's FRIEND_TEST macro that friends
// test with all possible prefixes. This is very helpful when changing the test
// prefix, because the friend declarations don't need to be updated.
//
// Example usage:
//
// class MyClass {
// private:
// void MyMethod();
// FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod);
// };
#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
FRIEND_TEST_WEBRTC(test_case_name, test_name); \
FRIEND_TEST_WEBRTC(test_case_name, DISABLED_##test_name); \
FRIEND_TEST_WEBRTC(test_case_name, FLAKY_##test_name); \
FRIEND_TEST_WEBRTC(test_case_name, FAILS_##test_name)
#endif // RTC_BASE_GTEST_PROD_UTIL_H_

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016 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_IGNORE_WUNDEF_H_
#define RTC_BASE_IGNORE_WUNDEF_H_
// If a header file uses #if on possibly undefined macros (and it's for some
// reason not possible to just fix the header file), include it like this:
//
// RTC_PUSH_IGNORING_WUNDEF()
// #include "misbehaving_header.h"
// RTC_POP_IGNORING_WUNDEF()
//
// This will cause the compiler to not emit -Wundef warnings for that file.
#ifdef __clang__
#define RTC_PUSH_IGNORING_WUNDEF() \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wundef\"")
#define RTC_POP_IGNORING_WUNDEF() _Pragma("clang diagnostic pop")
#else
#define RTC_PUSH_IGNORING_WUNDEF()
#define RTC_POP_IGNORING_WUNDEF()
#endif // __clang__
#endif // RTC_BASE_IGNORE_WUNDEF_H_

562
webrtc/rtc_base/logging.cc Normal file
View File

@ -0,0 +1,562 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/logging.h"
#include <string.h>
#if RTC_LOG_ENABLED()
#if defined(WEBRTC_WIN)
#include <windows.h>
#if _MSC_VER < 1900
#define snprintf _snprintf
#endif
#undef ERROR // wingdi.h
#endif
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
#include <CoreServices/CoreServices.h>
#elif defined(WEBRTC_ANDROID)
#include <android/log.h>
// Android has a 1024 limit on log inputs. We use 60 chars as an
// approx for the header/tag portion.
// See android/system/core/liblog/logd_write.c
static const int kMaxLogLineSize = 1024 - 60;
#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
#include <inttypes.h>
#include <stdio.h>
#include <time.h>
#include <algorithm>
#include <cstdarg>
#include <vector>
#include "absl/base/attributes.h"
#include "rtc_base/checks.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/string_encode.h"
#include "rtc_base/string_utils.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/thread_annotations.h"
#include "rtc_base/time_utils.h"
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;
#else
static LoggingSeverity g_min_sev = LS_NONE;
static LoggingSeverity g_dbg_sev = LS_NONE;
#endif
// Return the filename portion of the string (that following the last slash).
const char* FilenameFromPath(const char* file) {
const char* end1 = ::strrchr(file, '/');
const char* end2 = ::strrchr(file, '\\');
if (!end1 && !end2)
return file;
else
return (end1 > end2) ? end1 + 1 : end2 + 1;
}
// 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_;
} // namespace
/////////////////////////////////////////////////////////////////////////////
// LogMessage
/////////////////////////////////////////////////////////////////////////////
bool LogMessage::log_to_stderr_ = true;
// The list of logging streams currently configured.
// 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_) =
nullptr;
ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
// Boolean options default to false (0)
bool LogMessage::thread_, LogMessage::timestamp_;
LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
: LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
LogMessage::LogMessage(const char* file,
int line,
LoggingSeverity sev,
LogErrorContext err_ctx,
int err)
: severity_(sev) {
if (timestamp_) {
// 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());
// 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;
}
if (thread_) {
PlatformThreadId id = CurrentThreadId();
print_stream_ << "[" << id << "] ";
}
if (file != nullptr) {
#if defined(WEBRTC_ANDROID)
tag_ = FilenameFromPath(file);
print_stream_ << "(line " << line << "): ";
#else
print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
#endif
}
if (err_ctx != ERRCTX_NONE) {
char tmp_buf[1024];
SimpleStringBuilder tmp(tmp_buf);
tmp.AppendFormat("[0x%08X]", err);
switch (err_ctx) {
case ERRCTX_ERRNO:
tmp << " " << strerror(err);
break;
#ifdef WEBRTC_WIN
case ERRCTX_HRESULT: {
char msgbuf[256];
DWORD flags =
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
if (DWORD len = FormatMessageA(
flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
while ((len > 0) &&
isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
msgbuf[--len] = 0;
}
tmp << " " << msgbuf;
}
break;
}
#endif // WEBRTC_WIN
default:
break;
}
extra_ = tmp.str();
}
}
#if defined(WEBRTC_ANDROID)
LogMessage::LogMessage(const char* file,
int line,
LoggingSeverity sev,
const char* tag)
: LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
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();
if (severity_ >= g_dbg_sev) {
#if defined(WEBRTC_ANDROID)
OutputToDebug(str, severity_, tag_);
#else
OutputToDebug(str, severity_);
#endif
}
webrtc::MutexLock lock(&g_log_mutex_);
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
}
}
}
void LogMessage::AddTag(const char* tag) {
#ifdef WEBRTC_ANDROID
tag_ = tag;
#endif
}
rtc::StringBuilder& LogMessage::stream() {
return print_stream_;
}
int LogMessage::GetMinLogSeverity() {
return g_min_sev;
}
LoggingSeverity LogMessage::GetLogToDebug() {
return g_dbg_sev;
}
int64_t LogMessage::LogStartTime() {
static const int64_t g_start = SystemTimeMillis();
return g_start;
}
uint32_t LogMessage::WallClockStartTime() {
static const uint32_t g_start_wallclock = time(nullptr);
return g_start_wallclock;
}
void LogMessage::LogThreads(bool on) {
thread_ = on;
}
void LogMessage::LogTimestamps(bool on) {
timestamp_ = on;
}
void LogMessage::LogToDebug(LoggingSeverity min_sev) {
g_dbg_sev = min_sev;
webrtc::MutexLock lock(&g_log_mutex_);
UpdateMinLogSeverity();
}
void LogMessage::SetLogToStderr(bool log_to_stderr) {
log_to_stderr_ = log_to_stderr;
}
int LogMessage::GetLogToStream(LogSink* stream) {
webrtc::MutexLock lock(&g_log_mutex_);
LoggingSeverity sev = LS_NONE;
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
if (stream == nullptr || stream == entry) {
sev = std::min(sev, entry->min_severity_);
}
}
return sev;
}
void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
webrtc::MutexLock lock(&g_log_mutex_);
stream->min_severity_ = min_sev;
stream->next_ = streams_;
streams_ = stream;
streams_empty_.store(false, std::memory_order_relaxed);
UpdateMinLogSeverity();
}
void LogMessage::RemoveLogToStream(LogSink* stream) {
webrtc::MutexLock lock(&g_log_mutex_);
for (LogSink** entry = &streams_; *entry != nullptr;
entry = &(*entry)->next_) {
if (*entry == stream) {
*entry = (*entry)->next_;
break;
}
}
streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
UpdateMinLogSeverity();
}
void LogMessage::ConfigureLogging(const char* params) {
LoggingSeverity current_level = LS_VERBOSE;
LoggingSeverity debug_level = GetLogToDebug();
std::vector<std::string> tokens;
tokenize(params, ' ', &tokens);
for (const std::string& token : tokens) {
if (token.empty())
continue;
// Logging features
if (token == "tstamp") {
LogTimestamps();
} else if (token == "thread") {
LogThreads();
// Logging levels
} else if (token == "verbose") {
current_level = LS_VERBOSE;
} else if (token == "info") {
current_level = LS_INFO;
} else if (token == "warning") {
current_level = LS_WARNING;
} else if (token == "error") {
current_level = LS_ERROR;
} else if (token == "none") {
current_level = LS_NONE;
// Logging targets
} else if (token == "debug") {
debug_level = current_level;
}
}
#if defined(WEBRTC_WIN) && !defined(WINUWP)
if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
// First, attempt to attach to our parent's console... so if you invoke
// from the command line, we'll see the output there. Otherwise, create
// our own console window.
// Note: These methods fail if a console already exists, which is fine.
if (!AttachConsole(ATTACH_PARENT_PROCESS))
::AllocConsole();
}
#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
LogToDebug(debug_level);
}
void LogMessage::UpdateMinLogSeverity()
RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) {
LoggingSeverity min_sev = g_dbg_sev;
for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
min_sev = std::min(min_sev, entry->min_severity_);
}
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
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) {
Boolean exists_and_is_valid;
Boolean should_log =
CFPreferencesGetAppBooleanValue(key, 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());
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);
}
}
#endif // WEBRTC_WIN
#if defined(WEBRTC_ANDROID)
// Android's logging facility uses severity to log messages but we
// need to map libjingle's severity levels to Android ones first.
// Also write to stderr which maybe available to executable started
// from the shell.
int prio;
switch (severity) {
case LS_VERBOSE:
prio = ANDROID_LOG_VERBOSE;
break;
case LS_INFO:
prio = ANDROID_LOG_INFO;
break;
case LS_WARNING:
prio = ANDROID_LOG_WARN;
break;
case LS_ERROR:
prio = ANDROID_LOG_ERROR;
break;
default:
prio = ANDROID_LOG_UNKNOWN;
}
int size = str.size();
int 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());
} 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
// middle).
__android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
str.c_str() + idx);
idx += len;
size -= len;
++line;
}
}
#endif // WEBRTC_ANDROID
if (log_to_stderr) {
fprintf(stderr, "%s", str.c_str());
fflush(stderr);
}
}
// static
bool LogMessage::IsNoop(LoggingSeverity severity) {
if (severity >= g_dbg_sev || severity >= g_min_sev)
return false;
return streams_empty_.load(std::memory_order_relaxed);
}
void LogMessage::FinishPrintStream() {
if (!extra_.empty())
print_stream_ << " : " << extra_;
print_stream_ << "\n";
}
namespace webrtc_logging_impl {
void Log(const LogArgType* fmt, ...) {
va_list args;
va_start(args, fmt);
LogMetadataErr meta;
const char* tag = nullptr;
switch (*fmt) {
case LogArgType::kLogMetadata: {
meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
break;
}
case LogArgType::kLogMetadataErr: {
meta = va_arg(args, LogMetadataErr);
break;
}
#ifdef WEBRTC_ANDROID
case LogArgType::kLogMetadataTag: {
const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
tag = tag_meta.tag;
break;
}
#endif
default: {
RTC_NOTREACHED();
va_end(args);
return;
}
}
LogMessage log_message(meta.meta.File(), meta.meta.Line(),
meta.meta.Severity(), meta.err_ctx, meta.err);
if (tag) {
log_message.AddTag(tag);
}
for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
switch (*fmt) {
case LogArgType::kInt:
log_message.stream() << va_arg(args, int);
break;
case LogArgType::kLong:
log_message.stream() << va_arg(args, long);
break;
case LogArgType::kLongLong:
log_message.stream() << va_arg(args, long long);
break;
case LogArgType::kUInt:
log_message.stream() << va_arg(args, unsigned);
break;
case LogArgType::kULong:
log_message.stream() << va_arg(args, unsigned long);
break;
case LogArgType::kULongLong:
log_message.stream() << va_arg(args, unsigned long long);
break;
case LogArgType::kDouble:
log_message.stream() << va_arg(args, double);
break;
case LogArgType::kLongDouble:
log_message.stream() << va_arg(args, long double);
break;
case LogArgType::kCharP: {
const char* s = va_arg(args, const char*);
log_message.stream() << (s ? s : "(null)");
break;
}
case LogArgType::kStdString:
log_message.stream() << *va_arg(args, const std::string*);
break;
case LogArgType::kStringView:
log_message.stream() << *va_arg(args, const absl::string_view*);
break;
case LogArgType::kVoidP:
log_message.stream() << rtc::ToHex(
reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
break;
default:
RTC_NOTREACHED();
va_end(args);
return;
}
}
va_end(args);
}
} // namespace webrtc_logging_impl
} // namespace rtc
#endif
namespace rtc {
// Inefficient default implementation, override is recommended.
void LogSink::OnLogMessage(const std::string& msg,
LoggingSeverity severity,
const char* tag) {
OnLogMessage(tag + (": " + msg), severity);
}
void LogSink::OnLogMessage(const std::string& msg,
LoggingSeverity /* severity */) {
OnLogMessage(msg);
}
} // namespace rtc

712
webrtc/rtc_base/logging.h Normal file
View File

@ -0,0 +1,712 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// RTC_LOG(...) an ostream target that can be used to send formatted
// output to a variety of logging targets, such as debugger console, stderr,
// or any LogSink.
// The severity level passed as the first argument to the logging
// functions is used as a filter, to limit the verbosity of the logging.
// Static members of LogMessage documented below are used to control the
// verbosity and target of the output.
// There are several variations on the RTC_LOG macro which facilitate logging
// of common error conditions, detailed below.
// 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_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_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
// HRESULT returned by GetLastError.
// RTC_LOG_ERRNO(sev) attempts to add a string description of an errno-derived
// error. errno and associated facilities exist on both Windows and POSIX,
// but on Windows they only apply to the C/C++ runtime.
// RTC_LOG_ERR(sev) is an alias for the platform's normal error system, i.e.
// _GLE on Windows and _ERRNO on POSIX.
// (The above three also all have _EX versions that let you specify the error
// code, rather than using the last one.)
// RTC_LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the
// specified context.
// RTC_LOG_CHECK_LEVEL(sev) (and RTC_LOG_CHECK_LEVEL_V(sev)) can be used as a
// test before performing expensive or sensitive operations whose sole
// purpose is to output logging data at the desired level.
#ifndef RTC_BASE_LOGGING_H_
#define RTC_BASE_LOGGING_H_
#include <errno.h>
#include <atomic>
#include <sstream> // no-presubmit-check TODO(webrtc:8982)
#include <string>
#include <utility>
#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/deprecation.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/system/inline.h"
#if !defined(NDEBUG) || defined(DLOG_ALWAYS_ON)
#define RTC_DLOG_IS_ON 1
#else
#define RTC_DLOG_IS_ON 0
#endif
#if defined(RTC_DISABLE_LOGGING)
#define RTC_LOG_ENABLED() 0
#else
#define RTC_LOG_ENABLED() 1
#endif
namespace rtc {
//////////////////////////////////////////////////////////////////////
// Note that the non-standard LoggingSeverity aliases exist because they are
// still in broad use. 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
// in debug builds.
// LS_WARNING: Something that may warrant investigation.
// LS_ERROR: Something that should not have occurred.
// LS_NONE: Don't log.
enum LoggingSeverity {
LS_VERBOSE,
LS_INFO,
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.
enum LogErrorContext {
ERRCTX_NONE,
ERRCTX_ERRNO, // System-local errno
ERRCTX_HRESULT, // Windows HRESULT
// Abbreviations for LOG_E macro
ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x)
ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x)
};
class LogMessage;
// Virtual sink interface that can receive log messages.
class LogSink {
public:
LogSink() {}
virtual ~LogSink() {}
virtual void OnLogMessage(const std::string& msg,
LoggingSeverity severity,
const char* tag);
virtual void OnLogMessage(const std::string& message,
LoggingSeverity severity);
virtual void OnLogMessage(const std::string& message) = 0;
private:
friend class ::rtc::LogMessage;
#if RTC_LOG_ENABLED()
// Members for LogMessage class to keep linked list of the registered sinks.
LogSink* next_ = nullptr;
LoggingSeverity min_severity_;
#endif
};
namespace webrtc_logging_impl {
class LogMetadata {
public:
LogMetadata(const char* file, int line, LoggingSeverity severity)
: file_(file),
line_and_sev_(static_cast<uint32_t>(line) << 3 | severity) {}
LogMetadata() = default;
const char* File() const { return file_; }
int Line() const { return line_and_sev_ >> 3; }
LoggingSeverity Severity() const {
return static_cast<LoggingSeverity>(line_and_sev_ & 0x7);
}
private:
const char* file_;
// Line number and severity, the former in the most significant 29 bits, the
// latter in the least significant 3 bits. (This is an optimization; since
// both numbers are usually compile-time constants, this way we can load them
// both with a single instruction.)
uint32_t line_and_sev_;
};
static_assert(std::is_trivial<LogMetadata>::value, "");
struct LogMetadataErr {
LogMetadata meta;
LogErrorContext err_ctx;
int err;
};
#ifdef WEBRTC_ANDROID
struct LogMetadataTag {
LoggingSeverity severity;
const char* tag;
};
#endif
enum class LogArgType : int8_t {
kEnd = 0,
kInt,
kLong,
kLongLong,
kUInt,
kULong,
kULongLong,
kDouble,
kLongDouble,
kCharP,
kStdString,
kStringView,
kVoidP,
kLogMetadata,
kLogMetadataErr,
#ifdef WEBRTC_ANDROID
kLogMetadataTag,
#endif
};
// Wrapper for log arguments. Only ever make values of this type with the
// MakeVal() functions.
template <LogArgType N, typename T>
struct Val {
static constexpr LogArgType Type() { return N; }
T GetVal() const { return val; }
T val;
};
// Case for when we need to construct a temp string and then print that.
// (We can't use Val<CheckArgType::kStdString, const std::string*>
// because we need somewhere to store the temp string.)
struct ToStringVal {
static constexpr LogArgType Type() { return LogArgType::kStdString; }
const std::string* GetVal() const { return &val; }
std::string val;
};
inline Val<LogArgType::kInt, int> MakeVal(int x) {
return {x};
}
inline Val<LogArgType::kLong, long> MakeVal(long x) {
return {x};
}
inline Val<LogArgType::kLongLong, long long> MakeVal(long long x) {
return {x};
}
inline Val<LogArgType::kUInt, unsigned int> MakeVal(unsigned int x) {
return {x};
}
inline Val<LogArgType::kULong, unsigned long> MakeVal(unsigned long x) {
return {x};
}
inline Val<LogArgType::kULongLong, unsigned long long> MakeVal(
unsigned long long x) {
return {x};
}
inline Val<LogArgType::kDouble, double> MakeVal(double x) {
return {x};
}
inline Val<LogArgType::kLongDouble, long double> MakeVal(long double x) {
return {x};
}
inline Val<LogArgType::kCharP, const char*> MakeVal(const char* x) {
return {x};
}
inline Val<LogArgType::kStdString, const std::string*> MakeVal(
const std::string& x) {
return {&x};
}
inline Val<LogArgType::kStringView, const absl::string_view*> MakeVal(
const absl::string_view& x) {
return {&x};
}
inline Val<LogArgType::kVoidP, const void*> MakeVal(const void* x) {
return {x};
}
inline Val<LogArgType::kLogMetadata, LogMetadata> MakeVal(
const LogMetadata& x) {
return {x};
}
inline Val<LogArgType::kLogMetadataErr, LogMetadataErr> MakeVal(
const LogMetadataErr& x) {
return {x};
}
// The enum class types are not implicitly convertible to arithmetic types.
template <typename T,
absl::enable_if_t<std::is_enum<T>::value &&
!std::is_arithmetic<T>::value>* = nullptr>
inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal(
T x) {
return {static_cast<absl::underlying_type_t<T>>(x)};
}
#ifdef WEBRTC_ANDROID
inline Val<LogArgType::kLogMetadataTag, LogMetadataTag> MakeVal(
const LogMetadataTag& x) {
return {x};
}
#endif
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 {};
// 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
// it anymore. No in-tree caller does, but some external callers still do.
template <
typename T,
typename T1 = absl::decay_t<T>,
absl::enable_if_t<std::is_class<T1>::value &&
!std::is_same<T1, std::string>::value &&
!std::is_same<T1, LogMetadata>::value &&
!has_to_log_string<T1>::value &&
#ifdef WEBRTC_ANDROID
!std::is_same<T1, LogMetadataTag>::value &&
#endif
!std::is_same<T1, LogMetadataErr>::value>* = nullptr>
ToStringVal MakeVal(const T& x) {
std::ostringstream os; // no-presubmit-check TODO(webrtc:8982)
os << 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
inline void Log(const LogArgType* fmt, ...) {
// Do nothing, shouldn't be invoked
}
#endif
// Ephemeral type that represents the result of the logging << operator.
template <typename... Ts>
class LogStreamer;
// Base case: Before the first << argument.
template <>
class LogStreamer<> final {
public:
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<std::is_arithmetic<U>::value ||
std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const {
return LogStreamer<V>(MakeVal(arg), this);
}
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<!std::is_arithmetic<U>::value &&
!std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const {
return LogStreamer<V>(MakeVal(arg), this);
}
template <typename... Us>
RTC_FORCE_INLINE static void Call(const Us&... args) {
static constexpr LogArgType t[] = {Us::Type()..., LogArgType::kEnd};
Log(t, args.GetVal()...);
}
};
// Inductive case: We've already seen at least one << argument. The most recent
// one had type `T`, and the earlier ones had types `Ts`.
template <typename T, typename... Ts>
class LogStreamer<T, Ts...> final {
public:
RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
: arg_(arg), prior_(prior) {}
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<std::is_arithmetic<U>::value ||
std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(U arg) const {
return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
}
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<!std::is_arithmetic<U>::value &&
!std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(const U& arg) const {
return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
}
template <typename... Us>
RTC_FORCE_INLINE void Call(const Us&... args) const {
prior_->Call(arg_, args...);
}
private:
// The most recent argument.
T arg_;
// Earlier arguments.
const LogStreamer<Ts...>* prior_;
};
class LogCall final {
public:
// This can be any binary operator with precedence lower than <<.
// We return bool here to be able properly remove logging if
// RTC_DISABLE_LOGGING is defined.
template <typename... Ts>
RTC_FORCE_INLINE bool operator&(const LogStreamer<Ts...>& streamer) {
streamer.Call();
return true;
}
};
// This class is used to explicitly ignore values in the conditional
// logging macros. This avoids compiler warnings like "value computed
// is not used" and "statement has no effect".
class LogMessageVoidify {
public:
LogMessageVoidify() = default;
// This has to be an operator with a precedence lower than << but
// higher than ?:
template <typename... Ts>
void operator&(LogStreamer<Ts...>&& streamer) {}
};
} // namespace webrtc_logging_impl
// Direct use of this class is deprecated; please use the logging macros
// instead.
// TODO(bugs.webrtc.org/9278): Move this class to an unnamed namespace in the
// .cc file.
class LogMessage {
public:
// Same as the above, but using a compile-time constant for the logging
// severity. This saves space at the call site, since passing an empty struct
// is generally the same as not passing an argument at all.
template <LoggingSeverity S>
RTC_NO_INLINE LogMessage(const char* file,
int line,
std::integral_constant<LoggingSeverity, S>)
: LogMessage(file, line, S) {}
#if RTC_LOG_ENABLED()
LogMessage(const char* file, int line, LoggingSeverity sev);
LogMessage(const char* file,
int line,
LoggingSeverity sev,
LogErrorContext err_ctx,
int err);
#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();
void AddTag(const char* tag);
rtc::StringBuilder& stream();
// Returns the time at which this function was called for the first time.
// The time will be used as the logging start time.
// If this is not called externally, the LogMessage ctor also calls it, in
// 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
// epoch.
static uint32_t WallClockStartTime();
// LogThreads: Display the thread identifier of the current thread
static void LogThreads(bool on = true);
// LogTimestamps: Display the elapsed time of the program
static void LogTimestamps(bool on = true);
// These are the available logging channels
// Debug: Debug console on Windows, otherwise stderr
static void LogToDebug(LoggingSeverity min_sev);
static LoggingSeverity GetLogToDebug();
// 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
// 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
// calls.
static void RemoveLogToStream(LogSink* stream);
// Returns the severity for the specified stream, of if none is specified,
// the minimum stream severity.
static int GetLogToStream(LogSink* stream = nullptr);
// Testing against MinLogSeverity allows code to avoid potentially expensive
// logging operations by pre-checking the logging level.
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
// LogMessage.
static bool IsNoop(LoggingSeverity severity);
// Version of IsNoop that uses fewer instructions at the call site, since the
// caller doesn't have to pass an argument.
template <LoggingSeverity S>
RTC_NO_INLINE static bool IsNoop() {
return IsNoop(S);
}
#else
// Next methods do nothing; no one will call these functions.
LogMessage(const char* file, int line, LoggingSeverity sev) {}
LogMessage(const char* file,
int line,
LoggingSeverity sev,
LogErrorContext err_ctx,
int err) {}
#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() = default;
inline void AddTag(const char* tag) {}
inline rtc::StringBuilder& stream() { return print_stream_; }
inline static int64_t LogStartTime() { return 0; }
inline static uint32_t WallClockStartTime() { return 0; }
inline static void LogThreads(bool on = true) {}
inline static void LogTimestamps(bool on = true) {}
inline static void LogToDebug(LoggingSeverity min_sev) {}
inline static LoggingSeverity GetLogToDebug() {
return LoggingSeverity::LS_INFO;
}
inline static void SetLogToStderr(bool log_to_stderr) {}
inline static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {}
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) {}
static constexpr bool IsNoop(LoggingSeverity severity) { return true; }
template <LoggingSeverity S>
static constexpr bool IsNoop() {
return IsNoop(S);
}
#endif // RTC_LOG_ENABLED()
private:
friend class LogMessageForTesting;
#if RTC_LOG_ENABLED()
// 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)
// 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
// String data generated in the constructor, that should be appended to
// the message before output.
std::string extra_;
// The output streams and their associated severities
static LogSink* streams_;
// 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_;
// Determines if logs will be directed to stderr in debug mode.
static bool log_to_stderr_;
#else // RTC_LOG_ENABLED()
// 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,
LoggingSeverity severity,
const char* tag) {}
#else
inline static void OutputToDebug(const std::string& msg,
LoggingSeverity severity) {}
#endif // defined(WEBRTC_ANDROID)
inline void FinishPrintStream() {}
#endif // RTC_LOG_ENABLED()
// The stringbuilder that buffers the formatted message before output
rtc::StringBuilder print_stream_;
RTC_DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
//////////////////////////////////////////////////////////////////////
// Logging Helpers
//////////////////////////////////////////////////////////////////////
#define RTC_LOG_FILE_LINE(sev, file, line) \
::rtc::webrtc_logging_impl::LogCall() & \
::rtc::webrtc_logging_impl::LogStreamer<>() \
<< ::rtc::webrtc_logging_impl::LogMetadata(file, line, sev)
#define RTC_LOG(sev) \
!rtc::LogMessage::IsNoop<::rtc::sev>() && \
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__)
// 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_T_F(sev) \
RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": "
#else
#define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": "
#define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": "
#endif
#define RTC_LOG_CHECK_LEVEL(sev) ::rtc::LogCheckLevel(::rtc::sev)
#define RTC_LOG_CHECK_LEVEL_V(sev) ::rtc::LogCheckLevel(sev)
inline bool LogCheckLevel(LoggingSeverity sev) {
return (LogMessage::GetMinLogSeverity() <= sev);
}
#define RTC_LOG_E(sev, ctx, err) \
!rtc::LogMessage::IsNoop<::rtc::sev>() && \
::rtc::webrtc_logging_impl::LogCall() & \
::rtc::webrtc_logging_impl::LogStreamer<>() \
<< ::rtc::webrtc_logging_impl::LogMetadataErr { \
{__FILE__, __LINE__, ::rtc::sev}, ::rtc::ERRCTX_##ctx, (err) \
}
#define RTC_LOG_T(sev) RTC_LOG(sev) << this << ": "
#define RTC_LOG_ERRNO_EX(sev, err) RTC_LOG_E(sev, ERRNO, err)
#define RTC_LOG_ERRNO(sev) RTC_LOG_ERRNO_EX(sev, errno)
#if defined(WEBRTC_WIN)
#define RTC_LOG_GLE_EX(sev, err) RTC_LOG_E(sev, HRESULT, err)
#define RTC_LOG_GLE(sev) RTC_LOG_GLE_EX(sev, static_cast<int>(GetLastError()))
#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_GLE_EX(sev, err)
#define RTC_LOG_ERR(sev) RTC_LOG_GLE(sev)
#elif defined(__native_client__) && __native_client__
#define RTC_LOG_ERR_EX(sev, err) RTC_LOG(sev)
#define RTC_LOG_ERR(sev) RTC_LOG(sev)
#elif defined(WEBRTC_POSIX)
#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_ERRNO_EX(sev, err)
#define RTC_LOG_ERR(sev) RTC_LOG_ERRNO(sev)
#endif // WEBRTC_WIN
#ifdef WEBRTC_ANDROID
namespace webrtc_logging_impl {
// TODO(kwiberg): Replace these with absl::string_view.
inline const char* AdaptString(const char* str) {
return str;
}
inline const char* AdaptString(const std::string& str) {
return str.c_str();
}
} // namespace webrtc_logging_impl
#define RTC_LOG_TAG(sev, tag) \
!rtc::LogMessage::IsNoop(sev) && \
::rtc::webrtc_logging_impl::LogCall() & \
::rtc::webrtc_logging_impl::LogStreamer<>() \
<< ::rtc::webrtc_logging_impl::LogMetadataTag { \
sev, ::rtc::webrtc_logging_impl::AdaptString(tag) \
}
#else
// DEPRECATED. This macro is only intended for Android.
#define RTC_LOG_TAG(sev, tag) RTC_LOG_V(sev)
#endif
// The RTC_DLOG macros are equivalent to their RTC_LOG counterparts except that
// they only generate code in debug builds.
#if RTC_DLOG_IS_ON
#define RTC_DLOG(sev) RTC_LOG(sev)
#define RTC_DLOG_V(sev) RTC_LOG_V(sev)
#define RTC_DLOG_F(sev) RTC_LOG_F(sev)
#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_V(sev) RTC_DLOG_EAT_STREAM_PARAMS()
#define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS()
#endif
} // namespace rtc
#endif // RTC_BASE_LOGGING_H_

View File

@ -0,0 +1,56 @@
# 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_library("aligned_malloc") {
sources = [
"aligned_malloc.cc",
"aligned_malloc.h",
]
deps = [ "..:checks" ]
}
# Test only utility.
# TODO: Tag with `testonly = true` once all depending targets are correctly
# tagged.
rtc_library("fifo_buffer") {
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",
"../synchronization:mutex",
"../task_utils:pending_task_safety_flag",
"../task_utils:to_queued_task",
]
}
rtc_library("unittests") {
testonly = true
sources = [
"aligned_malloc_unittest.cc",
"fifo_buffer_unittest.cc",
]
deps = [
":aligned_malloc",
":fifo_buffer",
"../../test:test_support",
]
}

View File

@ -0,0 +1,98 @@
/*
* 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/memory/aligned_malloc.h"
#include <stdlib.h> // for free, malloc
#include <string.h> // for memcpy
#include "rtc_base/checks.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <stdint.h>
#endif
// Reference on memory alignment:
// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
namespace webrtc {
uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
// 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);
}
// Alignment must be an integer power of two.
bool ValidAlignment(size_t alignment) {
if (!alignment) {
return false;
}
return (alignment & (alignment - 1)) == 0;
}
void* GetRightAlign(const void* pointer, size_t alignment) {
if (!pointer) {
return NULL;
}
if (!ValidAlignment(alignment)) {
return NULL;
}
uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
}
void* AlignedMalloc(size_t size, size_t alignment) {
if (size == 0) {
return NULL;
}
if (!ValidAlignment(alignment)) {
return NULL;
}
// The memory is aligned towards the lowest address that so only
// alignment - 1 bytes needs to be allocated.
// A pointer to the start of the memory must be stored so that it can be
// retreived for deletion, ergo the sizeof(uintptr_t).
void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
RTC_CHECK(memory_pointer) << "Couldn't allocate memory in AlignedMalloc";
// Aligning after the sizeof(uintptr_t) bytes will leave room for the header
// in the same memory block.
uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
align_start_pos += sizeof(uintptr_t);
uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
// Store the address to the beginning of the memory just before the aligned
// memory.
uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
void* header_pointer = reinterpret_cast<void*>(header_pos);
uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
return aligned_pointer;
}
void AlignedFree(void* mem_block) {
if (mem_block == NULL) {
return;
}
uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
// Read out the address of the AlignedMemory struct from the header.
uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
void* memory_start = reinterpret_cast<void*>(memory_start_pos);
free(memory_start);
}
} // namespace webrtc

View File

@ -0,0 +1,57 @@
/*
* 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_MEMORY_ALIGNED_MALLOC_H_
#define RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
// The functions declared here
// 1) Allocates block of aligned memory.
// 2) Re-calculates a pointer such that it is aligned to a higher or equal
// address.
// Note: alignment must be a power of two. The alignment is in bytes.
#include <stddef.h>
namespace webrtc {
// 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.
void* GetRightAlign(const void* ptr, size_t alignment);
// 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);
// De-allocates memory created using the AlignedMalloc() API.
void AlignedFree(void* mem_block);
// Templated versions to facilitate usage of aligned malloc without casting
// to and from void*.
template <typename T>
T* GetRightAlign(const T* ptr, size_t alignment) {
return reinterpret_cast<T*>(
GetRightAlign(reinterpret_cast<const void*>(ptr), alignment));
}
template <typename T>
T* AlignedMalloc(size_t size, size_t alignment) {
return reinterpret_cast<T*>(AlignedMalloc(size, alignment));
}
// Deleter for use with unique_ptr. E.g., use as
// std::unique_ptr<Foo, AlignedFreeDeleter> foo;
struct AlignedFreeDeleter {
inline void operator()(void* ptr) const { AlignedFree(ptr); }
};
} // namespace webrtc
#endif // RTC_BASE_MEMORY_ALIGNED_MALLOC_H_

View File

@ -0,0 +1,64 @@
base_sources = [
'checks.cc',
'event.cc',
'event_tracer.cc',
'experiments/field_trial_parser.cc',
'logging.cc',
'memory/aligned_malloc.cc',
'platform_thread.cc',
'platform_thread_types.cc',
'race_checker.cc',
'string_encode.cc',
'string_to_number.cc',
'string_utils.cc',
'strings/string_builder.cc',
'synchronization/mutex.cc',
'synchronization/rw_lock_wrapper.cc',
'synchronization/yield.cc',
'synchronization/yield_policy.cc',
'system/file_wrapper.cc',
'time_utils.cc',
'zero_memory.cc',
]
base_headers = [
[ '', 'arraysize.h' ],
[ '', 'checks.h' ],
[ '', 'constructor_magic.h' ],
[ '', 'deprecation.h' ],
[ '', 'ref_count.h' ],
[ '', 'type_traits.h' ],
[ 'numerics', 'safe_compare.h' ],
[ 'system', 'file_wrapper.h' ],
[ 'system', 'inline.h' ],
[ '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]),
subdir: join_paths('webrtc_audio_processing', 'rtc_base', h[0])
)
endforeach
libbase = static_library('libbase',
base_sources,
dependencies: common_deps,
include_directories: webrtc_inc,
cpp_args : common_cxxflags
)
base_dep = declare_dependency(
link_with: libbase
)

View File

@ -0,0 +1,176 @@
/*
* Copyright 2016 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 file defines six constexpr functions:
//
// rtc::SafeEq // ==
// rtc::SafeNe // !=
// rtc::SafeLt // <
// rtc::SafeLe // <=
// rtc::SafeGt // >
// rtc::SafeGe // >=
//
// They each accept two arguments of arbitrary types, and in almost all cases,
// they simply call the appropriate comparison operator. However, if both
// arguments are integers, they don't compare them using C++'s quirky rules,
// but instead adhere to the true mathematical definitions. It is as if the
// arguments were first converted to infinite-range signed integers, and then
// compared, although of course nothing expensive like that actually takes
// place. In practice, for signed/signed and unsigned/unsigned comparisons and
// some mixed-signed comparisons with a compile-time constant, the overhead is
// zero; in the remaining cases, it is just a few machine instructions (no
// branches).
#ifndef RTC_BASE_NUMERICS_SAFE_COMPARE_H_
#define RTC_BASE_NUMERICS_SAFE_COMPARE_H_
#include <stddef.h>
#include <stdint.h>
#include <type_traits>
#include <utility>
#include "rtc_base/type_traits.h"
namespace rtc {
namespace safe_cmp_impl {
template <size_t N>
struct LargerIntImpl : std::false_type {};
template <>
struct LargerIntImpl<sizeof(int8_t)> : std::true_type {
using type = int16_t;
};
template <>
struct LargerIntImpl<sizeof(int16_t)> : std::true_type {
using type = int32_t;
};
template <>
struct LargerIntImpl<sizeof(int32_t)> : std::true_type {
using type = int64_t;
};
// LargerInt<T1, T2>::value is true iff there's a signed type that's larger
// than T1 (and no larger than the larger of T2 and int*, for performance
// reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias
// for it.
template <typename T1, typename T2>
struct LargerInt
: LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*)
? sizeof(T1)
: 0> {};
template <typename T>
constexpr typename std::make_unsigned<T>::type MakeUnsigned(T a) {
return static_cast<typename std::make_unsigned<T>::type>(a);
}
// Overload for when both T1 and T2 have the same signedness.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_signed<T1>::value ==
std::is_signed<T2>::value>::type* = nullptr>
constexpr bool Cmp(T1 a, T2 b) {
return Op::Op(a, b);
}
// Overload for signed - unsigned comparison that can be promoted to a bigger
// signed type.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_signed<T1>::value &&
std::is_unsigned<T2>::value &&
LargerInt<T2, T1>::value>::type* = nullptr>
constexpr bool Cmp(T1 a, T2 b) {
return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b));
}
// Overload for unsigned - signed comparison that can be promoted to a bigger
// signed type.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_unsigned<T1>::value &&
std::is_signed<T2>::value &&
LargerInt<T1, T2>::value>::type* = nullptr>
constexpr bool Cmp(T1 a, T2 b) {
return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b);
}
// Overload for signed - unsigned comparison that can't be promoted to a bigger
// signed type.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_signed<T1>::value &&
std::is_unsigned<T2>::value &&
!LargerInt<T2, T1>::value>::type* = nullptr>
constexpr bool Cmp(T1 a, T2 b) {
return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b);
}
// Overload for unsigned - signed comparison that can't be promoted to a bigger
// signed type.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_unsigned<T1>::value &&
std::is_signed<T2>::value &&
!LargerInt<T1, T2>::value>::type* = nullptr>
constexpr bool Cmp(T1 a, T2 b) {
return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b));
}
#define RTC_SAFECMP_MAKE_OP(name, op) \
struct name { \
template <typename T1, typename T2> \
static constexpr bool Op(T1 a, T2 b) { \
return a op b; \
} \
};
RTC_SAFECMP_MAKE_OP(EqOp, ==)
RTC_SAFECMP_MAKE_OP(NeOp, !=)
RTC_SAFECMP_MAKE_OP(LtOp, <)
RTC_SAFECMP_MAKE_OP(LeOp, <=)
RTC_SAFECMP_MAKE_OP(GtOp, >)
RTC_SAFECMP_MAKE_OP(GeOp, >=)
#undef RTC_SAFECMP_MAKE_OP
} // namespace safe_cmp_impl
#define RTC_SAFECMP_MAKE_FUN(name) \
template <typename T1, typename T2> \
constexpr \
typename std::enable_if<IsIntlike<T1>::value && IsIntlike<T2>::value, \
bool>::type Safe##name(T1 a, T2 b) { \
/* Unary plus here turns enums into real integral types. */ \
return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \
} \
template <typename T1, typename T2> \
constexpr \
typename std::enable_if<!IsIntlike<T1>::value || !IsIntlike<T2>::value, \
bool>::type Safe##name(const T1& a, \
const T2& b) { \
return safe_cmp_impl::name##Op::Op(a, b); \
}
RTC_SAFECMP_MAKE_FUN(Eq)
RTC_SAFECMP_MAKE_FUN(Ne)
RTC_SAFECMP_MAKE_FUN(Lt)
RTC_SAFECMP_MAKE_FUN(Le)
RTC_SAFECMP_MAKE_FUN(Gt)
RTC_SAFECMP_MAKE_FUN(Ge)
#undef RTC_SAFECMP_MAKE_FUN
} // namespace rtc
#endif // RTC_BASE_NUMERICS_SAFE_COMPARE_H_

View File

@ -0,0 +1,76 @@
/*
* Copyright 2014 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/numerics/safe_conversions.h.
#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
#include <limits>
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions_impl.h"
namespace rtc {
// Convenience function that returns true if the supplied value is in range
// for the destination type.
template <typename Dst, typename Src>
inline constexpr bool IsValueInRangeForNumericType(Src value) {
return internal::RangeCheck<Dst>(value) == internal::TYPE_VALID;
}
// checked_cast<> and dchecked_cast<> are analogous to static_cast<> for
// numeric types, except that they [D]CHECK that the specified numeric
// conversion will not overflow or underflow. NaN source will always trigger
// the [D]CHECK.
template <typename Dst, typename Src>
inline constexpr Dst checked_cast(Src value) {
RTC_CHECK(IsValueInRangeForNumericType<Dst>(value));
return static_cast<Dst>(value);
}
template <typename Dst, typename Src>
inline constexpr Dst dchecked_cast(Src value) {
RTC_DCHECK(IsValueInRangeForNumericType<Dst>(value));
return static_cast<Dst>(value);
}
// saturated_cast<> is analogous to static_cast<> for numeric types, except
// that the specified numeric conversion will saturate rather than overflow or
// underflow. NaN assignment to an integral will trigger a RTC_CHECK condition.
template <typename Dst, typename Src>
inline constexpr Dst saturated_cast(Src value) {
// Optimization for floating point values, which already saturate.
if (std::numeric_limits<Dst>::is_iec559)
return static_cast<Dst>(value);
switch (internal::RangeCheck<Dst>(value)) {
case internal::TYPE_VALID:
return static_cast<Dst>(value);
case internal::TYPE_UNDERFLOW:
return std::numeric_limits<Dst>::min();
case internal::TYPE_OVERFLOW:
return std::numeric_limits<Dst>::max();
// Should fail only on attempting to assign NaN to a saturated integer.
case internal::TYPE_INVALID:
FATAL();
return std::numeric_limits<Dst>::max();
}
FATAL();
return static_cast<Dst>(value);
}
} // namespace rtc
#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_

View File

@ -0,0 +1,177 @@
/*
* Copyright 2014 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h.
#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#include <limits>
namespace rtc {
namespace internal {
enum DstSign { DST_UNSIGNED, DST_SIGNED };
enum SrcSign { SRC_UNSIGNED, SRC_SIGNED };
enum DstRange { OVERLAPS_RANGE, CONTAINS_RANGE };
// Helper templates to statically determine if our destination type can contain
// all values represented by the source type.
template <typename Dst,
typename Src,
DstSign IsDstSigned =
std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
SrcSign IsSrcSigned =
std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED>
struct StaticRangeCheck {};
template <typename Dst, typename Src>
struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_SIGNED> {
typedef std::numeric_limits<Dst> DstLimits;
typedef std::numeric_limits<Src> SrcLimits;
// Compare based on max_exponent, which we must compute for integrals.
static const size_t kDstMaxExponent =
DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
static const size_t kSrcMaxExponent =
SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1);
static const DstRange value =
kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
};
template <typename Dst, typename Src>
struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED> {
static const DstRange value =
sizeof(Dst) >= sizeof(Src) ? CONTAINS_RANGE : OVERLAPS_RANGE;
};
template <typename Dst, typename Src>
struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_UNSIGNED> {
typedef std::numeric_limits<Dst> DstLimits;
typedef std::numeric_limits<Src> SrcLimits;
// Compare based on max_exponent, which we must compute for integrals.
static const size_t kDstMaxExponent =
DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
static const size_t kSrcMaxExponent = sizeof(Src) * 8;
static const DstRange value =
kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
};
template <typename Dst, typename Src>
struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_SIGNED> {
static const DstRange value = OVERLAPS_RANGE;
};
enum RangeCheckResult {
TYPE_VALID = 0, // Value can be represented by the destination type.
TYPE_UNDERFLOW = 1, // Value would overflow.
TYPE_OVERFLOW = 2, // Value would underflow.
TYPE_INVALID = 3 // Source value is invalid (i.e. NaN).
};
// This macro creates a RangeCheckResult from an upper and lower bound
// check by taking advantage of the fact that only NaN can be out of range in
// both directions at once.
#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \
RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \
((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW))
template <typename Dst,
typename Src,
DstSign IsDstSigned =
std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
SrcSign IsSrcSigned =
std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED,
DstRange IsSrcRangeContained = StaticRangeCheck<Dst, Src>::value>
struct RangeCheckImpl {};
// The following templates are for ranges that must be verified at runtime. We
// split it into checks based on signedness to avoid confusing casts and
// compiler warnings on signed an unsigned comparisons.
// Dst range always contains the result: nothing to check.
template <typename Dst, typename Src, DstSign IsDstSigned, SrcSign IsSrcSigned>
struct RangeCheckImpl<Dst, Src, IsDstSigned, IsSrcSigned, CONTAINS_RANGE> {
static constexpr RangeCheckResult Check(Src value) { return TYPE_VALID; }
};
// Signed to signed narrowing.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
static constexpr RangeCheckResult Check(Src value) {
typedef std::numeric_limits<Dst> DstLimits;
return DstLimits::is_iec559
? BASE_NUMERIC_RANGE_CHECK_RESULT(
value <= static_cast<Src>(DstLimits::max()),
value >= static_cast<Src>(DstLimits::max() * -1))
: BASE_NUMERIC_RANGE_CHECK_RESULT(
value <= static_cast<Src>(DstLimits::max()),
value >= static_cast<Src>(DstLimits::min()));
}
};
// Unsigned to unsigned narrowing.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
static constexpr RangeCheckResult Check(Src value) {
typedef std::numeric_limits<Dst> DstLimits;
return BASE_NUMERIC_RANGE_CHECK_RESULT(
value <= static_cast<Src>(DstLimits::max()), true);
}
};
// Unsigned to signed.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
static constexpr RangeCheckResult Check(Src value) {
typedef std::numeric_limits<Dst> DstLimits;
return sizeof(Dst) > sizeof(Src)
? TYPE_VALID
: BASE_NUMERIC_RANGE_CHECK_RESULT(
value <= static_cast<Src>(DstLimits::max()), true);
}
};
// Signed to unsigned.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
typedef std::numeric_limits<Dst> DstLimits;
typedef std::numeric_limits<Src> SrcLimits;
// Compare based on max_exponent, which we must compute for integrals.
static constexpr size_t DstMaxExponent() { return sizeof(Dst) * 8; }
static constexpr size_t SrcMaxExponent() {
return SrcLimits::is_iec559 ? SrcLimits::max_exponent
: (sizeof(Src) * 8 - 1);
}
static constexpr RangeCheckResult Check(Src value) {
return (DstMaxExponent() >= SrcMaxExponent())
? BASE_NUMERIC_RANGE_CHECK_RESULT(true,
value >= static_cast<Src>(0))
: BASE_NUMERIC_RANGE_CHECK_RESULT(
value <= static_cast<Src>(DstLimits::max()),
value >= static_cast<Src>(0));
}
};
template <typename Dst, typename Src>
inline constexpr RangeCheckResult RangeCheck(Src value) {
static_assert(std::numeric_limits<Src>::is_specialized,
"argument must be numeric");
static_assert(std::numeric_limits<Dst>::is_specialized,
"result must be numeric");
return RangeCheckImpl<Dst, Src>::Check(value);
}
} // namespace internal
} // namespace rtc
#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_

View File

@ -0,0 +1,335 @@
/*
* Copyright 2017 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.
*/
// Minimum and maximum
// ===================
//
// rtc::SafeMin(x, y)
// rtc::SafeMax(x, y)
//
// (These are both constexpr.)
//
// Accept two arguments of either any two integral or any two floating-point
// types, and return the smaller and larger value, respectively, with no
// truncation or wrap-around. If only one of the input types is statically
// guaranteed to be able to represent the result, the return type is that type;
// if either one would do, the result type is the smaller type. (One of these
// two cases always applies.)
//
// * The case with one floating-point and one integral type is not allowed,
// because the floating-point type will have greater range, but may not
// have sufficient precision to represent the integer value exactly.)
//
// Clamp (a.k.a. constrain to a given interval)
// ============================================
//
// rtc::SafeClamp(x, a, b)
//
// Accepts three arguments of any mix of integral types or any mix of
// floating-point types, and returns the value in the closed interval [a, b]
// that is closest to x (that is, if x < a it returns a; if x > b it returns b;
// and if a <= x <= b it returns x). As for SafeMin() and SafeMax(), there is
// no truncation or wrap-around. The result type
//
// 1. is statically guaranteed to be able to represent the result;
//
// 2. is no larger than the largest of the three argument types; and
//
// 3. has the same signedness as the type of the first argument, if this is
// possible without violating the First or Second Law.
//
// There is always at least one type that meets criteria 1 and 2. If more than
// one type meets these criteria equally well, the result type is one of the
// types that is smallest. Note that unlike SafeMin() and SafeMax(),
// SafeClamp() will sometimes pick a return type that isn't the type of any of
// its arguments.
//
// * In this context, a type A is smaller than a type B if it has a smaller
// range; that is, if A::max() - A::min() < B::max() - B::min(). For
// example, int8_t < int16_t == uint16_t < int32_t, and all integral types
// are smaller than all floating-point types.)
//
// * As for SafeMin and SafeMax, mixing integer and floating-point arguments
// is not allowed, because floating-point types have greater range than
// integer types, but do not have sufficient precision to represent the
// values of most integer types exactly.
//
// Requesting a specific return type
// =================================
//
// All three functions allow callers to explicitly specify the return type as a
// template parameter, overriding the default return type. E.g.
//
// rtc::SafeMin<int>(x, y) // returns an int
//
// If the requested type is statically guaranteed to be able to represent the
// result, then everything's fine, and the return type is as requested. But if
// the requested type is too small, a static_assert is triggered.
#ifndef RTC_BASE_NUMERICS_SAFE_MINMAX_H_
#define RTC_BASE_NUMERICS_SAFE_MINMAX_H_
#include <limits>
#include <type_traits>
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_compare.h"
#include "rtc_base/type_traits.h"
namespace rtc {
namespace safe_minmax_impl {
// Make the range of a type available via something other than a constexpr
// function, to work around MSVC limitations. See
// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
template <typename T>
struct Limits {
static constexpr T lowest = std::numeric_limits<T>::lowest();
static constexpr T max = std::numeric_limits<T>::max();
};
template <typename T, bool is_enum = std::is_enum<T>::value>
struct UnderlyingType;
template <typename T>
struct UnderlyingType<T, false> {
using type = T;
};
template <typename T>
struct UnderlyingType<T, true> {
using type = typename std::underlying_type<T>::type;
};
// Given two types T1 and T2, find types that can hold the smallest (in
// ::min_t) and the largest (in ::max_t) of the two values.
template <typename T1,
typename T2,
bool int1 = IsIntlike<T1>::value,
bool int2 = IsIntlike<T2>::value>
struct MType {
static_assert(int1 == int2,
"You may not mix integral and floating-point arguments");
};
// Specialization for when neither type is integral (and therefore presumably
// floating-point).
template <typename T1, typename T2>
struct MType<T1, T2, false, false> {
using min_t = typename std::common_type<T1, T2>::type;
static_assert(std::is_same<min_t, T1>::value ||
std::is_same<min_t, T2>::value,
"");
using max_t = typename std::common_type<T1, T2>::type;
static_assert(std::is_same<max_t, T1>::value ||
std::is_same<max_t, T2>::value,
"");
};
// Specialization for when both types are integral.
template <typename T1, typename T2>
struct MType<T1, T2, true, true> {
// The type with the lowest minimum value. In case of a tie, the type with
// the lowest maximum value. In case that too is a tie, the types have the
// same range, and we arbitrarily pick T1.
using min_t = typename std::conditional<
SafeLt(Limits<T1>::lowest, Limits<T2>::lowest),
T1,
typename std::conditional<
SafeGt(Limits<T1>::lowest, Limits<T2>::lowest),
T2,
typename std::conditional<SafeLe(Limits<T1>::max, Limits<T2>::max),
T1,
T2>::type>::type>::type;
static_assert(std::is_same<min_t, T1>::value ||
std::is_same<min_t, T2>::value,
"");
// The type with the highest maximum value. In case of a tie, the types have
// the same range (because in C++, integer types with the same maximum also
// have the same minimum).
static_assert(SafeNe(Limits<T1>::max, Limits<T2>::max) ||
SafeEq(Limits<T1>::lowest, Limits<T2>::lowest),
"integer types with the same max should have the same min");
using max_t = typename std::
conditional<SafeGe(Limits<T1>::max, Limits<T2>::max), T1, T2>::type;
static_assert(std::is_same<max_t, T1>::value ||
std::is_same<max_t, T2>::value,
"");
};
// A dummy type that we pass around at compile time but never actually use.
// Declared but not defined.
struct DefaultType;
// ::type is A, except we fall back to B if A is DefaultType. We static_assert
// that the chosen type can hold all values that B can hold.
template <typename A, typename B>
struct TypeOr {
using type = typename std::
conditional<std::is_same<A, DefaultType>::value, B, A>::type;
static_assert(SafeLe(Limits<type>::lowest, Limits<B>::lowest) &&
SafeGe(Limits<type>::max, Limits<B>::max),
"The specified type isn't large enough");
static_assert(IsIntlike<type>::value == IsIntlike<B>::value &&
std::is_floating_point<type>::value ==
std::is_floating_point<type>::value,
"float<->int conversions not allowed");
};
} // namespace safe_minmax_impl
template <
typename R = safe_minmax_impl::DefaultType,
typename T1 = safe_minmax_impl::DefaultType,
typename T2 = safe_minmax_impl::DefaultType,
typename R2 = typename safe_minmax_impl::TypeOr<
R,
typename safe_minmax_impl::MType<
typename safe_minmax_impl::UnderlyingType<T1>::type,
typename safe_minmax_impl::UnderlyingType<T2>::type>::min_t>::type>
constexpr R2 SafeMin(T1 a, T2 b) {
static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
"The first argument must be integral or floating-point");
static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
"The second argument must be integral or floating-point");
return SafeLt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
}
template <
typename R = safe_minmax_impl::DefaultType,
typename T1 = safe_minmax_impl::DefaultType,
typename T2 = safe_minmax_impl::DefaultType,
typename R2 = typename safe_minmax_impl::TypeOr<
R,
typename safe_minmax_impl::MType<
typename safe_minmax_impl::UnderlyingType<T1>::type,
typename safe_minmax_impl::UnderlyingType<T2>::type>::max_t>::type>
constexpr R2 SafeMax(T1 a, T2 b) {
static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
"The first argument must be integral or floating-point");
static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
"The second argument must be integral or floating-point");
return SafeGt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
}
namespace safe_minmax_impl {
// Given three types T, L, and H, let ::type be a suitable return value for
// SafeClamp(T, L, H). See the docs at the top of this file for details.
template <typename T,
typename L,
typename H,
bool int1 = IsIntlike<T>::value,
bool int2 = IsIntlike<L>::value,
bool int3 = IsIntlike<H>::value>
struct ClampType {
static_assert(int1 == int2 && int1 == int3,
"You may not mix integral and floating-point arguments");
};
// Specialization for when all three types are floating-point.
template <typename T, typename L, typename H>
struct ClampType<T, L, H, false, false, false> {
using type = typename std::common_type<T, L, H>::type;
};
// Specialization for when all three types are integral.
template <typename T, typename L, typename H>
struct ClampType<T, L, H, true, true, true> {
private:
// Range of the return value. The return type must be able to represent this
// full range.
static constexpr auto r_min =
SafeMax(Limits<L>::lowest, SafeMin(Limits<H>::lowest, Limits<T>::lowest));
static constexpr auto r_max =
SafeMin(Limits<H>::max, SafeMax(Limits<L>::max, Limits<T>::max));
// Is the given type an acceptable return type? (That is, can it represent
// all possible return values, and is it no larger than the largest of the
// input types?)
template <typename A>
struct AcceptableType {
private:
static constexpr bool not_too_large = sizeof(A) <= sizeof(L) ||
sizeof(A) <= sizeof(H) ||
sizeof(A) <= sizeof(T);
static constexpr bool range_contained =
SafeLe(Limits<A>::lowest, r_min) && SafeLe(r_max, Limits<A>::max);
public:
static constexpr bool value = not_too_large && range_contained;
};
using best_signed_type = typename std::conditional<
AcceptableType<int8_t>::value,
int8_t,
typename std::conditional<
AcceptableType<int16_t>::value,
int16_t,
typename std::conditional<AcceptableType<int32_t>::value,
int32_t,
int64_t>::type>::type>::type;
using best_unsigned_type = typename std::conditional<
AcceptableType<uint8_t>::value,
uint8_t,
typename std::conditional<
AcceptableType<uint16_t>::value,
uint16_t,
typename std::conditional<AcceptableType<uint32_t>::value,
uint32_t,
uint64_t>::type>::type>::type;
public:
// Pick the best type, preferring the same signedness as T but falling back
// to the other one if necessary.
using type = typename std::conditional<
std::is_signed<T>::value,
typename std::conditional<AcceptableType<best_signed_type>::value,
best_signed_type,
best_unsigned_type>::type,
typename std::conditional<AcceptableType<best_unsigned_type>::value,
best_unsigned_type,
best_signed_type>::type>::type;
static_assert(AcceptableType<type>::value, "");
};
} // namespace safe_minmax_impl
template <
typename R = safe_minmax_impl::DefaultType,
typename T = safe_minmax_impl::DefaultType,
typename L = safe_minmax_impl::DefaultType,
typename H = safe_minmax_impl::DefaultType,
typename R2 = typename safe_minmax_impl::TypeOr<
R,
typename safe_minmax_impl::ClampType<
typename safe_minmax_impl::UnderlyingType<T>::type,
typename safe_minmax_impl::UnderlyingType<L>::type,
typename safe_minmax_impl::UnderlyingType<H>::type>::type>::type>
R2 SafeClamp(T x, L min, H max) {
static_assert(IsIntlike<H>::value || std::is_floating_point<H>::value,
"The first argument must be integral or floating-point");
static_assert(IsIntlike<T>::value || std::is_floating_point<T>::value,
"The second argument must be integral or floating-point");
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);
}
} // namespace rtc
#endif // RTC_BASE_NUMERICS_SAFE_MINMAX_H_

View File

@ -0,0 +1,192 @@
/*
* 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/platform_thread.h"
#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;
}
#else
void* PlatformThread::StartThread(void* param) {
static_cast<PlatformThread*>(param)->Run();
return 0;
}
#endif // defined(WEBRTC_WIN)
void PlatformThread::Start() {
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(!thread_) << "Thread already started?";
#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;
#elif defined(__native_client__) || defined(WEBRTC_FUCHSIA)
// Setting thread priorities is not supported in NaCl or Fuchsia.
return true;
#elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
// TODO(tommi): Switch to the same mechanism as Chromium uses for changing
// thread priorities.
return true;
#else
const int policy = SCHED_FIFO;
const int min_prio = sched_get_priority_min(policy);
const int max_prio = sched_get_priority_max(policy);
if (min_prio == -1 || max_prio == -1) {
return false;
}
if (max_prio - min_prio <= 2)
return false;
// Convert webrtc priority to system priorities:
sched_param param;
const int top_prio = max_prio - 1;
const int low_prio = min_prio + 1;
switch (priority) {
case kLowPriority:
param.sched_priority = low_prio;
break;
case kNormalPriority:
// 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:
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:
param.sched_priority = top_prio;
break;
}
return pthread_setschedparam(thread_, policy, &param) == 0;
#endif // defined(WEBRTC_WIN)
}
#if defined(WEBRTC_WIN)
bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) {
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(IsRunning());
return QueueUserAPC(function, thread_, data) != FALSE;
}
#endif
} // namespace rtc

View File

@ -0,0 +1,104 @@
/*
* 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_PLATFORM_THREAD_H_
#define RTC_BASE_PLATFORM_THREAD_H_
#ifndef WEBRTC_WIN
#include <pthread.h>
#endif
#include <string>
#include "absl/strings/string_view.h"
#include "rtc_base/constructor_magic.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
};
// 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 {
public:
PlatformThread(ThreadRunFunction func,
void* obj,
absl::string_view thread_name,
ThreadPriority priority = kNormalPriority);
virtual ~PlatformThread();
const std::string& name() const { return name_; }
// Spawns a thread and tries to set thread priority according to the priority
// from when CreateThread was called.
void Start();
bool IsRunning() const;
// Returns an identifier for the worker thread that can be used to do
// thread checks.
PlatformThreadRef GetThreadRef() const;
// Stops (joins) the spawned thread.
void Stop();
protected:
#if defined(WEBRTC_WIN)
// Exposed to derived classes to allow for special cases specific to Windows.
bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data);
#endif
private:
void Run();
bool SetPriority(ThreadPriority priority);
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);
};
} // namespace rtc
#endif // RTC_BASE_PLATFORM_THREAD_H_

View File

@ -0,0 +1,115 @@
/*
* 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.
*/
#include "rtc_base/platform_thread_types.h"
#if defined(WEBRTC_LINUX)
#include <sys/prctl.h>
#include <sys/syscall.h>
#endif
#if defined(WEBRTC_WIN)
#include "rtc_base/arraysize.h"
// The SetThreadDescription API was brought in version 1607 of Windows 10.
// For compatibility with various versions of winuser and avoid clashing with
// a potentially defined type, we use the RTC_ prefix.
typedef HRESULT(WINAPI* RTC_SetThreadDescription)(HANDLE hThread,
PCWSTR lpThreadDescription);
#endif
namespace rtc {
PlatformThreadId CurrentThreadId() {
#if defined(WEBRTC_WIN)
return GetCurrentThreadId();
#elif defined(WEBRTC_POSIX)
#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
return pthread_mach_thread_np(pthread_self());
#elif defined(WEBRTC_ANDROID)
return gettid();
#elif defined(WEBRTC_FUCHSIA)
return zx_thread_self();
#elif defined(WEBRTC_LINUX)
return syscall(__NR_gettid);
#elif defined(__EMSCRIPTEN__)
return static_cast<PlatformThreadId>(pthread_self());
#else
// Default implementation for nacl and solaris.
return reinterpret_cast<PlatformThreadId>(pthread_self());
#endif
#endif // defined(WEBRTC_POSIX)
}
PlatformThreadRef CurrentThreadRef() {
#if defined(WEBRTC_WIN)
return GetCurrentThreadId();
#elif defined(WEBRTC_FUCHSIA)
return zx_thread_self();
#elif defined(WEBRTC_POSIX)
return pthread_self();
#endif
}
bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
#if defined(WEBRTC_WIN) || defined(WEBRTC_FUCHSIA)
return a == b;
#elif defined(WEBRTC_POSIX)
return pthread_equal(a, b);
#endif
}
void SetCurrentThreadName(const char* name) {
#if defined(WEBRTC_WIN)
// The SetThreadDescription API works even if no debugger is attached.
// The names set with this API also show up in ETW traces. Very handy.
static auto set_thread_description_func =
reinterpret_cast<RTC_SetThreadDescription>(::GetProcAddress(
::GetModuleHandleA("Kernel32.dll"), "SetThreadDescription"));
if (set_thread_description_func) {
// Convert from ASCII to UTF-16.
wchar_t wide_thread_name[64];
for (size_t i = 0; i < arraysize(wide_thread_name) - 1; ++i) {
wide_thread_name[i] = name[i];
if (wide_thread_name[i] == L'\0')
break;
}
// Guarantee null-termination.
wide_thread_name[arraysize(wide_thread_name) - 1] = L'\0';
set_thread_description_func(::GetCurrentThread(), wide_thread_name);
}
// For details see:
// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
#pragma pack(push, 8)
struct {
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
} threadname_info = {0x1000, name, static_cast<DWORD>(-1), 0};
#pragma pack(pop)
#pragma warning(push)
#pragma warning(disable : 6320 6322)
__try {
::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(ULONG_PTR),
reinterpret_cast<ULONG_PTR*>(&threadname_info));
} __except (EXCEPTION_EXECUTE_HANDLER) { // NOLINT
}
#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);
#endif
}
} // namespace rtc

View File

@ -0,0 +1,62 @@
/*
* 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_PLATFORM_THREAD_TYPES_H_
#define RTC_BASE_PLATFORM_THREAD_TYPES_H_
// clang-format off
// clang formating would change include order.
#if defined(WEBRTC_WIN)
// 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>
#elif defined(WEBRTC_FUCHSIA)
#include <zircon/types.h>
#include <zircon/process.h>
#elif defined(WEBRTC_POSIX)
#include <pthread.h>
#include <unistd.h>
#if defined(WEBRTC_MAC)
#include <pthread_spis.h>
#endif
#endif
// clang-format on
namespace rtc {
#if defined(WEBRTC_WIN)
typedef DWORD PlatformThreadId;
typedef DWORD PlatformThreadRef;
#elif defined(WEBRTC_FUCHSIA)
typedef zx_handle_t PlatformThreadId;
typedef zx_handle_t PlatformThreadRef;
#elif defined(WEBRTC_POSIX)
typedef pid_t PlatformThreadId;
typedef pthread_t PlatformThreadRef;
#endif
// Retrieve the ID of the current thread.
PlatformThreadId CurrentThreadId();
// Retrieves a reference to the current thread. On Windows, this is the same
// as CurrentThreadId. On other platforms it's the pthread_t returned by
// pthread_self().
PlatformThreadRef CurrentThreadRef();
// Compares two thread identifiers for equality.
bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b);
// Sets the current thread name.
void SetCurrentThreadName(const char* name);
} // namespace rtc
#endif // RTC_BASE_PLATFORM_THREAD_TYPES_H_

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2016 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/race_checker.h"
namespace rtc {
RaceChecker::RaceChecker() {}
// Note that the implementation here is in itself racy, but we pretend it does
// not matter because we want this useful in release builds without having to
// pay the cost of using atomics. A race hitting the race checker is likely to
// cause access_count_ to diverge from zero and therefore cause the ThreadRef
// comparison to fail, signaling a race, although it may not be in the exact
// spot where a race *first* appeared in the code we're trying to protect. There
// is also a chance that an actual race is missed, however the probability of
// that has been considered small enough to be an acceptable trade off.
bool RaceChecker::Acquire() const {
const PlatformThreadRef current_thread = CurrentThreadRef();
// Set new accessing thread if this is a new use.
if (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
// methods are OK since the accessing thread remains the same.
const PlatformThreadRef accessing_thread = accessing_thread_;
return IsThreadRefEqual(accessing_thread, current_thread);
}
void RaceChecker::Release() const {
--access_count_;
}
namespace internal {
RaceCheckerScope::RaceCheckerScope(const RaceChecker* race_checker)
: race_checker_(race_checker), race_check_ok_(race_checker->Acquire()) {}
bool RaceCheckerScope::RaceDetected() const {
return !race_check_ok_;
}
RaceCheckerScope::~RaceCheckerScope() {
race_checker_->Release();
}
} // namespace internal
} // namespace rtc

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2016 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_RACE_CHECKER_H_
#define RTC_BASE_RACE_CHECKER_H_
#include "rtc_base/checks.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/thread_annotations.h"
namespace rtc {
namespace internal {
class RaceCheckerScope;
} // namespace internal
// Best-effort race-checking implementation. This primitive uses no
// synchronization at all to be as-fast-as-possible in the non-racy case.
class RTC_LOCKABLE RaceChecker {
public:
friend class internal::RaceCheckerScope;
RaceChecker();
private:
bool Acquire() const RTC_EXCLUSIVE_LOCK_FUNCTION();
void Release() const RTC_UNLOCK_FUNCTION();
// Volatile to prevent code being optimized away in Acquire()/Release().
mutable volatile int access_count_ = 0;
mutable volatile PlatformThreadRef accessing_thread_;
};
namespace internal {
class RTC_SCOPED_LOCKABLE RaceCheckerScope {
public:
explicit RaceCheckerScope(const RaceChecker* race_checker)
RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker);
bool RaceDetected() const;
~RaceCheckerScope() RTC_UNLOCK_FUNCTION();
private:
const RaceChecker* const race_checker_;
const bool race_check_ok_;
};
class RTC_SCOPED_LOCKABLE RaceCheckerScopeDoNothing {
public:
explicit RaceCheckerScopeDoNothing(const RaceChecker* race_checker)
RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker) {}
~RaceCheckerScopeDoNothing() RTC_UNLOCK_FUNCTION() {}
};
} // namespace internal
} // namespace rtc
#define RTC_CHECK_RUNS_SERIALIZED(x) \
rtc::internal::RaceCheckerScope race_checker(x); \
RTC_CHECK(!race_checker.RaceDetected())
#if RTC_DCHECK_IS_ON
#define RTC_DCHECK_RUNS_SERIALIZED(x) \
rtc::internal::RaceCheckerScope race_checker(x); \
RTC_DCHECK(!race_checker.RaceDetected())
#else
#define RTC_DCHECK_RUNS_SERIALIZED(x) \
rtc::internal::RaceCheckerScopeDoNothing race_checker(x)
#endif
#endif // RTC_BASE_RACE_CHECKER_H_

View File

@ -0,0 +1,67 @@
/*
* 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_REF_COUNT_H_
#define RTC_BASE_REF_COUNT_H_
namespace rtc {
// Refcounted objects should implement the following informal interface:
//
// void AddRef() const ;
// RefCountReleaseStatus Release() const;
//
// You may access members of a reference-counted object, including the AddRef()
// and Release() methods, only if you already own a reference to it, or if
// you're borrowing someone else's reference. (A newly created object is a
// special case: the reference count is zero on construction, and the code that
// creates the object should immediately call AddRef(), bringing the reference
// count from zero to one, e.g., by constructing an rtc::scoped_refptr).
//
// AddRef() creates a new reference to the object.
//
// Release() releases a reference to the object; the caller now has one less
// reference than before the call. Returns kDroppedLastRef if the number of
// references dropped to zero because of this (in which case the object destroys
// itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise
// time the caller's reference was dropped, other references still remained (but
// if other threads own references, this may of course have changed by the time
// Release() returns).
//
// The caller of Release() must treat it in the same way as a delete operation:
// Regardless of the return value from Release(), the caller mustn't access the
// object. The object might still be alive, due to references held by other
// users of the object, but the object can go away at any time, e.g., as the
// result of another thread calling Release().
//
// Calling AddRef() and Release() manually is discouraged. It's recommended to
// use rtc::scoped_refptr to manage all pointers to reference counted objects.
// Note that rtc::scoped_refptr depends on compile-time duck-typing; formally
// implementing the below RefCountInterface is not required.
enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained };
// Interfaces where refcounting is part of the public api should
// inherit this abstract interface. The implementation of these
// methods is usually provided by the RefCountedObject template class,
// applied as a leaf in the inheritance tree.
class RefCountInterface {
public:
virtual void AddRef() const = 0;
virtual RefCountReleaseStatus Release() const = 0;
// Non-public destructor, because Release() has exclusive responsibility for
// destroying the object.
protected:
virtual ~RefCountInterface() {}
};
} // namespace rtc
#endif // RTC_BASE_REF_COUNT_H_

View File

@ -0,0 +1,64 @@
/*
* Copyright 2016 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_REF_COUNTED_OBJECT_H_
#define RTC_BASE_REF_COUNTED_OBJECT_H_
#include <type_traits>
#include <utility>
#include "rtc_base/constructor_magic.h"
#include "rtc_base/ref_count.h"
#include "rtc_base/ref_counter.h"
namespace rtc {
template <class T>
class RefCountedObject : public T {
public:
RefCountedObject() {}
template <class P0>
explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}
template <class P0, class P1, class... Args>
RefCountedObject(P0&& p0, P1&& p1, Args&&... args)
: T(std::forward<P0>(p0),
std::forward<P1>(p1),
std::forward<Args>(args)...) {}
virtual void AddRef() const { ref_count_.IncRef(); }
virtual RefCountReleaseStatus Release() const {
const auto status = ref_count_.DecRef();
if (status == RefCountReleaseStatus::kDroppedLastRef) {
delete this;
}
return status;
}
// Return whether the reference count is one. If the reference count is used
// in the conventional way, a reference count of 1 implies that the current
// thread owns the reference and no other thread shares it. This call
// performs the test for a reference count of one, and performs the memory
// barrier needed for the owning thread to act on the object, knowing that it
// has exclusive access to the object.
virtual bool HasOneRef() const { return ref_count_.HasOneRef(); }
protected:
virtual ~RefCountedObject() {}
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject);
};
} // namespace rtc
#endif // RTC_BASE_REF_COUNTED_OBJECT_H_

View File

@ -0,0 +1,75 @@
/*
* Copyright 2017 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_REF_COUNTER_H_
#define RTC_BASE_REF_COUNTER_H_
#include <atomic>
#include "rtc_base/ref_count.h"
namespace webrtc {
namespace webrtc_impl {
class RefCounter {
public:
explicit RefCounter(int ref_count) : ref_count_(ref_count) {}
RefCounter() = delete;
void IncRef() {
// Relaxed memory order: The current thread is allowed to act on the
// resource protected by the reference counter both before and after the
// atomic op, so this function doesn't prevent memory access reordering.
ref_count_.fetch_add(1, std::memory_order_relaxed);
}
// Returns kDroppedLastRef if this call dropped the last reference; the caller
// should therefore free the resource protected by the reference counter.
// Otherwise, returns kOtherRefsRemained (note that in case of multithreading,
// some other caller may have dropped the last reference by the time this call
// returns; all we know is that we didn't do it).
rtc::RefCountReleaseStatus DecRef() {
// Use release-acquire barrier to ensure all actions on the protected
// resource are finished before the resource can be freed.
// When ref_count_after_subtract > 0, this function require
// std::memory_order_release part of the barrier.
// When ref_count_after_subtract == 0, this function require
// std::memory_order_acquire part of the barrier.
// In addition std::memory_order_release is used for synchronization with
// the HasOneRef function to make sure all actions on the protected resource
// are finished before the resource is assumed to have exclusive access.
int ref_count_after_subtract =
ref_count_.fetch_sub(1, std::memory_order_acq_rel) - 1;
return ref_count_after_subtract == 0
? rtc::RefCountReleaseStatus::kDroppedLastRef
: rtc::RefCountReleaseStatus::kOtherRefsRemained;
}
// Return whether the reference count is one. If the reference count is used
// in the conventional way, a reference count of 1 implies that the current
// thread owns the reference and no other thread shares it. This call performs
// the test for a reference count of one, and performs the memory barrier
// needed for the owning thread to act on the resource protected by the
// reference counter, knowing that it has exclusive access.
bool HasOneRef() const {
// To ensure resource protected by the reference counter has exclusive
// access, all changes to the resource before it was released by other
// threads must be visible by current thread. That is provided by release
// (in DecRef) and acquire (in this function) ordering.
return ref_count_.load(std::memory_order_acquire) == 1;
}
private:
std::atomic<int> ref_count_;
};
} // namespace webrtc_impl
} // namespace webrtc
#endif // RTC_BASE_REF_COUNTER_H_

144
webrtc/rtc_base/sanitizer.h Normal file
View File

@ -0,0 +1,144 @@
/*
* Copyright 2016 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_SANITIZER_H_
#define RTC_BASE_SANITIZER_H_
#include <stddef.h> // For size_t.
#ifdef __cplusplus
#include "absl/meta/type_traits.h"
#endif
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define RTC_HAS_ASAN 1
#endif
#if __has_feature(memory_sanitizer)
#define RTC_HAS_MSAN 1
#endif
#endif
#ifndef RTC_HAS_ASAN
#define RTC_HAS_ASAN 0
#endif
#ifndef RTC_HAS_MSAN
#define RTC_HAS_MSAN 0
#endif
#if RTC_HAS_ASAN
#include <sanitizer/asan_interface.h>
#endif
#if RTC_HAS_MSAN
#include <sanitizer/msan_interface.h>
#endif
#ifdef __has_attribute
#if __has_attribute(no_sanitize)
#define RTC_NO_SANITIZE(what) __attribute__((no_sanitize(what)))
#endif
#endif
#ifndef RTC_NO_SANITIZE
#define RTC_NO_SANITIZE(what)
#endif
// Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements)
// as being unaddressable, so that reads and writes are not allowed. ASan may
// narrow the range to the nearest alignment boundaries.
static inline void rtc_AsanPoison(const volatile void* ptr,
size_t element_size,
size_t num_elements) {
#if RTC_HAS_ASAN
ASAN_POISON_MEMORY_REGION(ptr, element_size * num_elements);
#endif
}
// Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements)
// as being addressable, so that reads and writes are allowed. ASan may widen
// the range to the nearest alignment boundaries.
static inline void rtc_AsanUnpoison(const volatile void* ptr,
size_t element_size,
size_t num_elements) {
#if RTC_HAS_ASAN
ASAN_UNPOISON_MEMORY_REGION(ptr, element_size * num_elements);
#endif
}
// Ask MSan to mark the memory range [ptr, ptr + element_size * num_elements)
// as being uninitialized.
static inline void rtc_MsanMarkUninitialized(const volatile void* ptr,
size_t element_size,
size_t num_elements) {
#if RTC_HAS_MSAN
__msan_poison(ptr, element_size * num_elements);
#endif
}
// Force an MSan check (if any bits in the memory range [ptr, ptr +
// element_size * num_elements) are uninitialized the call will crash with an
// MSan report).
static inline void rtc_MsanCheckInitialized(const volatile void* ptr,
size_t element_size,
size_t num_elements) {
#if RTC_HAS_MSAN
__msan_check_mem_is_initialized(ptr, element_size * num_elements);
#endif
}
#ifdef __cplusplus
namespace rtc {
namespace sanitizer_impl {
template <typename T>
constexpr bool IsTriviallyCopyable() {
return static_cast<bool>(absl::is_trivially_copy_constructible<T>::value &&
(absl::is_trivially_copy_assignable<T>::value ||
!std::is_copy_assignable<T>::value) &&
absl::is_trivially_destructible<T>::value);
}
} // namespace sanitizer_impl
template <typename T>
inline void AsanPoison(const T& mem) {
rtc_AsanPoison(mem.data(), sizeof(mem.data()[0]), mem.size());
}
template <typename T>
inline void AsanUnpoison(const T& mem) {
rtc_AsanUnpoison(mem.data(), sizeof(mem.data()[0]), mem.size());
}
template <typename T>
inline void MsanMarkUninitialized(const T& mem) {
rtc_MsanMarkUninitialized(mem.data(), sizeof(mem.data()[0]), mem.size());
}
template <typename T>
inline T MsanUninitialized(T t) {
#if RTC_HAS_MSAN
// TODO(bugs.webrtc.org/8762): Switch to std::is_trivially_copyable when it
// becomes available in downstream projects.
static_assert(sanitizer_impl::IsTriviallyCopyable<T>(), "");
#endif
rtc_MsanMarkUninitialized(&t, sizeof(T), 1);
return t;
}
template <typename T>
inline void MsanCheckInitialized(const T& mem) {
rtc_MsanCheckInitialized(mem.data(), sizeof(mem.data()[0]), mem.size());
}
} // namespace rtc
#endif // __cplusplus
#endif // RTC_BASE_SANITIZER_H_

View File

@ -0,0 +1,387 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/string_encode.h"
#include <cstdio>
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
namespace rtc {
/////////////////////////////////////////////////////////////////////////////
// String Encoding Utilities
/////////////////////////////////////////////////////////////////////////////
namespace {
const char HEX[] = "0123456789abcdef";
// Convert an unsigned value from 0 to 15 to the hex character equivalent...
char hex_encode(unsigned char val) {
RTC_DCHECK_LT(val, 16);
return (val < 16) ? HEX[val] : '!';
}
// ...and vice-versa.
bool hex_decode(char ch, unsigned char* val) {
if ((ch >= '0') && (ch <= '9')) {
*val = ch - '0';
} else if ((ch >= 'A') && (ch <= 'F')) {
*val = (ch - 'A') + 10;
} else if ((ch >= 'a') && (ch <= 'f')) {
*val = (ch - 'a') + 10;
} else {
return false;
}
return true;
}
size_t hex_encode_output_length(size_t srclen, char delimiter) {
return delimiter && srclen > 0 ? (srclen * 3 - 1) : (srclen * 2);
}
// hex_encode shows the hex representation of binary data in ascii, with
// |delimiter| between bytes, or none if |delimiter| == 0.
void hex_encode_with_delimiter(char* buffer,
const char* csource,
size_t srclen,
char delimiter) {
RTC_DCHECK(buffer);
// Init and check bounds.
const unsigned char* bsource =
reinterpret_cast<const unsigned char*>(csource);
size_t srcpos = 0, bufpos = 0;
while (srcpos < srclen) {
unsigned char ch = bsource[srcpos++];
buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
buffer[bufpos + 1] = hex_encode((ch)&0xF);
bufpos += 2;
// Don't write a delimiter after the last byte.
if (delimiter && (srcpos < srclen)) {
buffer[bufpos] = delimiter;
++bufpos;
}
}
}
} // namespace
std::string hex_encode(const std::string& str) {
return hex_encode(str.c_str(), str.size());
}
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,
char delimiter) {
std::string s(hex_encode_output_length(srclen, delimiter), 0);
hex_encode_with_delimiter(&s[0], source, srclen, 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,
char delimiter) {
RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
if (buflen == 0)
return 0;
// Init and bounds check.
unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
size_t srcpos = 0, bufpos = 0;
size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
if (buflen < needed)
return 0;
while (srcpos < srclen) {
if ((srclen - srcpos) < 2) {
// This means we have an odd number of bytes.
return 0;
}
unsigned char h1, h2;
if (!hex_decode(source[srcpos], &h1) ||
!hex_decode(source[srcpos + 1], &h2))
return 0;
bbuffer[bufpos++] = (h1 << 4) | h2;
srcpos += 2;
// Remove the delimiter if needed.
if (delimiter && (srclen - srcpos) > 1) {
if (source[srcpos] != delimiter)
return 0;
++srcpos;
}
}
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 tokenize(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) {
if (i != last) {
fields->push_back(source.substr(last, i - last));
}
last = i + 1;
}
}
if (last != source.length()) {
fields->push_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,
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) {
return false;
}
// Look for additional occurrances of delimiter.
size_t right_pos = left_pos + 1;
while (source[right_pos] == delimiter) {
right_pos++;
}
*token = source.substr(0, left_pos);
*rest = 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();
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();
}
std::string ToString(const bool b) {
return b ? "true" : "false";
}
std::string ToString(const char* const s) {
return std::string(s);
}
std::string ToString(const std::string s) {
return s;
}
std::string ToString(const short s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const unsigned short s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const int s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const unsigned int s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const long int s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const unsigned long int s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const long long int s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const unsigned long long int s) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const double d) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const long double d) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
std::string ToString(const void* const p) {
char buf[32];
const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
RTC_DCHECK_LE(len, arraysize(buf));
return std::string(&buf[0], len);
}
bool FromString(const std::string& s, bool* b) {
if (s == "false") {
*b = false;
return true;
}
if (s == "true") {
*b = true;
return true;
}
return false;
}
} // namespace rtc

View File

@ -0,0 +1,154 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_STRING_ENCODE_H_
#define RTC_BASE_STRING_ENCODE_H_
#include <stddef.h>
#include <string>
#include <type_traits>
#include <vector>
#include "absl/types/optional.h"
#include "rtc_base/checks.h"
#include "rtc_base/string_to_number.h"
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);
// hex_decode converts ascii hex to binary.
size_t hex_decode(char* buffer,
size_t buflen,
const char* source,
size_t srclen);
// hex_decode, assuming that there is a delimiter between every byte
// pair.
// |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,
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);
// 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,
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,
std::string* token,
std::string* rest);
// Convert arbitrary values to/from a string.
// TODO(jonasolsson): Remove these when absl::StrCat becomes available.
std::string ToString(bool b);
std::string ToString(const char* s);
std::string ToString(std::string t);
std::string ToString(short s);
std::string ToString(unsigned short s);
std::string ToString(int s);
std::string ToString(unsigned int s);
std::string ToString(long int s);
std::string ToString(unsigned long int s);
std::string ToString(long long int s);
std::string ToString(unsigned long long int s);
std::string ToString(double t);
std::string ToString(long double t);
std::string ToString(const void* p);
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) {
RTC_DCHECK(t);
absl::optional<T> result = StringToNumber<T>(s);
if (result)
*t = *result;
return result.has_value();
}
bool FromString(const std::string& s, bool* b);
template <typename T>
static inline T FromString(const std::string& str) {
T val;
FromString(str, &val);
return val;
}
//////////////////////////////////////////////////////////////////////
} // namespace rtc
#endif // RTC_BASE_STRING_ENCODE_H__

View File

@ -0,0 +1,90 @@
/*
* Copyright 2017 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/string_to_number.h"
#include <ctype.h>
#include <cerrno>
#include <cstdlib>
#include "rtc_base/checks.h"
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] == '-') {
char* end = nullptr;
errno = 0;
const signed_type value = std::strtoll(str, &end, base);
if (end && *end == '\0' && 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] == '-') {
// 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)) {
return value;
}
}
return absl::nullopt;
}
template <typename T>
T StrToT(const char* str, char** str_end);
template <>
inline float StrToT(const char* str, char** str_end) {
return std::strtof(str, str_end);
}
template <>
inline double StrToT(const char* str, char** str_end) {
return std::strtod(str, str_end);
}
template <>
inline long double StrToT(const char* str, char** str_end) {
return std::strtold(str, str_end);
}
template <typename T>
absl::optional<T> ParseFloatingPoint(const char* str) {
RTC_DCHECK(str);
if (*str == '\0')
return absl::nullopt;
char* end = nullptr;
errno = 0;
const T value = StrToT<T>(str, &end);
if (end && *end == '\0' && 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);
} // namespace string_to_number_internal
} // namespace rtc

View File

@ -0,0 +1,116 @@
/*
* Copyright 2017 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_STRING_TO_NUMBER_H_
#define RTC_BASE_STRING_TO_NUMBER_H_
#include <limits>
#include <string>
#include <type_traits>
#include "absl/types/optional.h"
namespace rtc {
// This file declares a family of functions to parse integers from strings.
// The standard C library functions either fail to indicate errors (atoi, etc.)
// or are a hassle to work with (strtol, sscanf, etc.). The standard C++ library
// 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);
//
// 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
// failed. Values outside of the range supported by the type will be
// rejected. The strings must begin with a digit or a minus sign. No leading
// space nor trailing contents are allowed.
// 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);
template <typename T>
absl::optional<T> ParseFloatingPoint(const char* 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) {
using string_to_number_internal::signed_type;
static_assert(
std::numeric_limits<T>::max() <=
std::numeric_limits<signed_type>::max() &&
std::numeric_limits<T>::lowest() >=
std::numeric_limits<signed_type>::lowest(),
"StringToNumber only supports signed integers as large as long long int");
absl::optional<signed_type> value =
string_to_number_internal::ParseSigned(str, base);
if (value && *value >= std::numeric_limits<T>::lowest() &&
*value <= std::numeric_limits<T>::max()) {
return static_cast<T>(*value);
}
return absl::nullopt;
}
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) {
using string_to_number_internal::unsigned_type;
static_assert(std::numeric_limits<T>::max() <=
std::numeric_limits<unsigned_type>::max(),
"StringToNumber only supports unsigned integers as large as "
"unsigned long long int");
absl::optional<unsigned_type> value =
string_to_number_internal::ParseUnsigned(str, base);
if (value && *value <= std::numeric_limits<T>::max()) {
return static_cast<T>(*value);
}
return absl::nullopt;
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value,
absl::optional<T>>::type
StringToNumber(const char* 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 "
"as long double");
return string_to_number_internal::ParseFloatingPoint<T>(str);
}
// The std::string overloads only exists if there is a matching const char*
// version.
template <typename T>
auto StringToNumber(const std::string& str, int base = 10)
-> decltype(StringToNumber<T>(str.c_str(), base)) {
return StringToNumber<T>(str.c_str(), base);
}
} // namespace rtc
#endif // RTC_BASE_STRING_TO_NUMBER_H_

View File

@ -0,0 +1,53 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/string_utils.h"
namespace rtc {
size_t strcpyn(char* buffer,
size_t buflen,
const char* source,
size_t srclen /* = SIZE_UNKNOWN */) {
if (buflen <= 0)
return 0;
if (srclen == SIZE_UNKNOWN) {
srclen = strlen(source);
}
if (srclen >= buflen) {
srclen = buflen - 1;
}
memcpy(buffer, source, 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);
return std::string(buffer);
}
} // namespace rtc

View File

@ -0,0 +1,93 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_STRING_UTILS_H_
#define RTC_BASE_STRING_UTILS_H_
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#if defined(WEBRTC_WIN)
#include <malloc.h>
#include <wchar.h>
#include <windows.h>
#endif // WEBRTC_WIN
#if defined(WEBRTC_POSIX)
#include <stdlib.h>
#include <strings.h>
#endif // WEBRTC_POSIX
#include <string>
namespace rtc {
const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
// Safe version of strncpy that always nul-terminate.
size_t strcpyn(char* buffer,
size_t buflen,
const char* source,
size_t srclen = SIZE_UNKNOWN);
///////////////////////////////////////////////////////////////////////////////
// UTF helpers (Windows only)
///////////////////////////////////////////////////////////////////////////////
#if defined(WEBRTC_WIN)
inline std::wstring ToUtf16(const char* utf8, size_t len) {
if (len == 0)
return std::wstring();
int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len),
nullptr, 0);
std::wstring ws(len16, 0);
::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len), &*ws.begin(),
len16);
return ws;
}
inline std::wstring ToUtf16(const std::string& str) {
return ToUtf16(str.data(), str.length());
}
inline std::string ToUtf8(const wchar_t* wide, size_t len) {
if (len == 0)
return std::string();
int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len),
nullptr, 0, nullptr, nullptr);
std::string ns(len8, 0);
::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len), &*ns.begin(),
len8, nullptr, nullptr);
return ns;
}
inline std::string ToUtf8(const wchar_t* wide) {
return ToUtf8(wide, wcslen(wide));
}
inline std::string ToUtf8(const std::wstring& wstr) {
return ToUtf8(wstr.data(), wstr.length());
}
#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);
} // namespace rtc
#endif // RTC_BASE_STRING_UTILS_H_

View File

@ -0,0 +1,141 @@
/*
* Copyright 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.
*/
#include "rtc_base/strings/string_builder.h"
#include <stdarg.h>
#include <cstdio>
#include <cstring>
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_minmax.h"
namespace rtc {
SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView<char> buffer)
: buffer_(buffer) {
buffer_[0] = '\0';
RTC_DCHECK(IsConsistent());
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(const char* str) {
return Append(str, strlen(str));
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) {
return Append(&ch, 1);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(const std::string& str) {
return Append(str.c_str(), str.length());
}
// Numeric conversion routines.
//
// We use std::[v]snprintf instead of std::to_string because:
// * std::to_string relies on the current locale for formatting purposes,
// and therefore concurrent calls to std::to_string from multiple threads
// may result in partial serialization of calls
// * snprintf allows us to print the number directly into our buffer.
// * avoid allocating a std::string (potential heap alloc).
// TODO(tommi): Switch to std::to_chars in C++17.
SimpleStringBuilder& SimpleStringBuilder::operator<<(int i) {
return AppendFormat("%d", i);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(unsigned i) {
return AppendFormat("%u", i);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(long i) { // NOLINT
return AppendFormat("%ld", i);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(long long i) { // NOLINT
return AppendFormat("%lld", i);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(
unsigned long i) { // NOLINT
return AppendFormat("%lu", i);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(
unsigned long long i) { // NOLINT
return AppendFormat("%llu", i);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(float f) {
return AppendFormat("%g", f);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(double f) {
return AppendFormat("%g", f);
}
SimpleStringBuilder& SimpleStringBuilder::operator<<(long double f) {
return AppendFormat("%Lg", f);
}
SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
const int len =
std::vsnprintf(&buffer_[size_], buffer_.size() - size_, fmt, args);
if (len >= 0) {
const size_t chars_added = rtc::SafeMin(len, buffer_.size() - 1 - size_);
size_ += chars_added;
RTC_DCHECK_EQ(len, chars_added) << "Buffer size was insufficient";
} else {
// This should never happen, but we're paranoid, so re-write the
// terminator in case vsnprintf() overwrote it.
RTC_NOTREACHED();
buffer_[size_] = '\0';
}
va_end(args);
RTC_DCHECK(IsConsistent());
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);
va_copy(copy, args);
const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
va_end(copy);
RTC_DCHECK_GE(predicted_length, 0);
if (predicted_length > 0) {
const size_t size = str_.size();
str_.resize(size + predicted_length);
// Pass "+ 1" to vsnprintf to include space for the '\0'.
const int actual_length =
std::vsnprintf(&str_[size], predicted_length + 1, fmt, args);
RTC_DCHECK_GE(actual_length, 0);
}
va_end(args);
return *this;
}
} // namespace rtc

View File

@ -0,0 +1,175 @@
/*
* Copyright 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.
*/
#ifndef RTC_BASE_STRINGS_STRING_BUILDER_H_
#define RTC_BASE_STRINGS_STRING_BUILDER_H_
#include <cstdio>
#include <string>
#include <utility>
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "rtc_base/string_encode.h"
namespace rtc {
// This is a minimalistic string builder class meant to cover the most cases of
// 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()|.
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<<(int i);
SimpleStringBuilder& operator<<(unsigned i);
SimpleStringBuilder& operator<<(long i); // NOLINT
SimpleStringBuilder& operator<<(long long i); // NOLINT
SimpleStringBuilder& operator<<(unsigned long i); // NOLINT
SimpleStringBuilder& operator<<(unsigned long long i); // NOLINT
SimpleStringBuilder& operator<<(float f);
SimpleStringBuilder& operator<<(double f);
SimpleStringBuilder& operator<<(long double f);
// 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
// compatibility reasons.
size_t size() const { return size_; }
// Allows appending a printf style formatted string.
#if defined(__GNUC__)
__attribute__((__format__(__printf__, 2, 3)))
#endif
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';
}
// An always-zero-terminated fixed-size buffer that we write to. The fixed
// size allows the buffer to be stack allocated, which helps performance.
// Having a fixed size is furthermore useful to avoid unnecessary resizing
// while building it.
const rtc::ArrayView<char> buffer_;
// Represents the number of characters written to the buffer.
// This does not include the terminating '\0'.
size_t size_ = 0;
};
// A string builder that supports dynamic resizing while building a string.
// The class is based around an instance of std::string and allows moving
// ownership out of the class once the string has been built.
// Note that this class uses the heap for allocations, so SimpleStringBuilder
// might be more efficient for some use cases.
class StringBuilder {
public:
StringBuilder() {}
explicit StringBuilder(absl::string_view s) : str_(s) {}
// TODO(tommi): Support construction from StringBuilder?
StringBuilder(const StringBuilder&) = delete;
StringBuilder& operator=(const StringBuilder&) = delete;
StringBuilder& operator<<(const absl::string_view str) {
str_.append(str.data(), str.length());
return *this;
}
StringBuilder& operator<<(char c) = delete;
StringBuilder& operator<<(int i) {
str_ += rtc::ToString(i);
return *this;
}
StringBuilder& operator<<(unsigned i) {
str_ += rtc::ToString(i);
return *this;
}
StringBuilder& operator<<(long i) { // NOLINT
str_ += rtc::ToString(i);
return *this;
}
StringBuilder& operator<<(long long i) { // NOLINT
str_ += rtc::ToString(i);
return *this;
}
StringBuilder& operator<<(unsigned long i) { // NOLINT
str_ += rtc::ToString(i);
return *this;
}
StringBuilder& operator<<(unsigned long long i) { // NOLINT
str_ += rtc::ToString(i);
return *this;
}
StringBuilder& operator<<(float f) {
str_ += rtc::ToString(f);
return *this;
}
StringBuilder& operator<<(double f) {
str_ += rtc::ToString(f);
return *this;
}
StringBuilder& operator<<(long double f) {
str_ += rtc::ToString(f);
return *this;
}
const std::string& str() const { return str_; }
void Clear() { str_.clear(); }
size_t size() const { return str_.size(); }
std::string Release() {
std::string ret = std::move(str_);
str_.clear();
return ret;
}
// Allows appending a printf style formatted string.
StringBuilder& AppendFormat(const char* fmt, ...)
#if defined(__GNUC__)
__attribute__((__format__(__printf__, 2, 3)))
#endif
;
private:
std::string str_;
};
} // namespace rtc
#endif // RTC_BASE_STRINGS_STRING_BUILDER_H_

View File

@ -0,0 +1,249 @@
/*
* 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_SWAP_QUEUE_H_
#define RTC_BASE_SWAP_QUEUE_H_
#include <stddef.h>
#include <atomic>
#include <utility>
#include <vector>
#include "rtc_base/checks.h"
#include "rtc_base/system/unused.h"
namespace webrtc {
namespace internal {
// (Internal; please don't use outside this file.)
template <typename T>
bool NoopSwapQueueItemVerifierFunction(const T&) {
return true;
}
} // namespace internal
// Functor to use when supplying a verifier function for the queue.
template <typename T,
bool (*QueueItemVerifierFunction)(const T&) =
internal::NoopSwapQueueItemVerifierFunction>
class SwapQueueItemVerifier {
public:
bool operator()(const T& t) const { return QueueItemVerifierFunction(t); }
};
// This class is a fixed-size queue. A single producer calls Insert() to insert
// an element of type T at the back of the queue, and a single consumer calls
// Remove() to remove an element from the front of the queue. It's safe for the
// producer and the consumer to access the queue concurrently, from different
// threads.
//
// To avoid the construction, copying, and destruction of Ts that a naive
// queue implementation would require, for each "full" T passed from
// producer to consumer, SwapQueue<T> passes an "empty" T in the other
// direction (an "empty" T is one that contains nothing of value for the
// consumer). This bidirectional movement is implemented with swap().
//
// // Create queue:
// Bottle proto(568); // Prepare an empty Bottle. Heap allocates space for
// // 568 ml.
// SwapQueue<Bottle> q(N, proto); // Init queue with N copies of proto.
// // Each copy allocates on the heap.
// // Producer pseudo-code:
// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml.
// loop {
// b.Fill(amount); // Where amount <= 568 ml.
// q.Insert(&b); // Swap our full Bottle for an empty one from q.
// }
//
// // Consumer pseudo-code:
// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml.
// loop {
// q.Remove(&b); // Swap our empty Bottle for the next-in-line full Bottle.
// Drink(&b);
// }
//
// For a well-behaved Bottle class, there are no allocations in the
// producer, since it just fills an empty Bottle that's already large
// enough; no deallocations in the consumer, since it returns each empty
// Bottle to the queue after having drunk it; and no copies along the
// way, since the queue uses swap() everywhere to move full Bottles in
// one direction and empty ones in the other.
template <typename T, typename QueueItemVerifier = SwapQueueItemVerifier<T>>
class SwapQueue {
public:
// Creates a queue of size size and fills it with default constructed Ts.
explicit SwapQueue(size_t size) : queue_(size) {
RTC_DCHECK(VerifyQueueSlots());
}
// Same as above and accepts an item verification functor.
SwapQueue(size_t size, const QueueItemVerifier& queue_item_verifier)
: queue_item_verifier_(queue_item_verifier), queue_(size) {
RTC_DCHECK(VerifyQueueSlots());
}
// Creates a queue of size size and fills it with copies of prototype.
SwapQueue(size_t size, const T& prototype) : queue_(size, prototype) {
RTC_DCHECK(VerifyQueueSlots());
}
// Same as above and accepts an item verification functor.
SwapQueue(size_t size,
const T& prototype,
const QueueItemVerifier& queue_item_verifier)
: queue_item_verifier_(queue_item_verifier), queue_(size, prototype) {
RTC_DCHECK(VerifyQueueSlots());
}
// Resets the queue to have zero content while maintaining the queue size.
// Just like Remove(), this can only be called (safely) from the
// consumer.
void Clear() {
// Drop all non-empty elements by resetting num_elements_ and incrementing
// next_read_index_ by the previous value of num_elements_. Relaxed memory
// ordering is sufficient since the dropped elements are not accessed.
next_read_index_ += std::atomic_exchange_explicit(
&num_elements_, size_t{0}, std::memory_order_relaxed);
if (next_read_index_ >= queue_.size()) {
next_read_index_ -= queue_.size();
}
RTC_DCHECK_LT(next_read_index_, queue_.size());
}
// Inserts a "full" T at the back of the queue by swapping *input with an
// "empty" T from the queue.
// Returns true if the item was inserted or false if not (the queue was full).
// 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 {
RTC_DCHECK(input);
RTC_DCHECK(queue_item_verifier_(*input));
// Load the value of num_elements_. Acquire memory ordering prevents reads
// and writes to queue_[next_write_index_] to be reordered to before the
// load. (That element might be accessed by a concurrent call to Remove()
// until the load finishes.)
if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) ==
queue_.size()) {
return false;
}
using std::swap;
swap(*input, queue_[next_write_index_]);
// Increment the value of num_elements_ to account for the inserted element.
// Release memory ordering prevents the reads and writes to
// queue_[next_write_index_] to be reordered to after the increment. (Once
// the increment has finished, Remove() might start accessing that element.)
const size_t old_num_elements = std::atomic_fetch_add_explicit(
&num_elements_, size_t{1}, std::memory_order_release);
++next_write_index_;
if (next_write_index_ == queue_.size()) {
next_write_index_ = 0;
}
RTC_DCHECK_LT(next_write_index_, queue_.size());
RTC_DCHECK_LT(old_num_elements, queue_.size());
return true;
}
// Removes the frontmost "full" T from the queue by swapping it with
// the "empty" T in *output.
// Returns true if an item could be removed or false if not (the queue was
// 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 {
RTC_DCHECK(output);
RTC_DCHECK(queue_item_verifier_(*output));
// Load the value of num_elements_. Acquire memory ordering prevents reads
// and writes to queue_[next_read_index_] to be reordered to before the
// load. (That element might be accessed by a concurrent call to Insert()
// until the load finishes.)
if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) ==
0) {
return false;
}
using std::swap;
swap(*output, queue_[next_read_index_]);
// Decrement the value of num_elements_ to account for the removed element.
// Release memory ordering prevents the reads and writes to
// queue_[next_write_index_] to be reordered to after the decrement. (Once
// the decrement has finished, Insert() might start accessing that element.)
std::atomic_fetch_sub_explicit(&num_elements_, size_t{1},
std::memory_order_release);
++next_read_index_;
if (next_read_index_ == queue_.size()) {
next_read_index_ = 0;
}
RTC_DCHECK_LT(next_read_index_, queue_.size());
return true;
}
// Returns the current number of elements in the queue. Since elements may be
// concurrently added to the queue, the caller must treat this as a lower
// bound, not an exact count.
// May only be called by the consumer.
size_t SizeAtLeast() const {
// Acquire memory ordering ensures that we wait for the producer to finish
// inserting any element in progress.
return std::atomic_load_explicit(&num_elements_, std::memory_order_acquire);
}
private:
// Verify that the queue slots complies with the ItemVerifier test. This
// function is not thread-safe and can only be used in the constructors.
bool VerifyQueueSlots() {
for (const auto& v : queue_) {
RTC_DCHECK(queue_item_verifier_(v));
}
return true;
}
// TODO(peah): Change this to use std::function() once we can use C++11 std
// lib.
QueueItemVerifier queue_item_verifier_;
// Only accessed by the single producer.
size_t next_write_index_ = 0;
// Only accessed by the single consumer.
size_t next_read_index_ = 0;
// Accessed by both the producer and the consumer and used for synchronization
// between them.
std::atomic<size_t> num_elements_{0};
// The elements of the queue are acced by both the producer and the consumer,
// mediated by num_elements_. queue_.size() is constant.
std::vector<T> queue_;
SwapQueue(const SwapQueue&) = delete;
SwapQueue& operator=(const SwapQueue&) = delete;
};
} // namespace webrtc
#endif // RTC_BASE_SWAP_QUEUE_H_

View File

@ -0,0 +1,138 @@
# 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_library("yield") {
sources = [
"yield.cc",
"yield.h",
]
deps = []
}
rtc_library("mutex") {
sources = [
"mutex.cc",
"mutex.h",
"mutex_critical_section.h",
"mutex_pthread.h",
]
if (rtc_use_absl_mutex) {
sources += [ "mutex_abseil.h" ]
}
deps = [
":yield",
"..:checks",
"..:macromagic",
"..:platform_thread_types",
"../system:unused",
]
absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ]
if (rtc_use_absl_mutex) {
absl_deps += [ "//third_party/abseil-cpp/absl/synchronization" ]
}
}
rtc_library("rw_lock_wrapper") {
public = [ "rw_lock_wrapper.h" ]
sources = [ "rw_lock_wrapper.cc" ]
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") {
sources = [
"sequence_checker.cc",
"sequence_checker.h",
]
deps = [
":mutex",
"..:checks",
"..:criticalsection",
"..:macromagic",
"..:platform_thread_types",
"..:stringutils",
"../../api/task_queue",
"../system:rtc_export",
]
}
rtc_library("yield_policy") {
sources = [
"yield_policy.cc",
"yield_policy.h",
]
deps = [ "..:checks" ]
absl_deps = [
"//third_party/abseil-cpp/absl/base:config",
"//third_party/abseil-cpp/absl/base:core_headers",
]
}
if (rtc_include_tests) {
rtc_library("synchronization_unittests") {
testonly = true
sources = [
"mutex_unittest.cc",
"yield_policy_unittest.cc",
]
deps = [
":mutex",
":yield",
":yield_policy",
"..:checks",
"..:macromagic",
"..:rtc_base",
"..:rtc_event",
"../../test:test_support",
"//third_party/google_benchmark",
]
}
rtc_library("mutex_benchmark") {
testonly = true
sources = [ "mutex_benchmark.cc" ]
deps = [
":mutex",
"../system:unused",
"//third_party/google_benchmark",
]
}
rtc_library("sequence_checker_unittests") {
testonly = true
sources = [ "sequence_checker_unittest.cc" ]
deps = [
":sequence_checker",
"..:checks",
"..:rtc_base_approved",
"..:task_queue_for_test",
"../../api:function_view",
"../../test:test_main",
"../../test:test_support",
]
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/checks.h"
#include "rtc_base/synchronization/yield.h"
namespace webrtc {
#if !defined(WEBRTC_ABSL_MUTEX)
void GlobalMutex::Lock() {
while (mutex_locked_.exchange(1)) {
YieldCurrentThread();
}
}
void GlobalMutex::Unlock() {
int old = mutex_locked_.exchange(0);
RTC_DCHECK_EQ(old, 1) << "Unlock called without calling Lock first";
}
GlobalMutexLock::GlobalMutexLock(GlobalMutex* mutex) : mutex_(mutex) {
mutex_->Lock();
}
GlobalMutexLock::~GlobalMutexLock() {
mutex_->Unlock();
}
#endif // #if !defined(WEBRTC_ABSL_MUTEX)
} // namespace webrtc

View File

@ -0,0 +1,108 @@
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_H_
#define RTC_BASE_SYNCHRONIZATION_MUTEX_H_
#include <atomic>
#include "absl/base/const_init.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/unused.h"
#include "rtc_base/thread_annotations.h"
#if defined(WEBRTC_ABSL_MUTEX)
#include "rtc_base/synchronization/mutex_abseil.h" // nogncheck
#elif defined(WEBRTC_WIN)
#include "rtc_base/synchronization/mutex_critical_section.h"
#elif defined(WEBRTC_POSIX)
#include "rtc_base/synchronization/mutex_pthread.h"
#else
#error Unsupported platform.
#endif
namespace webrtc {
// The Mutex guarantees exclusive access and aims to follow Abseil semantics
// (i.e. non-reentrant etc).
class RTC_LOCKABLE Mutex final {
public:
Mutex() = default;
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
impl_.Lock();
}
RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return impl_.TryLock();
}
void Unlock() RTC_UNLOCK_FUNCTION() {
impl_.Unlock();
}
private:
MutexImpl impl_;
};
// MutexLock, for serializing execution through a scope.
class RTC_SCOPED_LOCKABLE MutexLock final {
public:
MutexLock(const MutexLock&) = delete;
MutexLock& operator=(const MutexLock&) = delete;
explicit MutexLock(Mutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(mutex)
: mutex_(mutex) {
mutex->Lock();
}
~MutexLock() RTC_UNLOCK_FUNCTION() { mutex_->Unlock(); }
private:
Mutex* mutex_;
};
// A mutex used to protect global variables. Do NOT use for other purposes.
#if defined(WEBRTC_ABSL_MUTEX)
using GlobalMutex = absl::Mutex;
using GlobalMutexLock = absl::MutexLock;
#else
class RTC_LOCKABLE GlobalMutex final {
public:
GlobalMutex(const GlobalMutex&) = delete;
GlobalMutex& operator=(const GlobalMutex&) = delete;
constexpr explicit GlobalMutex(absl::ConstInitType /*unused*/)
: mutex_locked_(0) {}
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION();
void Unlock() RTC_UNLOCK_FUNCTION();
private:
std::atomic<int> mutex_locked_; // 0 means lock not taken, 1 means taken.
};
// GlobalMutexLock, for serializing execution through a scope.
class RTC_SCOPED_LOCKABLE GlobalMutexLock final {
public:
GlobalMutexLock(const GlobalMutexLock&) = delete;
GlobalMutexLock& operator=(const GlobalMutexLock&) = delete;
explicit GlobalMutexLock(GlobalMutex* mutex)
RTC_EXCLUSIVE_LOCK_FUNCTION(mutex_);
~GlobalMutexLock() RTC_UNLOCK_FUNCTION();
private:
GlobalMutex* mutex_;
};
#endif // if defined(WEBRTC_ABSL_MUTEX)
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_

View File

@ -0,0 +1,54 @@
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_
#define RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_
#if defined(WEBRTC_WIN)
// clang-format off
// clang formating would change include order.
// Include winsock2.h before including <windows.h> to maintain consistency with
// win32.h. To include win32.h directly, it must be broken out into its own
// build target.
#include <winsock2.h>
#include <windows.h>
#include <sal.h> // must come after windows headers.
// clang-format on
#include "rtc_base/thread_annotations.h"
namespace webrtc {
class RTC_LOCKABLE MutexImpl final {
public:
MutexImpl() { InitializeCriticalSection(&critical_section_); }
MutexImpl(const MutexImpl&) = delete;
MutexImpl& operator=(const MutexImpl&) = delete;
~MutexImpl() { DeleteCriticalSection(&critical_section_); }
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
EnterCriticalSection(&critical_section_);
}
RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return TryEnterCriticalSection(&critical_section_) != FALSE;
}
void Unlock() RTC_UNLOCK_FUNCTION() {
LeaveCriticalSection(&critical_section_);
}
private:
CRITICAL_SECTION critical_section_;
};
} // namespace webrtc
#endif // #if defined(WEBRTC_WIN)
#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_

View File

@ -0,0 +1,53 @@
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_
#define RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_
#if defined(WEBRTC_POSIX)
#include <pthread.h>
#if defined(WEBRTC_MAC)
#include <pthread_spis.h>
#endif
#include "rtc_base/thread_annotations.h"
namespace webrtc {
class RTC_LOCKABLE MutexImpl final {
public:
MutexImpl() {
pthread_mutexattr_t mutex_attribute;
pthread_mutexattr_init(&mutex_attribute);
#if defined(WEBRTC_MAC)
pthread_mutexattr_setpolicy_np(&mutex_attribute,
_PTHREAD_MUTEX_POLICY_FIRSTFIT);
#endif
pthread_mutex_init(&mutex_, &mutex_attribute);
pthread_mutexattr_destroy(&mutex_attribute);
}
MutexImpl(const MutexImpl&) = delete;
MutexImpl& operator=(const MutexImpl&) = delete;
~MutexImpl() { pthread_mutex_destroy(&mutex_); }
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { pthread_mutex_lock(&mutex_); }
RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return pthread_mutex_trylock(&mutex_) == 0;
}
void Unlock() RTC_UNLOCK_FUNCTION() { pthread_mutex_unlock(&mutex_); }
private:
pthread_mutex_t mutex_;
};
} // namespace webrtc
#endif // #if defined(WEBRTC_POSIX)
#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/synchronization/rw_lock_posix.h"
#include <stddef.h>
namespace webrtc {
RWLockPosix::RWLockPosix() : lock_() {}
RWLockPosix::~RWLockPosix() {
pthread_rwlock_destroy(&lock_);
}
RWLockPosix* RWLockPosix::Create() {
RWLockPosix* ret_val = new RWLockPosix();
if (!ret_val->Init()) {
delete ret_val;
return NULL;
}
return ret_val;
}
bool RWLockPosix::Init() {
return pthread_rwlock_init(&lock_, 0) == 0;
}
void RWLockPosix::AcquireLockExclusive() {
pthread_rwlock_wrlock(&lock_);
}
void RWLockPosix::ReleaseLockExclusive() {
pthread_rwlock_unlock(&lock_);
}
void RWLockPosix::AcquireLockShared() {
pthread_rwlock_rdlock(&lock_);
}
void RWLockPosix::ReleaseLockShared() {
pthread_rwlock_unlock(&lock_);
}
} // namespace webrtc

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_
#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_
#include <pthread.h>
#include "rtc_base/synchronization/rw_lock_wrapper.h"
namespace webrtc {
class RWLockPosix : public RWLockWrapper {
public:
static RWLockPosix* Create();
~RWLockPosix() override;
void AcquireLockExclusive() override;
void ReleaseLockExclusive() override;
void AcquireLockShared() override;
void ReleaseLockShared() override;
private:
RWLockPosix();
bool Init();
pthread_rwlock_t lock_;
};
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/synchronization/rw_lock_win.h"
#include "rtc_base/logging.h"
namespace webrtc {
RWLockWin::RWLockWin() {
InitializeSRWLock(&lock_);
}
RWLockWin* RWLockWin::Create() {
return new RWLockWin();
}
void RWLockWin::AcquireLockExclusive() {
AcquireSRWLockExclusive(&lock_);
}
void RWLockWin::ReleaseLockExclusive() {
ReleaseSRWLockExclusive(&lock_);
}
void RWLockWin::AcquireLockShared() {
AcquireSRWLockShared(&lock_);
}
void RWLockWin::ReleaseLockShared() {
ReleaseSRWLockShared(&lock_);
}
} // namespace webrtc

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_
#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_
#include <Windows.h>
#include "rtc_base/synchronization/rw_lock_wrapper.h"
namespace webrtc {
class RWLockWin : public RWLockWrapper {
public:
static RWLockWin* Create();
void AcquireLockExclusive() override;
void ReleaseLockExclusive() override;
void AcquireLockShared() override;
void ReleaseLockShared() override;
private:
RWLockWin();
SRWLOCK lock_;
};
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_

View File

@ -0,0 +1,29 @@
/*
* 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_wrapper.h"
#if defined(_WIN32)
#include "rtc_base/synchronization/rw_lock_win.h"
#else
#include "rtc_base/synchronization/rw_lock_posix.h"
#endif
namespace webrtc {
RWLockWrapper* RWLockWrapper::CreateRWLock() {
#ifdef _WIN32
return RWLockWin::Create();
#else
return RWLockPosix::Create();
#endif
}
} // namespace webrtc

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_
#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_
#include "rtc_base/thread_annotations.h"
// Note, Windows pre-Vista version of RW locks are not supported natively. For
// these OSs regular critical sections have been used to approximate RW lock
// functionality and will therefore have worse performance.
namespace webrtc {
class RTC_LOCKABLE RWLockWrapper {
public:
static RWLockWrapper* CreateRWLock();
virtual ~RWLockWrapper() {}
virtual void AcquireLockExclusive() RTC_EXCLUSIVE_LOCK_FUNCTION() = 0;
virtual void ReleaseLockExclusive() RTC_UNLOCK_FUNCTION() = 0;
virtual void AcquireLockShared() RTC_SHARED_LOCK_FUNCTION() = 0;
virtual void ReleaseLockShared() RTC_UNLOCK_FUNCTION() = 0;
};
// RAII extensions of the RW lock. Prevents Acquire/Release missmatches and
// provides more compact locking syntax.
class RTC_SCOPED_LOCKABLE ReadLockScoped {
public:
explicit ReadLockScoped(RWLockWrapper& rw_lock)
RTC_SHARED_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockShared();
}
~ReadLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockShared(); }
private:
RWLockWrapper& rw_lock_;
};
class RTC_SCOPED_LOCKABLE WriteLockScoped {
public:
explicit WriteLockScoped(RWLockWrapper& rw_lock)
RTC_EXCLUSIVE_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockExclusive();
}
~WriteLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockExclusive(); }
private:
RWLockWrapper& rw_lock_;
};
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_

View File

@ -0,0 +1,112 @@
/*
* 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/synchronization/sequence_checker.h"
#if defined(WEBRTC_MAC)
#include <dispatch/dispatch.h>
#endif
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
namespace {
// On Mac, returns the label of the current dispatch queue; elsewhere, return
// null.
const void* GetSystemQueueRef() {
#if defined(WEBRTC_MAC)
return dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
#else
return nullptr;
#endif
}
} // namespace
std::string ExpectationToString(const webrtc::SequenceChecker* checker) {
#if RTC_DCHECK_IS_ON
return checker->ExpectationToString();
#endif
return std::string();
}
SequenceCheckerImpl::SequenceCheckerImpl()
: attached_(true),
valid_thread_(rtc::CurrentThreadRef()),
valid_queue_(TaskQueueBase::Current()),
valid_system_queue_(GetSystemQueueRef()) {}
SequenceCheckerImpl::~SequenceCheckerImpl() = default;
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) {
return valid_queue_ == current_queue;
}
if (valid_system_queue_ && valid_system_queue_ == current_system_queue) {
return true;
}
return rtc::IsThreadRefEqual(valid_thread_, current_thread);
}
void SequenceCheckerImpl::Detach() {
MutexLock scoped_lock(&lock_);
attached_ = false;
// We don't need to touch the other members here, they will be
// reset on the next call to IsCurrent().
}
#if RTC_DCHECK_IS_ON
std::string SequenceCheckerImpl::ExpectationToString() const {
const TaskQueueBase* const current_queue = TaskQueueBase::Current();
const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef();
const void* const current_system_queue = GetSystemQueueRef();
MutexLock scoped_lock(&lock_);
if (!attached_)
return "Checker currently not attached.";
// The format of the string is meant to compliment the one we have inside of
// FatalLog() (checks.cc). Example:
//
// # Expected: TQ: 0x0 SysQ: 0x7fff69541330 Thread: 0x11dcf6dc0
// # Actual: TQ: 0x7fa8f0604190 SysQ: 0x7fa8f0604a30 Thread: 0x700006f1a000
// TaskQueue doesn't match
rtc::StringBuilder message;
message.AppendFormat(
"# Expected: TQ: %p SysQ: %p Thread: %p\n"
"# Actual: TQ: %p SysQ: %p Thread: %p\n",
valid_queue_, valid_system_queue_,
reinterpret_cast<const void*>(valid_thread_), current_queue,
current_system_queue, reinterpret_cast<const void*>(current_thread));
if ((valid_queue_ || current_queue) && valid_queue_ != current_queue) {
message << "TaskQueue doesn't match\n";
} else if (valid_system_queue_ &&
valid_system_queue_ != current_system_queue) {
message << "System queue doesn't match\n";
} else if (!rtc::IsThreadRefEqual(valid_thread_, current_thread)) {
message << "Threads don't match\n";
}
return message.Release();
}
#endif // RTC_DCHECK_IS_ON
} // namespace webrtc

View File

@ -0,0 +1,187 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
#define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
#include <type_traits>
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// Real implementation of SequenceChecker, for use in debug mode, or
// for temporary use in release mode (e.g. to RTC_CHECK on a threading issue
// seen only in the wild).
//
// Note: You should almost always use the SequenceChecker class to get the
// right version for your build configuration.
class RTC_EXPORT SequenceCheckerImpl {
public:
SequenceCheckerImpl();
~SequenceCheckerImpl();
bool IsCurrent() const;
// Changes the task queue or thread that is checked for in IsCurrent. This can
// be useful when an object may be created on one task queue / thread and then
// used exclusively on another thread.
void Detach();
// Returns a string that is formatted to match with the error string printed
// by RTC_CHECK() when a condition is not met.
// This is used in conjunction with the RTC_DCHECK_RUN_ON() macro.
std::string ExpectationToString() const;
private:
mutable Mutex lock_;
// These are mutable so that IsCurrent can set them.
mutable bool attached_ RTC_GUARDED_BY(lock_);
mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_);
mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_);
mutable const void* valid_system_queue_ RTC_GUARDED_BY(lock_);
};
// Do nothing implementation, for use in release mode.
//
// Note: You should almost always use the SequenceChecker class to get the
// right version for your build configuration.
class SequenceCheckerDoNothing {
public:
bool IsCurrent() const { return true; }
void Detach() {}
};
// SequenceChecker is a helper class used to help verify that some methods
// of a class are called on the same task queue or thread. A
// SequenceChecker is bound to a a task queue if the object is
// created on a task queue, or a thread otherwise.
//
//
// Example:
// class MyClass {
// public:
// void Foo() {
// RTC_DCHECK_RUN_ON(sequence_checker_);
// ... (do stuff) ...
// }
//
// private:
// SequenceChecker sequence_checker_;
// }
//
// In Release mode, IsCurrent will always return true.
#if RTC_DCHECK_IS_ON
class RTC_LOCKABLE SequenceChecker : public SequenceCheckerImpl {};
#else
class RTC_LOCKABLE SequenceChecker : public SequenceCheckerDoNothing {};
#endif // RTC_ENABLE_THREAD_CHECKER
namespace webrtc_seq_check_impl {
// Helper class used by RTC_DCHECK_RUN_ON (see example usage below).
class RTC_SCOPED_LOCKABLE SequenceCheckerScope {
public:
template <typename ThreadLikeObject>
explicit SequenceCheckerScope(const ThreadLikeObject* thread_like_object)
RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
SequenceCheckerScope(const SequenceCheckerScope&) = delete;
SequenceCheckerScope& operator=(const SequenceCheckerScope&) = delete;
~SequenceCheckerScope() RTC_UNLOCK_FUNCTION() {}
template <typename ThreadLikeObject>
static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
return thread_like_object->IsCurrent();
}
};
} // namespace webrtc_seq_check_impl
} // namespace webrtc
// RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate
// variables are accessed from same thread/task queue.
// Using tools designed to check mutexes, it checks at compile time everywhere
// variable is access, there is a run-time dcheck thread/task queue is correct.
//
// class ThreadExample {
// public:
// void NeedVar1() {
// RTC_DCHECK_RUN_ON(network_thread_);
// transport_->Send();
// }
//
// private:
// rtc::Thread* network_thread_;
// int transport_ RTC_GUARDED_BY(network_thread_);
// };
//
// class SequenceCheckerExample {
// public:
// int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) {
// return var2_;
// }
//
// void CallMeFromPacer() {
// RTC_DCHECK_RUN_ON(&pacer_sequence_checker_)
// << "Should be called from pacer";
// CalledFromPacer();
// }
//
// private:
// int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_);
// SequenceChecker pacer_sequence_checker_;
// };
//
// class TaskQueueExample {
// public:
// class Encoder {
// public:
// rtc::TaskQueue* Queue() { return encoder_queue_; }
// void Encode() {
// RTC_DCHECK_RUN_ON(encoder_queue_);
// DoSomething(var_);
// }
//
// private:
// rtc::TaskQueue* const encoder_queue_;
// Frame var_ RTC_GUARDED_BY(encoder_queue_);
// };
//
// void Encode() {
// // Will fail at runtime when DCHECK is enabled:
// // encoder_->Encode();
// // Will work:
// rtc::scoped_refptr<Encoder> encoder = encoder_;
// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
// }
//
// private:
// rtc::scoped_refptr<Encoder> encoder_;
// }
// Document if a function expected to be called from same thread/task queue.
#define RTC_RUN_ON(x) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
namespace webrtc {
std::string ExpectationToString(const webrtc::SequenceChecker* checker);
// Catch-all implementation for types other than explicitly supported above.
template <typename ThreadLikeObject>
std::string ExpectationToString(const ThreadLikeObject*) {
return std::string();
}
} // namespace webrtc
#define RTC_DCHECK_RUN_ON(x) \
webrtc::webrtc_seq_check_impl::SequenceCheckerScope seq_check_scope(x); \
RTC_DCHECK((x)->IsCurrent()) << webrtc::ExpectationToString(x)
#endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_

View File

@ -0,0 +1,36 @@
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/synchronization/yield.h"
#if defined(WEBRTC_WIN)
#include <windows.h>
#else
#include <sched.h>
#include <time.h>
#endif
namespace webrtc {
void YieldCurrentThread() {
// TODO(bugs.webrtc.org/11634): use dedicated OS functionality instead of
// sleep for yielding.
#if defined(WEBRTC_WIN)
::Sleep(0);
#elif defined(WEBRTC_MAC) && defined(RTC_USE_NATIVE_MUTEX_ON_MAC) && \
!RTC_USE_NATIVE_MUTEX_ON_MAC
sched_yield();
#else
static const struct timespec ts_null = {0};
nanosleep(&ts_null, nullptr);
#endif
}
} // namespace webrtc

View File

@ -0,0 +1,20 @@
/*
* Copyright 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_YIELD_H_
#define RTC_BASE_SYNCHRONIZATION_YIELD_H_
namespace webrtc {
// Request rescheduling of threads.
void YieldCurrentThread();
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_YIELD_H_

View File

@ -0,0 +1,82 @@
/*
* 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/synchronization/yield_policy.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "rtc_base/checks.h"
#if !defined(ABSL_HAVE_THREAD_LOCAL) && defined(WEBRTC_POSIX)
#include <pthread.h>
#endif
namespace rtc {
namespace {
#if defined(ABSL_HAVE_THREAD_LOCAL)
ABSL_CONST_INIT thread_local YieldInterface* current_yield_policy = nullptr;
YieldInterface* GetCurrentYieldPolicy() {
return current_yield_policy;
}
void SetCurrentYieldPolicy(YieldInterface* ptr) {
current_yield_policy = ptr;
}
#elif defined(WEBRTC_POSIX)
// Emscripten does not support the C++11 thread_local keyword but does support
// the pthread thread-local storage API.
// https://github.com/emscripten-core/emscripten/issues/3502
ABSL_CONST_INIT pthread_key_t g_current_yield_policy_tls = 0;
void InitializeTls() {
RTC_CHECK_EQ(pthread_key_create(&g_current_yield_policy_tls, nullptr), 0);
}
pthread_key_t GetCurrentYieldPolicyTls() {
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
RTC_CHECK_EQ(pthread_once(&init_once, &InitializeTls), 0);
return g_current_yield_policy_tls;
}
YieldInterface* GetCurrentYieldPolicy() {
return static_cast<YieldInterface*>(
pthread_getspecific(GetCurrentYieldPolicyTls()));
}
void SetCurrentYieldPolicy(YieldInterface* ptr) {
pthread_setspecific(GetCurrentYieldPolicyTls(), ptr);
}
#else
#error Unsupported platform
#endif
} // namespace
ScopedYieldPolicy::ScopedYieldPolicy(YieldInterface* policy)
: previous_(GetCurrentYieldPolicy()) {
SetCurrentYieldPolicy(policy);
}
ScopedYieldPolicy::~ScopedYieldPolicy() {
SetCurrentYieldPolicy(previous_);
}
void ScopedYieldPolicy::YieldExecution() {
YieldInterface* current = GetCurrentYieldPolicy();
if (current)
current->YieldExecution();
}
} // namespace rtc

View File

@ -0,0 +1,38 @@
/*
* 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_YIELD_POLICY_H_
#define RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_
namespace rtc {
class YieldInterface {
public:
virtual ~YieldInterface() = default;
virtual void YieldExecution() = 0;
};
// Sets the current thread-local yield policy while it's in scope and reverts
// to the previous policy when it leaves the scope.
class ScopedYieldPolicy final {
public:
explicit ScopedYieldPolicy(YieldInterface* policy);
ScopedYieldPolicy(const ScopedYieldPolicy&) = delete;
ScopedYieldPolicy& operator=(const ScopedYieldPolicy&) = delete;
~ScopedYieldPolicy();
// Will yield as specified by the currently active thread-local yield policy
// (which by default is a no-op).
static void YieldExecution();
private:
YieldInterface* const previous_;
};
} // namespace rtc
#endif // RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_

View File

@ -0,0 +1,61 @@
/*
* 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.
*/
// This file contains platform-specific typedefs and defines.
// Much of it is derived from Chromium's build/build_config.h.
#ifndef RTC_BASE_SYSTEM_ARCH_H_
#define RTC_BASE_SYSTEM_ARCH_H_
// Processor architecture detection. For more info on what's defined, see:
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
// http://www.agner.org/optimize/calling_conventions.pdf
// or with gcc, run: "echo | gcc -E -dM -"
#if defined(_M_X64) || defined(__x86_64__)
#define WEBRTC_ARCH_X86_FAMILY
#define WEBRTC_ARCH_X86_64
#define WEBRTC_ARCH_64_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(_M_ARM64) || defined(__aarch64__)
#define WEBRTC_ARCH_ARM_FAMILY
#define WEBRTC_ARCH_64_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(_M_IX86) || defined(__i386__)
#define WEBRTC_ARCH_X86_FAMILY
#define WEBRTC_ARCH_X86
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__ARMEL__)
#define WEBRTC_ARCH_ARM_FAMILY
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__MIPSEL__)
#define WEBRTC_ARCH_MIPS_FAMILY
#if defined(__LP64__)
#define WEBRTC_ARCH_64_BITS
#else
#define WEBRTC_ARCH_32_BITS
#endif
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__pnacl__)
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__EMSCRIPTEN__)
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#else
#error Please add support for your architecture in rtc_base/system/arch.h
#endif
#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
#endif
#endif // RTC_BASE_SYSTEM_ARCH_H_

View File

@ -0,0 +1,72 @@
/*
* 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_SYSTEM_ASM_DEFINES_H_
#define RTC_BASE_SYSTEM_ASM_DEFINES_H_
// clang-format off
// clang formatting breaks everything here, e.g. concatenating directives,
// due to absence of context via asm keyword.
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
// Define the macros used in ARM assembly code, so that for Mac or iOS builds
// we add leading underscores for the function names.
#ifdef __APPLE__
.macro GLOBAL_FUNCTION name
.global _\name
.private_extern _\name
.endm
.macro DEFINE_FUNCTION name
_\name:
.endm
.macro CALL_FUNCTION name
bl _\name
.endm
.macro GLOBAL_LABEL name
.global _\name
.private_extern _\name
.endm
#else
.macro GLOBAL_FUNCTION name
.global \name
.hidden \name
.endm
.macro DEFINE_FUNCTION name
#if defined(__linux__) && defined(__ELF__)
.type \name,%function
#endif
\name:
.endm
.macro CALL_FUNCTION name
bl \name
.endm
.macro GLOBAL_LABEL name
.global \name
.hidden \name
.endm
#endif
// With Apple's clang compiler, for instructions ldrb, strh, etc.,
// the condition code is after the width specifier. Here we define
// only the ones that are actually used in the assembly files.
#if (defined __llvm__) && (defined __APPLE__)
.macro streqh reg1, reg2, num
strheq \reg1, \reg2, \num
.endm
#endif
.text
// clang-format on
#endif // RTC_BASE_SYSTEM_ASM_DEFINES_H_

View File

@ -0,0 +1,127 @@
/*
* 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/system/file_wrapper.h"
#include "rtc_base/numerics/safe_conversions.h"
#include <cerrno>
#ifdef _WIN32
#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) {
#if defined(_WIN32)
int len = MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, nullptr, 0);
std::wstring wstr(len, 0);
MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -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");
#endif
if (!file && error) {
*error = errno;
}
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) {
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,
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));
}
FileWrapper& FileWrapper::operator=(FileWrapper&& other) {
Close();
file_ = other.file_;
other.file_ = nullptr;
return *this;
}
bool FileWrapper::SeekRelative(int64_t offset) {
RTC_DCHECK(file_);
return fseek(file_, rtc::checked_cast<long>(offset), SEEK_CUR) == 0;
}
bool FileWrapper::SeekTo(int64_t position) {
RTC_DCHECK(file_);
return fseek(file_, rtc::checked_cast<long>(position), SEEK_SET) == 0;
}
bool FileWrapper::Flush() {
RTC_DCHECK(file_);
return fflush(file_) == 0;
}
size_t FileWrapper::Read(void* buf, size_t length) {
RTC_DCHECK(file_);
return fread(buf, 1, length, file_);
}
bool FileWrapper::ReadEof() const {
RTC_DCHECK(file_);
return feof(file_);
}
bool FileWrapper::Write(const void* buf, size_t length) {
RTC_DCHECK(file_);
return fwrite(buf, 1, length, file_) == length;
}
bool FileWrapper::Close() {
if (file_ == nullptr)
return true;
bool success = fclose(file_) == 0;
file_ = nullptr;
return success;
}
FILE* FileWrapper::Release() {
FILE* file = file_;
file_ = nullptr;
return file;
}
} // namespace webrtc

View File

@ -0,0 +1,109 @@
/*
* 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_SYSTEM_FILE_WRAPPER_H_
#define RTC_BASE_SYSTEM_FILE_WRAPPER_H_
#include <stddef.h>
#include <stdio.h>
#include <string>
// Implementation that can read (exclusive) or write from/to a file.
namespace webrtc {
// This class is a thin wrapper around FILE*. It's main features are that it
// owns the FILE*, calling fclose on destruction, and that on windows, file
// names passed to the open methods are always treated as utf-8, regardless of
// system code page.
// Most of the methods return only a success/fail indication. When needed, an
// optional argument |int* error| should be added to all methods, in the same
// way as for the OpenWriteOnly methods.
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|.
// 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,
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.
explicit FileWrapper(FILE* file) : file_(file) {}
~FileWrapper() { Close(); }
// Copying is not supported.
FileWrapper(const FileWrapper&) = delete;
FileWrapper& operator=(const FileWrapper&) = delete;
// Support for move semantics.
FileWrapper(FileWrapper&&);
FileWrapper& operator=(FileWrapper&&);
// Returns true if a file has been opened. If the file is not open, no methods
// but is_open and Close may be called.
bool is_open() const { return file_ != nullptr; }
// Closes the file, and implies Flush. Returns true on success, false if
// writing buffered data fails. On failure, the file is nevertheless closed.
// Calling Close on an already closed file does nothing and returns success.
bool Close();
// Releases and returns the wrapped file without closing it. This call passes
// the ownership of the file to the caller, and the wrapper is no longer
// responsible for closing it. Similarly the previously wrapped file is no
// longer available for the wrapper to use in any aspect.
FILE* Release();
// Write any buffered data to the underlying file. Returns true on success,
// false on write error. Note: Flushing when closing, is not required.
bool Flush();
// Seeks to the beginning of file. Returns true on success, false on failure,
// e.g., if the underlying file isn't seekable.
bool Rewind() { return SeekTo(0); }
// TODO(nisse): The seek functions are used only by the WavReader. If that
// code is demoted to test code, seek functions can be deleted from this
// utility.
// Seek relative to current file position.
bool SeekRelative(int64_t offset);
// Seek to given position.
bool SeekTo(int64_t position);
// Returns number of bytes read. Short count indicates EOF or error.
size_t Read(void* buf, size_t length);
// If the most recent Read() returned a short count, this methods returns true
// if the short count was due to EOF, and false it it was due to some i/o
// error.
bool ReadEof() const;
// Returns true if all data was successfully written (or buffered), or false
// if there was an error. Writing buffered data can fail later, and is
// reported with return value from Flush or Close.
bool Write(const void* buf, size_t length);
private:
FILE* file_ = nullptr;
};
} // namespace webrtc
#endif // RTC_BASE_SYSTEM_FILE_WRAPPER_H_

View File

@ -0,0 +1,29 @@
/*
* 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.
*/
#ifndef RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
#define RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
#ifdef __clang__
#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wframe-larger-than=\"")
#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("clang diagnostic pop")
#elif __GNUC__
#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wframe-larger-than=\"")
#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("GCC diagnostic pop")
#else
#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
#define RTC_POP_IGNORING_WFRAME_LARGER_THAN()
#endif
#endif // RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_

View File

@ -0,0 +1,31 @@
/*
* 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.
*/
#ifndef RTC_BASE_SYSTEM_INLINE_H_
#define RTC_BASE_SYSTEM_INLINE_H_
#if defined(_MSC_VER)
#define RTC_FORCE_INLINE __forceinline
#define RTC_NO_INLINE __declspec(noinline)
#elif defined(__GNUC__)
#define RTC_FORCE_INLINE __attribute__((__always_inline__))
#define RTC_NO_INLINE __attribute__((__noinline__))
#else
#define RTC_FORCE_INLINE
#define RTC_NO_INLINE
#endif
#endif // RTC_BASE_SYSTEM_INLINE_H_

View File

@ -0,0 +1,43 @@
/*
* 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.
*/
#ifndef RTC_BASE_SYSTEM_RTC_EXPORT_H_
#define RTC_BASE_SYSTEM_RTC_EXPORT_H_
// RTC_EXPORT is used to mark symbols as exported or imported when WebRTC is
// built or used as a shared library.
// When WebRTC is built as a static library the RTC_EXPORT macro expands to
// nothing.
#ifdef WEBRTC_ENABLE_SYMBOL_EXPORT
#ifdef WEBRTC_WIN
#ifdef WEBRTC_LIBRARY_IMPL
#define RTC_EXPORT __declspec(dllexport)
#else
#define RTC_EXPORT __declspec(dllimport)
#endif
#else // WEBRTC_WIN
#if __has_attribute(visibility) && defined(WEBRTC_LIBRARY_IMPL)
#define RTC_EXPORT __attribute__((visibility("default")))
#endif
#endif // WEBRTC_WIN
#endif // WEBRTC_ENABLE_SYMBOL_EXPORT
#ifndef RTC_EXPORT
#define RTC_EXPORT
#endif
#endif // RTC_BASE_SYSTEM_RTC_EXPORT_H_

View File

@ -0,0 +1,39 @@
/*
* 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.
*/
#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_UNUSED(result);
// Note: In most cases it is better to remove the unused variable rather than
// suppressing the compiler warning.
#ifndef RTC_UNUSED
#define RTC_UNUSED(x) static_cast<void>(x)
#endif // RTC_UNUSED
#endif // RTC_BASE_SYSTEM_UNUSED_H_

View File

@ -0,0 +1,24 @@
/*
* 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_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_
#define RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_
namespace webrtc {
#if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
void WarnThatTheCurrentThreadIsProbablyDeadlocked();
#else
inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {}
#endif
} // namespace webrtc
#endif // RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_

View File

@ -0,0 +1,95 @@
//
// Copyright (c) 2013 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
// https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h
// but adapted for clang attributes instead of the gcc.
//
// This header file contains the macro definitions for thread safety
// annotations that allow the developers to document the locking policies
// of their multi-threaded code. The annotations can also help program
// analysis tools to identify potential thread safety issues.
#ifndef RTC_BASE_THREAD_ANNOTATIONS_H_
#define RTC_BASE_THREAD_ANNOTATIONS_H_
#if defined(__clang__) && (!defined(SWIG))
#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
// Document if a shared variable/field needs to be protected by a lock.
// GUARDED_BY allows the user to specify a particular lock that should be
// held when accessing the annotated variable.
#define RTC_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
// Document if the memory location pointed to by a pointer should be guarded
// by a lock when dereferencing the pointer. Note that a pointer variable to a
// shared memory location could itself be a shared variable. For example, if a
// shared global pointer q, which is guarded by mu1, points to a shared memory
// location that is guarded by mu2, q should be annotated as follows:
// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
#define RTC_PT_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
// Document the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
// and ACQUIRED_BEFORE.)
#define RTC_ACQUIRED_AFTER(x) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x))
#define RTC_ACQUIRED_BEFORE(x) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x))
// The following three annotations document the lock requirements for
// functions/methods.
// Document if a function expects certain locks to be held before it is called
#define RTC_EXCLUSIVE_LOCKS_REQUIRED(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
#define RTC_SHARED_LOCKS_REQUIRED(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
// Document the locks acquired in the body of the function. These locks
// cannot be held when calling this function (as google3's Mutex locks are
// non-reentrant).
#define RTC_LOCKS_EXCLUDED(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
// Document the lock the annotated function returns without acquiring it.
#define RTC_LOCK_RETURNED(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
// Document if a class/type is a lockable type (such as the Mutex class).
#define RTC_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
// Document if a class is a scoped lockable type (such as the MutexLock class).
#define RTC_SCOPED_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
// The following annotations specify lock and unlock primitives.
#define RTC_EXCLUSIVE_LOCK_FUNCTION(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
#define RTC_SHARED_LOCK_FUNCTION(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
#define RTC_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
#define RTC_SHARED_TRYLOCK_FUNCTION(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
#define RTC_UNLOCK_FUNCTION(...) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__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)
#endif // RTC_BASE_THREAD_ANNOTATIONS_H_

View File

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

View File

@ -0,0 +1,327 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdint.h>
#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/time_utils.h"
namespace rtc {
ClockInterface* g_clock = nullptr;
ClockInterface* SetClockForTesting(ClockInterface* clock) {
ClockInterface* prev = g_clock;
g_clock = clock;
return prev;
}
ClockInterface* GetClockForTesting() {
return g_clock;
}
#if defined(WINUWP)
namespace {
class TimeHelper final {
public:
TimeHelper(const TimeHelper&) = delete;
// Resets the clock based upon an NTP server. This routine must be called
// prior to the main system start-up to ensure all clocks are based upon
// an NTP server time if NTP synchronization is required. No critical
// section is used thus this method must be called prior to any clock
// routines being used.
static void SyncWithNtp(int64_t ntp_server_time_ms) {
auto& singleton = Singleton();
TIME_ZONE_INFORMATION time_zone;
GetTimeZoneInformation(&time_zone);
int64_t time_zone_bias_ns =
rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
singleton.app_start_time_ns_ =
(ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 -
time_zone_bias_ns;
singleton.UpdateReferenceTime();
}
// Returns the number of nanoseconds that have passed since unix epoch.
static int64_t TicksNs() {
auto& singleton = Singleton();
int64_t result = 0;
LARGE_INTEGER qpcnt;
QueryPerformanceCounter(&qpcnt);
result = rtc::dchecked_cast<int64_t>(
(rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
rtc::dchecked_cast<uint64_t>(singleton.os_ticks_per_second_)) *
10000);
result = singleton.app_start_time_ns_ + result -
singleton.time_since_os_start_ns_;
return result;
}
private:
TimeHelper() {
TIME_ZONE_INFORMATION time_zone;
GetTimeZoneInformation(&time_zone);
int64_t time_zone_bias_ns =
rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
FILETIME ft;
// This will give us system file in UTC format.
GetSystemTimeAsFileTime(&ft);
LARGE_INTEGER li;
li.HighPart = ft.dwHighDateTime;
li.LowPart = ft.dwLowDateTime;
app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 -
time_zone_bias_ns;
UpdateReferenceTime();
}
static TimeHelper& Singleton() {
static TimeHelper singleton;
return singleton;
}
void UpdateReferenceTime() {
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
os_ticks_per_second_ = rtc::dchecked_cast<int64_t>(qpfreq.QuadPart);
LARGE_INTEGER qpcnt;
QueryPerformanceCounter(&qpcnt);
time_since_os_start_ns_ = rtc::dchecked_cast<int64_t>(
(rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
rtc::dchecked_cast<uint64_t>(os_ticks_per_second_)) *
10000);
}
private:
static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
116444736000000000ULL;
static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L;
// The number of nanoseconds since unix system epoch
int64_t app_start_time_ns_;
// The number of nanoseconds since the OS started
int64_t time_since_os_start_ns_;
// The OS calculated ticks per second
int64_t os_ticks_per_second_;
};
} // namespace
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 SystemTimeMillis() {
return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec);
}
int64_t TimeNanos() {
if (g_clock) {
return g_clock->TimeNanos();
}
return SystemTimeNanos();
}
uint32_t Time32() {
return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec);
}
int64_t TimeMillis() {
return TimeNanos() / kNumNanosecsPerMillisec;
}
int64_t TimeMicros() {
return TimeNanos() / kNumNanosecsPerMicrosec;
}
int64_t TimeAfter(int64_t elapsed) {
RTC_DCHECK_GE(elapsed, 0);
return TimeMillis() + elapsed;
}
int32_t TimeDiff32(uint32_t later, uint32_t earlier) {
return later - earlier;
}
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,
181, 212, 243, 273, 304, 334};
int year = tm.tm_year + 1900;
int month = tm.tm_mon;
int day = tm.tm_mday - 1; // Make 0-based like the rest.
int hour = tm.tm_hour;
int min = tm.tm_min;
int sec = tm.tm_sec;
bool expiry_in_leap_year =
(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
if (year < 1970)
return -1;
if (month < 0 || month > 11)
return -1;
if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
return -1;
if (hour < 0 || hour > 23)
return -1;
if (min < 0 || min > 59)
return -1;
if (sec < 0 || sec > 59)
return -1;
day += cumul_mdays[month];
// Add number of leap days between 1970 and the expiration year, inclusive.
day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) +
(year / 400 - 1970 / 400));
// 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.
day -= 1;
// 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 +
sec;
}
int64_t TimeUTCMicros() {
if (g_clock) {
return g_clock->TimeNanos() / kNumNanosecsPerMicrosec;
}
#if defined(WEBRTC_POSIX)
struct timeval time;
gettimeofday(&time, nullptr);
// 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);
#endif
}
int64_t TimeUTCMillis() {
return TimeUTCMicros() / kNumMicrosecsPerMillisec;
}
} // namespace rtc

View File

@ -0,0 +1,139 @@
/*
* Copyright 2005 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_TIME_UTILS_H_
#define RTC_BASE_TIME_UTILS_H_
#include <stdint.h>
#include <time.h>
#include "rtc_base/checks.h"
#include "rtc_base/system/rtc_export.h"
namespace rtc {
static const int64_t kNumMillisecsPerSec = INT64_C(1000);
static const int64_t kNumMicrosecsPerSec = INT64_C(1000000);
static const int64_t kNumNanosecsPerSec = INT64_C(1000000000);
static const int64_t kNumMicrosecsPerMillisec =
kNumMicrosecsPerSec / kNumMillisecsPerSec;
static const int64_t kNumNanosecsPerMillisec =
kNumNanosecsPerSec / kNumMillisecsPerSec;
static const int64_t kNumNanosecsPerMicrosec =
kNumNanosecsPerSec / kNumMicrosecsPerSec;
// TODO(honghaiz): Define a type for the time value specifically.
class ClockInterface {
public:
virtual ~ClockInterface() {}
virtual int64_t TimeNanos() const = 0;
};
// Sets the global source of time. This is useful mainly for unit tests.
//
// Returns the previously set ClockInterface, or nullptr if none is set.
//
// Does not transfer ownership of the clock. SetClockForTesting(nullptr)
// should be called before the ClockInterface is deleted.
//
// This method is not thread-safe; it should only be used when no other thread
// is running (for example, at the start/end of a unit test, or start/end of
// main()).
//
// TODO(deadbeef): Instead of having functions that access this global
// ClockInterface, we may want to pass the ClockInterface into everything
// that uses it, eliminating the need for a global variable and this function.
RTC_EXPORT ClockInterface* SetClockForTesting(ClockInterface* clock);
// Returns previously set clock, or nullptr if no custom clock is being used.
RTC_EXPORT ClockInterface* GetClockForTesting();
#if defined(WINUWP)
// Synchronizes the current clock based upon an NTP server's epoch in
// milliseconds.
void SyncWithNtp(int64_t time_from_ntp_server_ms);
#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.
uint32_t Time32();
// Returns the current time in milliseconds in 64 bits.
RTC_EXPORT int64_t TimeMillis();
// Deprecated. Do not use this in any new code.
inline int64_t Time() {
return TimeMillis();
}
// Returns the current time in microseconds.
RTC_EXPORT int64_t TimeMicros();
// Returns the current time in nanoseconds.
RTC_EXPORT int64_t TimeNanos();
// Returns a future timestamp, 'elapsed' milliseconds from now.
int64_t TimeAfter(int64_t elapsed);
// Number of milliseconds that would elapse between 'earlier' and 'later'
// timestamps. The value is negative if 'later' occurs before 'earlier'.
int64_t TimeDiff(int64_t later, int64_t earlier);
int32_t TimeDiff32(uint32_t later, uint32_t earlier);
// The number of milliseconds that have elapsed since 'earlier'.
inline int64_t TimeSince(int64_t earlier) {
return TimeMillis() - earlier;
}
// The number of milliseconds that will elapse between now and 'later'.
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.
int64_t TmToSeconds(const tm& tm);
// Return the number of microseconds since January 1, 1970, UTC.
// Useful mainly when producing logs to be correlated with other
// devices, and when the devices in question all have properly
// synchronized clocks.
//
// Note that this function obeys the system's idea about what the time
// is. It is not guaranteed to be monotonic; it will jump in case the
// system time is changed, e.g., by some other process calling
// settimeofday. Always use rtc::TimeMicros(), not this function, for
// measuring time intervals and timeouts.
int64_t TimeUTCMicros();
// Return the number of milliseconds since January 1, 1970, UTC.
// See above.
int64_t TimeUTCMillis();
} // namespace rtc
#endif // RTC_BASE_TIME_UTILS_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,140 @@
/*
* Copyright 2016 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_TYPE_TRAITS_H_
#define RTC_BASE_TYPE_TRAITS_H_
#include <cstddef>
#include <type_traits>
namespace rtc {
// Determines if the given class has zero-argument .data() and .size() methods
// whose return values are convertible to T* and size_t, respectively.
template <typename DS, typename T>
class HasDataAndSize {
private:
template <
typename C,
typename std::enable_if<
std::is_convertible<decltype(std::declval<C>().data()), T*>::value &&
std::is_convertible<decltype(std::declval<C>().size()),
std::size_t>::value>::type* = nullptr>
static int Test(int);
template <typename>
static char Test(...);
public:
static constexpr bool value = std::is_same<decltype(Test<DS>(0)), int>::value;
};
namespace test_has_data_and_size {
template <typename DR, typename SR>
struct Test1 {
DR data();
SR size();
};
static_assert(HasDataAndSize<Test1<int*, int>, int>::value, "");
static_assert(HasDataAndSize<Test1<int*, int>, const int>::value, "");
static_assert(HasDataAndSize<Test1<const int*, int>, const int>::value, "");
static_assert(!HasDataAndSize<Test1<const int*, int>, int>::value,
"implicit cast of const int* to int*");
static_assert(!HasDataAndSize<Test1<char*, size_t>, int>::value,
"implicit cast of char* to int*");
struct Test2 {
int* data;
size_t size;
};
static_assert(!HasDataAndSize<Test2, int>::value,
".data and .size aren't functions");
struct Test3 {
int* data();
};
static_assert(!HasDataAndSize<Test3, int>::value, ".size() is missing");
class Test4 {
int* data();
size_t size();
};
static_assert(!HasDataAndSize<Test4, int>::value,
".data() and .size() are private");
} // namespace test_has_data_and_size
namespace type_traits_impl {
// Determines if the given type is an enum that converts implicitly to
// an integral type.
template <typename T>
struct IsIntEnum {
private:
// This overload is used if the type is an enum, and unary plus
// compiles and turns it into an integral type.
template <typename X,
typename std::enable_if<
std::is_enum<X>::value &&
std::is_integral<decltype(+std::declval<X>())>::value>::type* =
nullptr>
static int Test(int);
// Otherwise, this overload is used.
template <typename>
static char Test(...);
public:
static constexpr bool value =
std::is_same<decltype(Test<typename std::remove_reference<T>::type>(0)),
int>::value;
};
} // namespace type_traits_impl
// Determines if the given type is integral, or an enum that
// converts implicitly to an integral type.
template <typename T>
struct IsIntlike {
private:
using X = typename std::remove_reference<T>::type;
public:
static constexpr bool value =
std::is_integral<X>::value || type_traits_impl::IsIntEnum<X>::value;
};
namespace test_enum_intlike {
enum E1 { e1 };
enum { e2 };
enum class E3 { e3 };
struct S {};
static_assert(type_traits_impl::IsIntEnum<E1>::value, "");
static_assert(type_traits_impl::IsIntEnum<decltype(e2)>::value, "");
static_assert(!type_traits_impl::IsIntEnum<E3>::value, "");
static_assert(!type_traits_impl::IsIntEnum<int>::value, "");
static_assert(!type_traits_impl::IsIntEnum<float>::value, "");
static_assert(!type_traits_impl::IsIntEnum<S>::value, "");
static_assert(IsIntlike<E1>::value, "");
static_assert(IsIntlike<decltype(e2)>::value, "");
static_assert(!IsIntlike<E3>::value, "");
static_assert(IsIntlike<int>::value, "");
static_assert(!IsIntlike<float>::value, "");
static_assert(!IsIntlike<S>::value, "");
} // namespace test_enum_intlike
} // namespace rtc
#endif // RTC_BASE_TYPE_TRAITS_H_

View File

@ -0,0 +1,33 @@
# 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")
rtc_source_set("unit_base") {
visibility = [
"../../api/units:*",
":*",
]
sources = [ "unit_base.h" ]
deps = [
"../../rtc_base:checks",
"../../rtc_base:safe_conversions",
]
}
if (rtc_include_tests) {
rtc_library("units_unittests") {
testonly = true
sources = [ "unit_base_unittest.cc" ]
deps = [
":unit_base",
"../../test:test_support",
]
}
}

View File

@ -0,0 +1,306 @@
/*
* Copyright 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.
*/
#ifndef RTC_BASE_UNITS_UNIT_BASE_H_
#define RTC_BASE_UNITS_UNIT_BASE_H_
#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <limits>
#include <type_traits>
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
namespace rtc_units_impl {
// UnitBase is a base class for implementing custom value types with a specific
// unit. It provides type safety and commonly useful operations. The underlying
// storage is always an int64_t, it's up to the unit implementation to choose
// what scale it represents.
//
// It's used like:
// class MyUnit: public UnitBase<MyUnit> {...};
//
// Unit_T is the subclass representing the specific unit.
template <class Unit_T>
class UnitBase {
public:
UnitBase() = delete;
static constexpr Unit_T Zero() { return Unit_T(0); }
static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); }
static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); }
constexpr bool IsZero() const { return value_ == 0; }
constexpr bool IsFinite() const { return !IsInfinite(); }
constexpr bool IsInfinite() const {
return value_ == PlusInfinityVal() || value_ == MinusInfinityVal();
}
constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); }
constexpr bool IsMinusInfinity() const {
return value_ == MinusInfinityVal();
}
constexpr bool operator==(const Unit_T& other) const {
return value_ == other.value_;
}
constexpr bool operator!=(const Unit_T& other) const {
return value_ != other.value_;
}
constexpr bool operator<=(const Unit_T& other) const {
return value_ <= other.value_;
}
constexpr bool operator>=(const Unit_T& other) const {
return value_ >= other.value_;
}
constexpr bool operator>(const Unit_T& other) const {
return value_ > other.value_;
}
constexpr bool operator<(const Unit_T& other) const {
return value_ < other.value_;
}
constexpr Unit_T RoundTo(const Unit_T& resolution) const {
RTC_DCHECK(IsFinite());
RTC_DCHECK(resolution.IsFinite());
RTC_DCHECK_GT(resolution.value_, 0);
return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) *
resolution.value_;
}
constexpr Unit_T RoundUpTo(const Unit_T& resolution) const {
RTC_DCHECK(IsFinite());
RTC_DCHECK(resolution.IsFinite());
RTC_DCHECK_GT(resolution.value_, 0);
return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) *
resolution.value_;
}
constexpr Unit_T RoundDownTo(const Unit_T& resolution) const {
RTC_DCHECK(IsFinite());
RTC_DCHECK(resolution.IsFinite());
RTC_DCHECK_GT(resolution.value_, 0);
return Unit_T(value_ / resolution.value_) * resolution.value_;
}
protected:
template <
typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
static constexpr Unit_T FromValue(T value) {
if (Unit_T::one_sided)
RTC_DCHECK_GE(value, 0);
RTC_DCHECK_GT(value, MinusInfinityVal());
RTC_DCHECK_LT(value, PlusInfinityVal());
return Unit_T(rtc::dchecked_cast<int64_t>(value));
}
template <typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type* =
nullptr>
static constexpr Unit_T FromValue(T value) {
if (value == std::numeric_limits<T>::infinity()) {
return PlusInfinity();
} else if (value == -std::numeric_limits<T>::infinity()) {
return MinusInfinity();
} else {
RTC_DCHECK(!std::isnan(value));
return FromValue(rtc::dchecked_cast<int64_t>(value));
}
}
template <
typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
static constexpr Unit_T FromFraction(int64_t denominator, T value) {
if (Unit_T::one_sided)
RTC_DCHECK_GE(value, 0);
RTC_DCHECK_GT(value, MinusInfinityVal() / denominator);
RTC_DCHECK_LT(value, PlusInfinityVal() / denominator);
return Unit_T(rtc::dchecked_cast<int64_t>(value * denominator));
}
template <typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type* =
nullptr>
static constexpr Unit_T FromFraction(int64_t denominator, T value) {
return FromValue(value * denominator);
}
template <typename T = int64_t>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
ToValue() const {
RTC_DCHECK(IsFinite());
return rtc::dchecked_cast<T>(value_);
}
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_;
}
template <typename T>
constexpr T ToValueOr(T fallback_value) const {
return IsFinite() ? value_ : fallback_value;
}
template <int64_t Denominator, typename T = int64_t>
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));
}
}
template <int64_t Denominator, typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
ToFraction() const {
return ToValue<T>() * (1 / static_cast<T>(Denominator));
}
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)
: fallback_value;
}
template <int64_t Factor, typename T = int64_t>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
ToMultiple() const {
RTC_DCHECK_GE(ToValue(), std::numeric_limits<T>::min() / Factor);
RTC_DCHECK_LE(ToValue(), std::numeric_limits<T>::max() / Factor);
return rtc::dchecked_cast<T>(ToValue() * Factor);
}
template <int64_t Factor, typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
ToMultiple() const {
return ToValue<T>() * Factor;
}
explicit constexpr UnitBase(int64_t value) : value_(value) {}
private:
template <class RelativeUnit_T>
friend class RelativeUnit;
static inline constexpr int64_t PlusInfinityVal() {
return std::numeric_limits<int64_t>::max();
}
static inline constexpr int64_t MinusInfinityVal() {
return std::numeric_limits<int64_t>::min();
}
constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); }
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_;
};
// Extends UnitBase to provide operations for relative units, that is, units
// that have a meaningful relation between values such that a += b is a
// sensible thing to do. For a,b <- same unit.
template <class Unit_T>
class RelativeUnit : public UnitBase<Unit_T> {
public:
constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const {
return std::max(min_value,
std::min(UnitBase<Unit_T>::AsSubClassRef(), max_value));
}
constexpr void Clamp(Unit_T min_value, Unit_T max_value) {
*this = Clamped(min_value, max_value);
}
constexpr Unit_T operator+(const Unit_T other) const {
if (this->IsPlusInfinity() || other.IsPlusInfinity()) {
RTC_DCHECK(!this->IsMinusInfinity());
RTC_DCHECK(!other.IsMinusInfinity());
return this->PlusInfinity();
} else if (this->IsMinusInfinity() || other.IsMinusInfinity()) {
RTC_DCHECK(!this->IsPlusInfinity());
RTC_DCHECK(!other.IsPlusInfinity());
return this->MinusInfinity();
}
return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue());
}
constexpr Unit_T operator-(const Unit_T other) const {
if (this->IsPlusInfinity() || other.IsMinusInfinity()) {
RTC_DCHECK(!this->IsMinusInfinity());
RTC_DCHECK(!other.IsPlusInfinity());
return this->PlusInfinity();
} else if (this->IsMinusInfinity() || other.IsPlusInfinity()) {
RTC_DCHECK(!this->IsPlusInfinity());
RTC_DCHECK(!other.IsMinusInfinity());
return this->MinusInfinity();
}
return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue());
}
constexpr Unit_T& operator+=(const Unit_T other) {
*this = *this + other;
return this->AsSubClassRef();
}
constexpr Unit_T& operator-=(const Unit_T other) {
*this = *this - other;
return this->AsSubClassRef();
}
constexpr double operator/(const Unit_T other) const {
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));
}
constexpr Unit_T operator*(double scalar) const {
return UnitBase<Unit_T>::FromValue(std::round(this->ToValue() * scalar));
}
constexpr Unit_T operator*(int64_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
constexpr Unit_T operator*(int32_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
protected:
using UnitBase<Unit_T>::UnitBase;
};
template <class Unit_T>
inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
} // namespace rtc_units_impl
} // namespace webrtc
#endif // RTC_BASE_UNITS_UNIT_BASE_H_

104
webrtc/rtc_base/win32.h Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_WIN32_H_
#define RTC_BASE_WIN32_H_
#ifndef WEBRTC_WIN
#error "Only #include this header in Windows builds"
#endif
// Make sure we don't get min/max macros
#ifndef NOMINMAX
#define NOMINMAX
#endif
// clang-format off
// clang formating would change include order.
#include <winsock2.h> // must come first
#include <windows.h>
// clang-format on
typedef int socklen_t;
#ifndef SECURITY_MANDATORY_LABEL_AUTHORITY
// Add defines that we use if we are compiling against older sdks
#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
#define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(0x19)
typedef struct _TOKEN_MANDATORY_LABEL {
SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
#endif // SECURITY_MANDATORY_LABEL_AUTHORITY
#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_

View File

@ -0,0 +1,38 @@
/*
* Copyright 2017 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 defined(WEBRTC_WIN)
#include <windows.h>
#else
#include <string.h>
#endif
#include "rtc_base/checks.h"
#include "rtc_base/zero_memory.h"
namespace rtc {
// Code and comment taken from "OPENSSL_cleanse" of BoringSSL.
void ExplicitZeroMemory(void* ptr, size_t len) {
RTC_DCHECK(ptr || !len);
#if defined(WEBRTC_WIN)
SecureZeroMemory(ptr, len);
#else
memset(ptr, 0, len);
#if !defined(__pnacl__)
/* As best as we can tell, this is sufficient to break any optimisations that
might try to eliminate "superfluous" memsets. If there's an easy way to
detect memset_s, it would be better to use that. */
__asm__ __volatile__("" : : "r"(ptr) : "memory"); // NOLINT
#endif
#endif // !WEBRTC_WIN
}
} // namespace rtc

View File

@ -0,0 +1,35 @@
/*
* Copyright 2017 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_ZERO_MEMORY_H_
#define RTC_BASE_ZERO_MEMORY_H_
#include <stddef.h>
#include <type_traits>
#include "api/array_view.h"
namespace rtc {
// Fill memory with zeros in a way that the compiler doesn't optimize it away
// even if the pointer is not used afterwards.
void ExplicitZeroMemory(void* ptr, size_t len);
template <typename T,
typename std::enable_if<!std::is_const<T>::value &&
std::is_trivial<T>::value>::type* = nullptr>
void ExplicitZeroMemory(rtc::ArrayView<T> a) {
ExplicitZeroMemory(a.data(), a.size());
}
} // namespace rtc
#endif // RTC_BASE_ZERO_MEMORY_H_