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:
1482
webrtc/rtc_base/BUILD.gn
Normal file
1482
webrtc/rtc_base/BUILD.gn
Normal file
File diff suppressed because it is too large
Load Diff
32
webrtc/rtc_base/arraysize.h
Normal file
32
webrtc/rtc_base/arraysize.h
Normal 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_
|
79
webrtc/rtc_base/atomic_ops.h
Normal file
79
webrtc/rtc_base/atomic_ops.h
Normal 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
437
webrtc/rtc_base/buffer.h
Normal 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
207
webrtc/rtc_base/checks.cc
Normal 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
485
webrtc/rtc_base/checks.h
Normal 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_
|
25
webrtc/rtc_base/compile_assert_c.h
Normal file
25
webrtc/rtc_base/compile_assert_c.h
Normal 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_
|
20
webrtc/rtc_base/constructor_magic.h
Normal file
20
webrtc/rtc_base/constructor_magic.h
Normal 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_
|
45
webrtc/rtc_base/deprecation.h
Normal file
45
webrtc/rtc_base/deprecation.h
Normal 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
203
webrtc/rtc_base/event.cc
Normal 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
86
webrtc/rtc_base/event.h
Normal 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_
|
412
webrtc/rtc_base/event_tracer.cc
Normal file
412
webrtc/rtc_base/event_tracer.cc
Normal 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
|
82
webrtc/rtc_base/event_tracer.h
Normal file
82
webrtc/rtc_base/event_tracer.h
Normal 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_
|
247
webrtc/rtc_base/experiments/field_trial_parser.cc
Normal file
247
webrtc/rtc_base/experiments/field_trial_parser.cc
Normal 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
|
288
webrtc/rtc_base/experiments/field_trial_parser.h
Normal file
288
webrtc/rtc_base/experiments/field_trial_parser.h
Normal 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_
|
38
webrtc/rtc_base/gtest_prod_util.h
Normal file
38
webrtc/rtc_base/gtest_prod_util.h
Normal 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_
|
33
webrtc/rtc_base/ignore_wundef.h
Normal file
33
webrtc/rtc_base/ignore_wundef.h
Normal 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
562
webrtc/rtc_base/logging.cc
Normal 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
712
webrtc/rtc_base/logging.h
Normal 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_
|
56
webrtc/rtc_base/memory/BUILD.gn
Normal file
56
webrtc/rtc_base/memory/BUILD.gn
Normal 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",
|
||||
]
|
||||
}
|
98
webrtc/rtc_base/memory/aligned_malloc.cc
Normal file
98
webrtc/rtc_base/memory/aligned_malloc.cc
Normal 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
|
57
webrtc/rtc_base/memory/aligned_malloc.h
Normal file
57
webrtc/rtc_base/memory/aligned_malloc.h
Normal 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_
|
64
webrtc/rtc_base/meson.build
Normal file
64
webrtc/rtc_base/meson.build
Normal 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
|
||||
)
|
||||
|
176
webrtc/rtc_base/numerics/safe_compare.h
Normal file
176
webrtc/rtc_base/numerics/safe_compare.h
Normal 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_
|
76
webrtc/rtc_base/numerics/safe_conversions.h
Normal file
76
webrtc/rtc_base/numerics/safe_conversions.h
Normal 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_
|
177
webrtc/rtc_base/numerics/safe_conversions_impl.h
Normal file
177
webrtc/rtc_base/numerics/safe_conversions_impl.h
Normal 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_
|
335
webrtc/rtc_base/numerics/safe_minmax.h
Normal file
335
webrtc/rtc_base/numerics/safe_minmax.h
Normal 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_
|
192
webrtc/rtc_base/platform_thread.cc
Normal file
192
webrtc/rtc_base/platform_thread.cc
Normal 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, ¶m) == 0;
|
||||
#endif // defined(WEBRTC_WIN)
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) {
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
RTC_DCHECK(IsRunning());
|
||||
|
||||
return QueueUserAPC(function, thread_, data) != FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace rtc
|
104
webrtc/rtc_base/platform_thread.h
Normal file
104
webrtc/rtc_base/platform_thread.h
Normal 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_
|
115
webrtc/rtc_base/platform_thread_types.cc
Normal file
115
webrtc/rtc_base/platform_thread_types.cc
Normal 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
|
62
webrtc/rtc_base/platform_thread_types.h
Normal file
62
webrtc/rtc_base/platform_thread_types.h
Normal 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_
|
54
webrtc/rtc_base/race_checker.cc
Normal file
54
webrtc/rtc_base/race_checker.cc
Normal 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
|
78
webrtc/rtc_base/race_checker.h
Normal file
78
webrtc/rtc_base/race_checker.h
Normal 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_
|
67
webrtc/rtc_base/ref_count.h
Normal file
67
webrtc/rtc_base/ref_count.h
Normal 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_
|
64
webrtc/rtc_base/ref_counted_object.h
Normal file
64
webrtc/rtc_base/ref_counted_object.h
Normal 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_
|
75
webrtc/rtc_base/ref_counter.h
Normal file
75
webrtc/rtc_base/ref_counter.h
Normal 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
144
webrtc/rtc_base/sanitizer.h
Normal 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_
|
387
webrtc/rtc_base/string_encode.cc
Normal file
387
webrtc/rtc_base/string_encode.cc
Normal 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
|
154
webrtc/rtc_base/string_encode.h
Normal file
154
webrtc/rtc_base/string_encode.h
Normal 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__
|
90
webrtc/rtc_base/string_to_number.cc
Normal file
90
webrtc/rtc_base/string_to_number.cc
Normal 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
|
116
webrtc/rtc_base/string_to_number.h
Normal file
116
webrtc/rtc_base/string_to_number.h
Normal 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_
|
53
webrtc/rtc_base/string_utils.cc
Normal file
53
webrtc/rtc_base/string_utils.cc
Normal 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
|
93
webrtc/rtc_base/string_utils.h
Normal file
93
webrtc/rtc_base/string_utils.h
Normal 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_
|
141
webrtc/rtc_base/strings/string_builder.cc
Normal file
141
webrtc/rtc_base/strings/string_builder.cc
Normal 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
|
175
webrtc/rtc_base/strings/string_builder.h
Normal file
175
webrtc/rtc_base/strings/string_builder.h
Normal 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_
|
249
webrtc/rtc_base/swap_queue.h
Normal file
249
webrtc/rtc_base/swap_queue.h
Normal 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_
|
138
webrtc/rtc_base/synchronization/BUILD.gn
Normal file
138
webrtc/rtc_base/synchronization/BUILD.gn
Normal 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",
|
||||
]
|
||||
}
|
||||
}
|
39
webrtc/rtc_base/synchronization/mutex.cc
Normal file
39
webrtc/rtc_base/synchronization/mutex.cc
Normal 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
|
108
webrtc/rtc_base/synchronization/mutex.h
Normal file
108
webrtc/rtc_base/synchronization/mutex.h
Normal 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_
|
54
webrtc/rtc_base/synchronization/mutex_critical_section.h
Normal file
54
webrtc/rtc_base/synchronization/mutex_critical_section.h
Normal 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_
|
53
webrtc/rtc_base/synchronization/mutex_pthread.h
Normal file
53
webrtc/rtc_base/synchronization/mutex_pthread.h
Normal 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_
|
52
webrtc/rtc_base/synchronization/rw_lock_posix.cc
Normal file
52
webrtc/rtc_base/synchronization/rw_lock_posix.cc
Normal 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
|
40
webrtc/rtc_base/synchronization/rw_lock_posix.h
Normal file
40
webrtc/rtc_base/synchronization/rw_lock_posix.h
Normal 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_
|
41
webrtc/rtc_base/synchronization/rw_lock_win.cc
Normal file
41
webrtc/rtc_base/synchronization/rw_lock_win.cc
Normal 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
|
38
webrtc/rtc_base/synchronization/rw_lock_win.h
Normal file
38
webrtc/rtc_base/synchronization/rw_lock_win.h
Normal 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_
|
29
webrtc/rtc_base/synchronization/rw_lock_wrapper.cc
Normal file
29
webrtc/rtc_base/synchronization/rw_lock_wrapper.cc
Normal 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
|
66
webrtc/rtc_base/synchronization/rw_lock_wrapper.h
Normal file
66
webrtc/rtc_base/synchronization/rw_lock_wrapper.h
Normal 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_
|
112
webrtc/rtc_base/synchronization/sequence_checker.cc
Normal file
112
webrtc/rtc_base/synchronization/sequence_checker.cc
Normal 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
|
187
webrtc/rtc_base/synchronization/sequence_checker.h
Normal file
187
webrtc/rtc_base/synchronization/sequence_checker.h
Normal 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_
|
36
webrtc/rtc_base/synchronization/yield.cc
Normal file
36
webrtc/rtc_base/synchronization/yield.cc
Normal 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
|
20
webrtc/rtc_base/synchronization/yield.h
Normal file
20
webrtc/rtc_base/synchronization/yield.h
Normal 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_
|
82
webrtc/rtc_base/synchronization/yield_policy.cc
Normal file
82
webrtc/rtc_base/synchronization/yield_policy.cc
Normal 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
|
38
webrtc/rtc_base/synchronization/yield_policy.h
Normal file
38
webrtc/rtc_base/synchronization/yield_policy.h
Normal 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_
|
61
webrtc/rtc_base/system/arch.h
Normal file
61
webrtc/rtc_base/system/arch.h
Normal 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_
|
72
webrtc/rtc_base/system/asm_defines.h
Normal file
72
webrtc/rtc_base/system/asm_defines.h
Normal 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_
|
127
webrtc/rtc_base/system/file_wrapper.cc
Normal file
127
webrtc/rtc_base/system/file_wrapper.cc
Normal 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
|
109
webrtc/rtc_base/system/file_wrapper.h
Normal file
109
webrtc/rtc_base/system/file_wrapper.h
Normal 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_
|
29
webrtc/rtc_base/system/ignore_warnings.h
Normal file
29
webrtc/rtc_base/system/ignore_warnings.h
Normal 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_
|
31
webrtc/rtc_base/system/inline.h
Normal file
31
webrtc/rtc_base/system/inline.h
Normal 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_
|
43
webrtc/rtc_base/system/rtc_export.h
Normal file
43
webrtc/rtc_base/system/rtc_export.h
Normal 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_
|
39
webrtc/rtc_base/system/unused.h
Normal file
39
webrtc/rtc_base/system/unused.h
Normal 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_
|
24
webrtc/rtc_base/system/warn_current_thread_is_deadlocked.h
Normal file
24
webrtc/rtc_base/system/warn_current_thread_is_deadlocked.h
Normal 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_
|
95
webrtc/rtc_base/thread_annotations.h
Normal file
95
webrtc/rtc_base/thread_annotations.h
Normal 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_
|
27
webrtc/rtc_base/thread_checker.h
Normal file
27
webrtc/rtc_base/thread_checker.h
Normal 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_
|
327
webrtc/rtc_base/time_utils.cc
Normal file
327
webrtc/rtc_base/time_utils.cc
Normal 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
|
139
webrtc/rtc_base/time_utils.h
Normal file
139
webrtc/rtc_base/time_utils.h
Normal 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_
|
1022
webrtc/rtc_base/trace_event.h
Normal file
1022
webrtc/rtc_base/trace_event.h
Normal file
File diff suppressed because it is too large
Load Diff
140
webrtc/rtc_base/type_traits.h
Normal file
140
webrtc/rtc_base/type_traits.h
Normal 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_
|
33
webrtc/rtc_base/units/BUILD.gn
Normal file
33
webrtc/rtc_base/units/BUILD.gn
Normal 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",
|
||||
]
|
||||
}
|
||||
}
|
306
webrtc/rtc_base/units/unit_base.h
Normal file
306
webrtc/rtc_base/units/unit_base.h
Normal 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
104
webrtc/rtc_base/win32.h
Normal 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_
|
38
webrtc/rtc_base/zero_memory.cc
Normal file
38
webrtc/rtc_base/zero_memory.cc
Normal 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
|
35
webrtc/rtc_base/zero_memory.h
Normal file
35
webrtc/rtc_base/zero_memory.h
Normal 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_
|
Reference in New Issue
Block a user