Bump to WebRTC M120 release
Some API deprecation -- ExperimentalAgc and ExperimentalNs are gone. We're continuing to carry iSAC even though it's gone upstream, but maybe we'll want to drop that soon.
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,79 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright 2011 The WebRTC Project Authors. All rights reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_ATOMIC_OPS_H_ | ||||
| #define RTC_BASE_ATOMIC_OPS_H_ | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| // clang-format off | ||||
| // clang formating would change include order. | ||||
|  | ||||
| // Include winsock2.h before including <windows.h> to maintain consistency with | ||||
| // win32.h. To include win32.h directly, it must be broken out into its own | ||||
| // build target. | ||||
| #include <winsock2.h> | ||||
| #include <windows.h> | ||||
| // clang-format on | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
|  | ||||
| namespace rtc { | ||||
| class AtomicOps { | ||||
|  public: | ||||
| #if defined(WEBRTC_WIN) | ||||
|   // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64. | ||||
|   static int Increment(volatile int* i) { | ||||
|     return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i)); | ||||
|   } | ||||
|   static int Decrement(volatile int* i) { | ||||
|     return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i)); | ||||
|   } | ||||
|   static int AcquireLoad(volatile const int* i) { return *i; } | ||||
|   static void ReleaseStore(volatile int* i, int value) { *i = value; } | ||||
|   static int CompareAndSwap(volatile int* i, int old_value, int new_value) { | ||||
|     return ::InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(i), | ||||
|                                         new_value, old_value); | ||||
|   } | ||||
|   // Pointer variants. | ||||
|   template <typename T> | ||||
|   static T* AcquireLoadPtr(T* volatile* ptr) { | ||||
|     return *ptr; | ||||
|   } | ||||
|   template <typename T> | ||||
|   static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) { | ||||
|     return static_cast<T*>(::InterlockedCompareExchangePointer( | ||||
|         reinterpret_cast<PVOID volatile*>(ptr), new_value, old_value)); | ||||
|   } | ||||
| #else | ||||
|   static int Increment(volatile int* i) { return __sync_add_and_fetch(i, 1); } | ||||
|   static int Decrement(volatile int* i) { return __sync_sub_and_fetch(i, 1); } | ||||
|   static int AcquireLoad(volatile const int* i) { | ||||
|     return __atomic_load_n(i, __ATOMIC_ACQUIRE); | ||||
|   } | ||||
|   static void ReleaseStore(volatile int* i, int value) { | ||||
|     __atomic_store_n(i, value, __ATOMIC_RELEASE); | ||||
|   } | ||||
|   static int CompareAndSwap(volatile int* i, int old_value, int new_value) { | ||||
|     return __sync_val_compare_and_swap(i, old_value, new_value); | ||||
|   } | ||||
|   // Pointer variants. | ||||
|   template <typename T> | ||||
|   static T* AcquireLoadPtr(T* volatile* ptr) { | ||||
|     return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); | ||||
|   } | ||||
|   template <typename T> | ||||
|   static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) { | ||||
|     return __sync_val_compare_and_swap(ptr, old_value, new_value); | ||||
|   } | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| }  // namespace rtc | ||||
|  | ||||
| #endif  // RTC_BASE_ATOMIC_OPS_H_ | ||||
| @@ -19,6 +19,7 @@ | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "api/array_view.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/type_traits.h" | ||||
| @@ -105,7 +106,10 @@ class BufferT { | ||||
|                 internal::BufferCompat<T, U>::value>::type* = nullptr> | ||||
|   BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) { | ||||
|     static_assert(sizeof(T) == sizeof(U), ""); | ||||
|     std::memcpy(data_.get(), data, size * sizeof(U)); | ||||
|     if (size > 0) { | ||||
|       RTC_DCHECK(data); | ||||
|       std::memcpy(data_.get(), data, size * sizeof(U)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Construct a buffer from the contents of an array. | ||||
| @@ -117,6 +121,13 @@ class BufferT { | ||||
|  | ||||
|   ~BufferT() { MaybeZeroCompleteBuffer(); } | ||||
|  | ||||
|   // Implicit conversion to absl::string_view if T is compatible with char. | ||||
|   template <typename U = T> | ||||
|   operator typename std::enable_if<internal::BufferCompat<U, char>::value, | ||||
|                                    absl::string_view>::type() const { | ||||
|     return absl::string_view(data<char>(), size()); | ||||
|   } | ||||
|  | ||||
|   // Get a pointer to the data. Just .data() will give you a (const) T*, but if | ||||
|   // T is a byte-sized integer, you may also use .data<U>() for any other | ||||
|   // byte-sized integer U. | ||||
| @@ -229,13 +240,13 @@ class BufferT { | ||||
|     SetData(w.data(), w.size()); | ||||
|   } | ||||
|  | ||||
|   // Replaces the data in the buffer with at most |max_elements| of data, using | ||||
|   // the function |setter|, which should have the following signature: | ||||
|   // Replaces the data in the buffer with at most `max_elements` of data, using | ||||
|   // the function `setter`, which should have the following signature: | ||||
|   // | ||||
|   //   size_t setter(ArrayView<U> view) | ||||
|   // | ||||
|   // |setter| is given an appropriately typed ArrayView of length exactly | ||||
|   // |max_elements| that describes the area where it should write the data; it | ||||
|   // `setter` is given an appropriately typed ArrayView of length exactly | ||||
|   // `max_elements` that describes the area where it should write the data; it | ||||
|   // should return the number of elements actually written. (If it doesn't fill | ||||
|   // the whole ArrayView, it should leave the unused space at the end.) | ||||
|   template <typename U = T, | ||||
| @@ -259,6 +270,10 @@ class BufferT { | ||||
|             typename std::enable_if< | ||||
|                 internal::BufferCompat<T, U>::value>::type* = nullptr> | ||||
|   void AppendData(const U* data, size_t size) { | ||||
|     if (size == 0) { | ||||
|       return; | ||||
|     } | ||||
|     RTC_DCHECK(data); | ||||
|     RTC_DCHECK(IsConsistent()); | ||||
|     const size_t new_size = size_ + size; | ||||
|     EnsureCapacityWithHeadroom(new_size, true); | ||||
| @@ -290,13 +305,13 @@ class BufferT { | ||||
|     AppendData(&item, 1); | ||||
|   } | ||||
|  | ||||
|   // Appends at most |max_elements| to the end of the buffer, using the function | ||||
|   // |setter|, which should have the following signature: | ||||
|   // Appends at most `max_elements` to the end of the buffer, using the function | ||||
|   // `setter`, which should have the following signature: | ||||
|   // | ||||
|   //   size_t setter(ArrayView<U> view) | ||||
|   // | ||||
|   // |setter| is given an appropriately typed ArrayView of length exactly | ||||
|   // |max_elements| that describes the area where it should write the data; it | ||||
|   // `setter` is given an appropriately typed ArrayView of length exactly | ||||
|   // `max_elements` that describes the area where it should write the data; it | ||||
|   // should return the number of elements actually written. (If it doesn't fill | ||||
|   // the whole ArrayView, it should leave the unused space at the end.) | ||||
|   template <typename U = T, | ||||
|   | ||||
| @@ -15,6 +15,8 @@ | ||||
| #include <cstdio> | ||||
| #include <cstdlib> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
|  | ||||
| #if defined(WEBRTC_ANDROID) | ||||
| #define RTC_LOG_TAG_ANDROID "rtc" | ||||
| #include <android/log.h>  // NOLINT | ||||
| @@ -36,6 +38,7 @@ | ||||
| #include "rtc_base/checks.h" | ||||
|  | ||||
| namespace { | ||||
|  | ||||
| #if defined(__GNUC__) | ||||
| __attribute__((__format__(__printf__, 2, 3))) | ||||
| #endif | ||||
| @@ -59,6 +62,30 @@ void AppendFormat(std::string* s, const char* fmt, ...) { | ||||
| namespace rtc { | ||||
| namespace webrtc_checks_impl { | ||||
|  | ||||
| #if !defined(WEBRTC_CHROMIUM_BUILD) | ||||
| RTC_NORETURN void WriteFatalLog(absl::string_view output) { | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   std::string output_str(output); | ||||
|   __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", | ||||
|                       output_str.c_str()); | ||||
| #endif | ||||
|   fflush(stdout); | ||||
|   fwrite(output.data(), output.size(), 1, stderr); | ||||
|   fflush(stderr); | ||||
| #if defined(WEBRTC_WIN) | ||||
|   DebugBreak(); | ||||
| #endif | ||||
|   abort(); | ||||
| } | ||||
|  | ||||
| RTC_NORETURN void WriteFatalLog(const char* file, | ||||
|                                 int line, | ||||
|                                 absl::string_view output) { | ||||
|   WriteFatalLog(output); | ||||
| } | ||||
|  | ||||
| #endif  // !defined(WEBRTC_CHROMIUM_BUILD) | ||||
|  | ||||
| #if RTC_CHECK_MSG_ENABLED | ||||
| // Reads one argument from args, appends it to s and advances fmt. | ||||
| // Returns true iff an argument was sucessfully parsed. | ||||
| @@ -149,19 +176,7 @@ RTC_NORETURN void FatalLog(const char* file, | ||||
|  | ||||
|   va_end(args); | ||||
|  | ||||
|   const char* output = s.c_str(); | ||||
|  | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output); | ||||
| #endif | ||||
|  | ||||
|   fflush(stdout); | ||||
|   fprintf(stderr, "%s", output); | ||||
|   fflush(stderr); | ||||
| #if defined(WEBRTC_WIN) | ||||
|   DebugBreak(); | ||||
| #endif | ||||
|   abort(); | ||||
|   WriteFatalLog(file, line, s); | ||||
| } | ||||
| #else  // RTC_CHECK_MSG_ENABLED | ||||
| RTC_NORETURN void FatalLog(const char* file, int line) { | ||||
| @@ -174,22 +189,40 @@ RTC_NORETURN void FatalLog(const char* file, int line) { | ||||
|                "# Check failed.\n" | ||||
|                "# ", | ||||
|                file, line, LAST_SYSTEM_ERROR); | ||||
|   const char* output = s.c_str(); | ||||
|  | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output); | ||||
| #endif | ||||
|  | ||||
|   fflush(stdout); | ||||
|   fprintf(stderr, "%s", output); | ||||
|   fflush(stderr); | ||||
| #if defined(WEBRTC_WIN) | ||||
|   DebugBreak(); | ||||
| #endif | ||||
|   abort(); | ||||
|   WriteFatalLog(file, line, s); | ||||
| } | ||||
| #endif  // RTC_CHECK_MSG_ENABLED | ||||
|  | ||||
| #if RTC_DCHECK_IS_ON | ||||
|  | ||||
| RTC_NORETURN void UnreachableCodeReached(const char* file, int line) { | ||||
|   std::string s; | ||||
|   AppendFormat(&s, | ||||
|                "\n\n" | ||||
|                "#\n" | ||||
|                "# Unreachable code reached: %s, line %d\n" | ||||
|                "# last system error: %u\n" | ||||
|                "# ", | ||||
|                file, line, LAST_SYSTEM_ERROR); | ||||
|   WriteFatalLog(file, line, s); | ||||
| } | ||||
|  | ||||
| #else  // !RTC_DCHECK_IS_ON | ||||
|  | ||||
| RTC_NORETURN void UnreachableCodeReached() { | ||||
|   std::string s; | ||||
|   AppendFormat(&s, | ||||
|                "\n\n" | ||||
|                "#\n" | ||||
|                "# Unreachable code reached (file and line unknown)\n" | ||||
|                "# last system error: %u\n" | ||||
|                "# ", | ||||
|                LAST_SYSTEM_ERROR); | ||||
|   WriteFatalLog(s); | ||||
| } | ||||
|  | ||||
| #endif  // !RTC_DCHECK_IS_ON | ||||
|  | ||||
| }  // namespace webrtc_checks_impl | ||||
| }  // namespace rtc | ||||
|  | ||||
|   | ||||
| @@ -56,6 +56,7 @@ RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg); | ||||
|  | ||||
| #include "absl/meta/type_traits.h" | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "api/scoped_refptr.h" | ||||
| #include "rtc_base/numerics/safe_compare.h" | ||||
| #include "rtc_base/system/inline.h" | ||||
| #include "rtc_base/system/rtc_export.h" | ||||
| @@ -95,7 +96,7 @@ RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg); | ||||
| //   messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and | ||||
| //   RTC_DCHECK. | ||||
| // | ||||
| // - FATAL() aborts unconditionally. | ||||
| // - RTC_FATAL() aborts unconditionally. | ||||
|  | ||||
| namespace rtc { | ||||
| namespace webrtc_checks_impl { | ||||
| @@ -121,6 +122,13 @@ enum class CheckArgType : int8_t { | ||||
|   kCheckOp, | ||||
| }; | ||||
|  | ||||
| // These two functions are public so they can be overridden from | ||||
| // webrtc_overrides in chromium. | ||||
| RTC_NORETURN void WriteFatalLog(const char* file, | ||||
|                                 int line, | ||||
|                                 absl::string_view output); | ||||
| RTC_NORETURN void WriteFatalLog(absl::string_view output); | ||||
|  | ||||
| #if RTC_CHECK_MSG_ENABLED | ||||
| RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, | ||||
|                                       int line, | ||||
| @@ -192,6 +200,12 @@ inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) { | ||||
|   return {x}; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline Val<CheckArgType::kVoidP, const void*> MakeVal( | ||||
|     const rtc::scoped_refptr<T>& p) { | ||||
|   return {p.get()}; | ||||
| } | ||||
|  | ||||
| // The enum class types are not implicitly convertible to arithmetic types. | ||||
| template <typename T, | ||||
|           absl::enable_if_t<std::is_enum<T>::value && | ||||
| @@ -338,9 +352,25 @@ class FatalLogCall final { | ||||
|   const char* message_; | ||||
| }; | ||||
|  | ||||
| #if RTC_DCHECK_IS_ON | ||||
|  | ||||
| // Be helpful, and include file and line in the RTC_CHECK_NOTREACHED error | ||||
| // message. | ||||
| #define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS __FILE__, __LINE__ | ||||
| RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(const char* file, int line); | ||||
|  | ||||
| #else | ||||
|  | ||||
| // Be mindful of binary size, and don't include file and line in the | ||||
| // RTC_CHECK_NOTREACHED error message. | ||||
| #define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS | ||||
| RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(); | ||||
|  | ||||
| #endif | ||||
|  | ||||
| }  // namespace webrtc_checks_impl | ||||
|  | ||||
| // The actual stream used isn't important. We reference |ignored| in the code | ||||
| // The actual stream used isn't important. We reference `ignored` in the code | ||||
| // but don't evaluate it; this is to avoid "unused variable" warnings (we do so | ||||
| // in a particularly convoluted way with an extra ?: because that appears to be | ||||
| // the simplest construct that keeps Visual Studio from complaining about | ||||
| @@ -352,8 +382,8 @@ class FatalLogCall final { | ||||
|             ::rtc::webrtc_checks_impl::LogStreamer<>() | ||||
|  | ||||
| // Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if | ||||
| // values of the same types as |a| and |b| can't be compared with the given | ||||
| // operation, and that would evaluate |a| and |b| if evaluated. | ||||
| // values of the same types as `a` and `b` can't be compared with the given | ||||
| // operation, and that would evaluate `a` and `b` if evaluated. | ||||
| #define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \ | ||||
|   RTC_EAT_STREAM_PARAMETERS(((void)::rtc::Safe##op(a, b))) | ||||
|  | ||||
| @@ -361,7 +391,7 @@ class FatalLogCall final { | ||||
| // controlled by NDEBUG or anything else, so the check will be executed | ||||
| // regardless of compilation mode. | ||||
| // | ||||
| // We make sure RTC_CHECK et al. always evaluates |condition|, as | ||||
| // We make sure RTC_CHECK et al. always evaluates `condition`, as | ||||
| // doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom. | ||||
| // | ||||
| // RTC_CHECK_OP is a helper macro for binary operators. | ||||
| @@ -381,22 +411,20 @@ class FatalLogCall final { | ||||
|             ::rtc::webrtc_checks_impl::LogStreamer<>() << (val1) << (val2) | ||||
| #else | ||||
| #define RTC_CHECK(condition)                                                  \ | ||||
|   (condition)                                                                 \ | ||||
|       ? static_cast<void>(0)                                                  \ | ||||
|       : true ? ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__,       \ | ||||
|                                                               __LINE__, "") & \ | ||||
|                    ::rtc::webrtc_checks_impl::LogStreamer<>()                 \ | ||||
|              : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") &    \ | ||||
|                    ::rtc::webrtc_checks_impl::LogStreamer<>() | ||||
|   (condition) ? static_cast<void>(0)                                          \ | ||||
|   : true ? ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \ | ||||
|                                                           "") &               \ | ||||
|                ::rtc::webrtc_checks_impl::LogStreamer<>()                     \ | ||||
|          : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") &        \ | ||||
|                ::rtc::webrtc_checks_impl::LogStreamer<>() | ||||
|  | ||||
| #define RTC_CHECK_OP(name, op, val1, val2)                                   \ | ||||
|   ::rtc::Safe##name((val1), (val2))                                          \ | ||||
|       ? static_cast<void>(0)                                                 \ | ||||
|       : true ? ::rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__,       \ | ||||
|                                                              __LINE__, "") & \ | ||||
|                    ::rtc::webrtc_checks_impl::LogStreamer<>()                \ | ||||
|              : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") &   \ | ||||
|                    ::rtc::webrtc_checks_impl::LogStreamer<>() | ||||
|   ::rtc::Safe##name((val1), (val2)) ? static_cast<void>(0)                   \ | ||||
|   : true ? ::rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__, __LINE__, \ | ||||
|                                                          "") &               \ | ||||
|                ::rtc::webrtc_checks_impl::LogStreamer<>()                    \ | ||||
|          : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") &       \ | ||||
|                ::rtc::webrtc_checks_impl::LogStreamer<>() | ||||
| #endif | ||||
|  | ||||
| #define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2) | ||||
| @@ -428,10 +456,17 @@ class FatalLogCall final { | ||||
| #endif | ||||
|  | ||||
| #define RTC_UNREACHABLE_CODE_HIT false | ||||
| #define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT) | ||||
| #define RTC_DCHECK_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT) | ||||
|  | ||||
| // TODO(bugs.webrtc.org/8454): Add an RTC_ prefix or rename differently. | ||||
| #define FATAL()                                                      \ | ||||
| // Kills the process with an error message. Never returns. Use when you wish to | ||||
| // assert that a point in the code is never reached. | ||||
| #define RTC_CHECK_NOTREACHED()                         \ | ||||
|   do {                                                 \ | ||||
|     ::rtc::webrtc_checks_impl::UnreachableCodeReached( \ | ||||
|         RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS);      \ | ||||
|   } while (0) | ||||
|  | ||||
| #define RTC_FATAL()                                                  \ | ||||
|   ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \ | ||||
|                                                  "FATAL()") &        \ | ||||
|       ::rtc::webrtc_checks_impl::LogStreamer<>() | ||||
|   | ||||
							
								
								
									
										56
									
								
								webrtc/rtc_base/containers/BUILD.gn
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								webrtc/rtc_base/containers/BUILD.gn
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| # Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | ||||
| # | ||||
| # Use of this source code is governed by a BSD-style license | ||||
| # that can be found in the LICENSE file in the root of the source | ||||
| # tree. An additional intellectual property rights grant can be found | ||||
| # in the file PATENTS.  All contributing project authors may | ||||
| # be found in the AUTHORS file in the root of the source tree. | ||||
|  | ||||
| import("../../webrtc.gni") | ||||
|  | ||||
| rtc_library("flat_containers_internal") { | ||||
|   sources = [ | ||||
|     "flat_tree.cc", | ||||
|     "flat_tree.h", | ||||
|     "identity.h", | ||||
|     "invoke.h", | ||||
|     "move_only_int.h", | ||||
|   ] | ||||
|   deps = [ | ||||
|     "..:checks", | ||||
|     "../system:no_unique_address", | ||||
|   ] | ||||
|   absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ] | ||||
|   visibility = [ ":*" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("flat_set") { | ||||
|   sources = [ "flat_set.h" ] | ||||
|   deps = [ ":flat_containers_internal" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("flat_map") { | ||||
|   sources = [ "flat_map.h" ] | ||||
|   deps = [ | ||||
|     ":flat_containers_internal", | ||||
|     "..:checks", | ||||
|   ] | ||||
| } | ||||
|  | ||||
| rtc_library("unittests") { | ||||
|   testonly = true | ||||
|   sources = [ | ||||
|     "flat_map_unittest.cc", | ||||
|     "flat_set_unittest.cc", | ||||
|     "flat_tree_unittest.cc", | ||||
|   ] | ||||
|   deps = [ | ||||
|     ":flat_containers_internal", | ||||
|     ":flat_map", | ||||
|     ":flat_set", | ||||
|     "../../test:test_support", | ||||
|     "//testing/gmock:gmock", | ||||
|     "//testing/gtest:gtest", | ||||
|   ] | ||||
|   absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ] | ||||
| } | ||||
							
								
								
									
										178
									
								
								webrtc/rtc_base/containers/flat_set.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								webrtc/rtc_base/containers/flat_set.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| // This implementation is borrowed from Chromium. | ||||
|  | ||||
| #ifndef RTC_BASE_CONTAINERS_FLAT_SET_H_ | ||||
| #define RTC_BASE_CONTAINERS_FLAT_SET_H_ | ||||
|  | ||||
| #include <functional> | ||||
| #include <vector> | ||||
|  | ||||
| #include "rtc_base/containers/flat_tree.h"  // IWYU pragma: export | ||||
| #include "rtc_base/containers/identity.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| // flat_set is a container with a std::set-like interface that stores its | ||||
| // contents in a sorted container, by default a vector. | ||||
| // | ||||
| // Its implementation mostly tracks the corresponding standardization proposal | ||||
| // https://wg21.link/P1222. | ||||
| // | ||||
| // | ||||
| // PROS | ||||
| // | ||||
| //  - Good memory locality. | ||||
| //  - Low overhead, especially for smaller sets. | ||||
| //  - Performance is good for more workloads than you might expect (see | ||||
| //    //base/containers/README.md in Chromium repository) | ||||
| //  - Supports C++14 set interface. | ||||
| // | ||||
| // CONS | ||||
| // | ||||
| //  - Inserts and removals are O(n). | ||||
| // | ||||
| // IMPORTANT NOTES | ||||
| // | ||||
| //  - Iterators are invalidated across mutations. | ||||
| //  - If possible, construct a flat_set in one operation by inserting into | ||||
| //    a container and moving that container into the flat_set constructor. | ||||
| //  - For multiple removals use base::EraseIf() which is O(n) rather than | ||||
| //    O(n * removed_items). | ||||
| // | ||||
| // QUICK REFERENCE | ||||
| // | ||||
| // Most of the core functionality is inherited from flat_tree. Please see | ||||
| // flat_tree.h for more details for most of these functions. As a quick | ||||
| // reference, the functions available are: | ||||
| // | ||||
| // Constructors (inputs need not be sorted): | ||||
| //   flat_set(const flat_set&); | ||||
| //   flat_set(flat_set&&); | ||||
| //   flat_set(InputIterator first, InputIterator last, | ||||
| //            const Compare& compare = Compare()); | ||||
| //   flat_set(const container_type& items, | ||||
| //            const Compare& compare = Compare()); | ||||
| //   flat_set(container_type&& items, | ||||
| //            const Compare& compare = Compare());  // Re-use storage. | ||||
| //   flat_set(std::initializer_list<value_type> ilist, | ||||
| //            const Compare& comp = Compare()); | ||||
| // | ||||
| // Constructors (inputs need to be sorted): | ||||
| //   flat_set(sorted_unique_t, | ||||
| //            InputIterator first, InputIterator last, | ||||
| //            const Compare& compare = Compare()); | ||||
| //   flat_set(sorted_unique_t, | ||||
| //            const container_type& items, | ||||
| //            const Compare& compare = Compare()); | ||||
| //   flat_set(sorted_unique_t, | ||||
| //            container_type&& items, | ||||
| //            const Compare& compare = Compare());  // Re-use storage. | ||||
| //   flat_set(sorted_unique_t, | ||||
| //            std::initializer_list<value_type> ilist, | ||||
| //            const Compare& comp = Compare()); | ||||
| // | ||||
| // Assignment functions: | ||||
| //   flat_set& operator=(const flat_set&); | ||||
| //   flat_set& operator=(flat_set&&); | ||||
| //   flat_set& operator=(initializer_list<Key>); | ||||
| // | ||||
| // Memory management functions: | ||||
| //   void   reserve(size_t); | ||||
| //   size_t capacity() const; | ||||
| //   void   shrink_to_fit(); | ||||
| // | ||||
| // Size management functions: | ||||
| //   void   clear(); | ||||
| //   size_t size() const; | ||||
| //   size_t max_size() const; | ||||
| //   bool   empty() const; | ||||
| // | ||||
| // Iterator functions: | ||||
| //   iterator               begin(); | ||||
| //   const_iterator         begin() const; | ||||
| //   const_iterator         cbegin() const; | ||||
| //   iterator               end(); | ||||
| //   const_iterator         end() const; | ||||
| //   const_iterator         cend() const; | ||||
| //   reverse_iterator       rbegin(); | ||||
| //   const reverse_iterator rbegin() const; | ||||
| //   const_reverse_iterator crbegin() const; | ||||
| //   reverse_iterator       rend(); | ||||
| //   const_reverse_iterator rend() const; | ||||
| //   const_reverse_iterator crend() const; | ||||
| // | ||||
| // Insert and accessor functions: | ||||
| //   pair<iterator, bool> insert(const key_type&); | ||||
| //   pair<iterator, bool> insert(key_type&&); | ||||
| //   void                 insert(InputIterator first, InputIterator last); | ||||
| //   iterator             insert(const_iterator hint, const key_type&); | ||||
| //   iterator             insert(const_iterator hint, key_type&&); | ||||
| //   pair<iterator, bool> emplace(Args&&...); | ||||
| //   iterator             emplace_hint(const_iterator, Args&&...); | ||||
| // | ||||
| // Underlying type functions: | ||||
| //   container_type       extract() &&; | ||||
| //   void                 replace(container_type&&); | ||||
| // | ||||
| // Erase functions: | ||||
| //   iterator erase(iterator); | ||||
| //   iterator erase(const_iterator); | ||||
| //   iterator erase(const_iterator first, const_iterator& last); | ||||
| //   template <typename K> size_t erase(const K& key); | ||||
| // | ||||
| // Comparators (see std::set documentation). | ||||
| //   key_compare   key_comp() const; | ||||
| //   value_compare value_comp() const; | ||||
| // | ||||
| // Search functions: | ||||
| //   template <typename K> size_t                   count(const K&) const; | ||||
| //   template <typename K> iterator                 find(const K&); | ||||
| //   template <typename K> const_iterator           find(const K&) const; | ||||
| //   template <typename K> bool                     contains(const K&) const; | ||||
| //   template <typename K> pair<iterator, iterator> equal_range(K&); | ||||
| //   template <typename K> iterator                 lower_bound(const K&); | ||||
| //   template <typename K> const_iterator           lower_bound(const K&) const; | ||||
| //   template <typename K> iterator                 upper_bound(const K&); | ||||
| //   template <typename K> const_iterator           upper_bound(const K&) const; | ||||
| // | ||||
| // General functions: | ||||
| //   void swap(flat_set&); | ||||
| // | ||||
| // Non-member operators: | ||||
| //   bool operator==(const flat_set&, const flat_set); | ||||
| //   bool operator!=(const flat_set&, const flat_set); | ||||
| //   bool operator<(const flat_set&, const flat_set); | ||||
| //   bool operator>(const flat_set&, const flat_set); | ||||
| //   bool operator>=(const flat_set&, const flat_set); | ||||
| //   bool operator<=(const flat_set&, const flat_set); | ||||
| // | ||||
| template <class Key, | ||||
|           class Compare = std::less<>, | ||||
|           class Container = std::vector<Key>> | ||||
| using flat_set = typename ::webrtc::flat_containers_internal:: | ||||
|     flat_tree<Key, webrtc::identity, Compare, Container>; | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // General operations. | ||||
|  | ||||
| // Erases all elements that match predicate. It has O(size) complexity. | ||||
| // | ||||
| //  flat_set<int> numbers; | ||||
| //  ... | ||||
| //  EraseIf(numbers, [](int number) { return number % 2 == 1; }); | ||||
|  | ||||
| // NOLINTNEXTLINE(misc-unused-using-decls) | ||||
| using ::webrtc::flat_containers_internal::EraseIf; | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_CONTAINERS_FLAT_SET_H_ | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | ||||
|  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
| @@ -8,22 +8,12 @@ | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
| 
 | ||||
| #include "rtc_base/synchronization/rw_lock_wrapper.h" | ||||
| // This implementation is borrowed from Chromium.
 | ||||
| 
 | ||||
| #if defined(_WIN32) | ||||
| #include "rtc_base/synchronization/rw_lock_win.h" | ||||
| #else | ||||
| #include "rtc_base/synchronization/rw_lock_posix.h" | ||||
| #endif | ||||
| #include "rtc_base/containers/flat_tree.h" | ||||
| 
 | ||||
| namespace webrtc { | ||||
| 
 | ||||
| RWLockWrapper* RWLockWrapper::CreateRWLock() { | ||||
| #ifdef _WIN32 | ||||
|   return RWLockWin::Create(); | ||||
| #else | ||||
|   return RWLockPosix::Create(); | ||||
| #endif | ||||
| } | ||||
| sorted_unique_t sorted_unique; | ||||
| 
 | ||||
| }  // namespace webrtc
 | ||||
							
								
								
									
										1099
									
								
								webrtc/rtc_base/containers/flat_tree.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1099
									
								
								webrtc/rtc_base/containers/flat_tree.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										36
									
								
								webrtc/rtc_base/containers/identity.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								webrtc/rtc_base/containers/identity.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| // This implementation is borrowed from Chromium. | ||||
|  | ||||
| #ifndef RTC_BASE_CONTAINERS_IDENTITY_H_ | ||||
| #define RTC_BASE_CONTAINERS_IDENTITY_H_ | ||||
|  | ||||
| #include <utility> | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| // Implementation of C++20's std::identity. | ||||
| // | ||||
| // Reference: | ||||
| // - https://en.cppreference.com/w/cpp/utility/functional/identity | ||||
| // - https://wg21.link/func.identity | ||||
| struct identity { | ||||
|   template <typename T> | ||||
|   constexpr T&& operator()(T&& t) const noexcept { | ||||
|     return std::forward<T>(t); | ||||
|   } | ||||
|  | ||||
|   using is_transparent = void; | ||||
| }; | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_CONTAINERS_IDENTITY_H_ | ||||
| @@ -1,45 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_DEPRECATION_H_ | ||||
| #define RTC_BASE_DEPRECATION_H_ | ||||
|  | ||||
| // Annotate the declarations of deprecated functions with this to cause a | ||||
| // compiler warning when they're used. Like so: | ||||
| // | ||||
| //   RTC_DEPRECATED std::pony PonyPlz(const std::pony_spec& ps); | ||||
| // | ||||
| // NOTE 1: The annotation goes on the declaration in the .h file, not the | ||||
| // definition in the .cc file! | ||||
| // | ||||
| // NOTE 2: In order to keep unit testing the deprecated function without | ||||
| // getting warnings, do something like this: | ||||
| // | ||||
| //   std::pony DEPRECATED_PonyPlz(const std::pony_spec& ps); | ||||
| //   RTC_DEPRECATED inline std::pony PonyPlz(const std::pony_spec& ps) { | ||||
| //     return DEPRECATED_PonyPlz(ps); | ||||
| //   } | ||||
| // | ||||
| // In other words, rename the existing function, and provide an inline wrapper | ||||
| // using the original name that calls it. That way, callers who are willing to | ||||
| // call it using the DEPRECATED_-prefixed name don't get the warning. | ||||
| // | ||||
| // TODO(kwiberg): Remove this when we can use [[deprecated]] from C++14. | ||||
| #if defined(_MSC_VER) | ||||
| // Note: Deprecation warnings seem to fail to trigger on Windows | ||||
| // (https://bugs.chromium.org/p/webrtc/issues/detail?id=5368). | ||||
| #define RTC_DEPRECATED __declspec(deprecated) | ||||
| #elif defined(__GNUC__) | ||||
| #define RTC_DEPRECATED __attribute__((__deprecated__)) | ||||
| #else | ||||
| #define RTC_DEPRECATED | ||||
| #endif | ||||
|  | ||||
| #endif  // RTC_BASE_DEPRECATION_H_ | ||||
| @@ -25,9 +25,12 @@ | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/synchronization/yield_policy.h" | ||||
| #include "rtc_base/system/warn_current_thread_is_deadlocked.h" | ||||
| #include "rtc_base/time_utils.h" | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| using ::webrtc::TimeDelta; | ||||
|  | ||||
| Event::Event() : Event(false, false) {} | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| @@ -51,9 +54,12 @@ void Event::Reset() { | ||||
|   ResetEvent(event_handle_); | ||||
| } | ||||
|  | ||||
| bool Event::Wait(const int give_up_after_ms, int /*warn_after_ms*/) { | ||||
| bool Event::Wait(TimeDelta give_up_after, TimeDelta /*warn_after*/) { | ||||
|   ScopedYieldPolicy::YieldExecution(); | ||||
|   const DWORD ms = give_up_after_ms == kForever ? INFINITE : give_up_after_ms; | ||||
|   const DWORD ms = | ||||
|       give_up_after.IsPlusInfinity() | ||||
|           ? INFINITE | ||||
|           : give_up_after.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms(); | ||||
|   return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0); | ||||
| } | ||||
|  | ||||
| @@ -108,7 +114,7 @@ void Event::Reset() { | ||||
|  | ||||
| namespace { | ||||
|  | ||||
| timespec GetTimespec(const int milliseconds_from_now) { | ||||
| timespec GetTimespec(TimeDelta duration_from_now) { | ||||
|   timespec ts; | ||||
|  | ||||
|   // Get the current time. | ||||
| @@ -118,17 +124,19 @@ timespec GetTimespec(const int milliseconds_from_now) { | ||||
|   timeval tv; | ||||
|   gettimeofday(&tv, nullptr); | ||||
|   ts.tv_sec = tv.tv_sec; | ||||
|   ts.tv_nsec = tv.tv_usec * 1000; | ||||
|   ts.tv_nsec = tv.tv_usec * kNumNanosecsPerMicrosec; | ||||
| #endif | ||||
|  | ||||
|   // Add the specified number of milliseconds to it. | ||||
|   ts.tv_sec += (milliseconds_from_now / 1000); | ||||
|   ts.tv_nsec += (milliseconds_from_now % 1000) * 1000000; | ||||
|   int64_t microsecs_from_now = duration_from_now.us(); | ||||
|   ts.tv_sec += microsecs_from_now / kNumMicrosecsPerSec; | ||||
|   ts.tv_nsec += | ||||
|       (microsecs_from_now % kNumMicrosecsPerSec) * kNumNanosecsPerMicrosec; | ||||
|  | ||||
|   // Normalize. | ||||
|   if (ts.tv_nsec >= 1000000000) { | ||||
|   if (ts.tv_nsec >= kNumNanosecsPerSec) { | ||||
|     ts.tv_sec++; | ||||
|     ts.tv_nsec -= 1000000000; | ||||
|     ts.tv_nsec -= kNumNanosecsPerSec; | ||||
|   } | ||||
|  | ||||
|   return ts; | ||||
| @@ -136,22 +144,21 @@ timespec GetTimespec(const int milliseconds_from_now) { | ||||
|  | ||||
| }  // namespace | ||||
|  | ||||
| bool Event::Wait(const int give_up_after_ms, const int warn_after_ms) { | ||||
| bool Event::Wait(TimeDelta give_up_after, TimeDelta warn_after) { | ||||
|   // Instant when we'll log a warning message (because we've been waiting so | ||||
|   // long it might be a bug), but not yet give up waiting. nullopt if we | ||||
|   // shouldn't log a warning. | ||||
|   const absl::optional<timespec> warn_ts = | ||||
|       warn_after_ms == kForever || | ||||
|               (give_up_after_ms != kForever && warn_after_ms > give_up_after_ms) | ||||
|       warn_after >= give_up_after | ||||
|           ? absl::nullopt | ||||
|           : absl::make_optional(GetTimespec(warn_after_ms)); | ||||
|           : absl::make_optional(GetTimespec(warn_after)); | ||||
|  | ||||
|   // Instant when we'll stop waiting and return an error. nullopt if we should | ||||
|   // never give up. | ||||
|   const absl::optional<timespec> give_up_ts = | ||||
|       give_up_after_ms == kForever | ||||
|       give_up_after.IsPlusInfinity() | ||||
|           ? absl::nullopt | ||||
|           : absl::make_optional(GetTimespec(give_up_after_ms)); | ||||
|           : absl::make_optional(GetTimespec(give_up_after)); | ||||
|  | ||||
|   ScopedYieldPolicy::YieldExecution(); | ||||
|   pthread_mutex_lock(&event_mutex_); | ||||
|   | ||||
| @@ -11,6 +11,8 @@ | ||||
| #ifndef RTC_BASE_EVENT_H_ | ||||
| #define RTC_BASE_EVENT_H_ | ||||
|  | ||||
| #include "api/units/time_delta.h" | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| #include <windows.h> | ||||
| #elif defined(WEBRTC_POSIX) | ||||
| @@ -19,11 +21,43 @@ | ||||
| #error "Must define either WEBRTC_WIN or WEBRTC_POSIX." | ||||
| #endif | ||||
|  | ||||
| #include "rtc_base/synchronization/yield_policy.h" | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| // RTC_DISALLOW_WAIT() utility | ||||
| // | ||||
| // Sets a stack-scoped flag that disallows use of `rtc::Event::Wait` by means | ||||
| // of raising a DCHECK when a call to `rtc::Event::Wait()` is made.. | ||||
| // This is useful to guard synchronization-free scopes against regressions. | ||||
| // | ||||
| // Example of what this would catch (`ScopeToProtect` calls `Foo`): | ||||
| // | ||||
| //  void Foo(TaskQueue* tq) { | ||||
| //    Event event; | ||||
| //    tq->PostTask([&event]() { | ||||
| //      event.Set(); | ||||
| //    }); | ||||
| //    event.Wait(Event::kForever);  // <- Will trigger a DCHECK. | ||||
| //  } | ||||
| // | ||||
| //  void ScopeToProtect() { | ||||
| //    TaskQueue* tq = GetSomeTaskQueue(); | ||||
| //    RTC_DISALLOW_WAIT();  // Policy takes effect. | ||||
| //    Foo(tq); | ||||
| //  } | ||||
| // | ||||
| #if RTC_DCHECK_IS_ON | ||||
| #define RTC_DISALLOW_WAIT() ScopedDisallowWait disallow_wait_##__LINE__ | ||||
| #else | ||||
| #define RTC_DISALLOW_WAIT() | ||||
| #endif | ||||
|  | ||||
| class Event { | ||||
|  public: | ||||
|   static const int kForever = -1; | ||||
|   // TODO(bugs.webrtc.org/14366): Consider removing this redundant alias. | ||||
|   static constexpr webrtc::TimeDelta kForever = | ||||
|       webrtc::TimeDelta::PlusInfinity(); | ||||
|  | ||||
|   Event(); | ||||
|   Event(bool manual_reset, bool initially_signaled); | ||||
| @@ -35,19 +69,22 @@ class Event { | ||||
|   void Reset(); | ||||
|  | ||||
|   // Waits for the event to become signaled, but logs a warning if it takes more | ||||
|   // than `warn_after_ms` milliseconds, and gives up completely if it takes more | ||||
|   // than `give_up_after_ms` milliseconds. (If `warn_after_ms >= | ||||
|   // give_up_after_ms`, no warning will be logged.) Either or both may be | ||||
|   // `kForever`, which means wait indefinitely. | ||||
|   // than `warn_after`, and gives up completely if it takes more than | ||||
|   // `give_up_after`. (If `warn_after >= give_up_after`, no warning will be | ||||
|   // logged.) Either or both may be `kForever`, which means wait indefinitely. | ||||
|   // | ||||
|   // Care is taken so that the underlying OS wait call isn't requested to sleep | ||||
|   // shorter than `give_up_after`. | ||||
|   // | ||||
|   // Returns true if the event was signaled, false if there was a timeout or | ||||
|   // some other error. | ||||
|   bool Wait(int give_up_after_ms, int warn_after_ms); | ||||
|   bool Wait(webrtc::TimeDelta give_up_after, webrtc::TimeDelta warn_after); | ||||
|  | ||||
|   // Waits with the given timeout and a reasonable default warning timeout. | ||||
|   bool Wait(int give_up_after_ms) { | ||||
|     return Wait(give_up_after_ms, | ||||
|                 give_up_after_ms == kForever ? 3000 : kForever); | ||||
|   bool Wait(webrtc::TimeDelta give_up_after) { | ||||
|     return Wait(give_up_after, give_up_after.IsPlusInfinity() | ||||
|                                    ? webrtc::TimeDelta::Seconds(3) | ||||
|                                    : kForever); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
| @@ -81,6 +118,20 @@ class ScopedAllowBaseSyncPrimitivesForTesting { | ||||
|   ~ScopedAllowBaseSyncPrimitivesForTesting() {} | ||||
| }; | ||||
|  | ||||
| #if RTC_DCHECK_IS_ON | ||||
| class ScopedDisallowWait { | ||||
|  public: | ||||
|   ScopedDisallowWait() = default; | ||||
|  | ||||
|  private: | ||||
|   class DisallowYieldHandler : public YieldInterface { | ||||
|    public: | ||||
|     void YieldExecution() override { RTC_DCHECK_NOTREACHED(); } | ||||
|   } handler_; | ||||
|   rtc::ScopedYieldPolicy policy{&handler_}; | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| }  // namespace rtc | ||||
|  | ||||
| #endif  // RTC_BASE_EVENT_H_ | ||||
|   | ||||
| @@ -14,10 +14,12 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include <atomic> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| #include "rtc_base/atomic_ops.h" | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "api/sequence_checker.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/event.h" | ||||
| #include "rtc_base/logging.h" | ||||
| @@ -25,7 +27,6 @@ | ||||
| #include "rtc_base/platform_thread_types.h" | ||||
| #include "rtc_base/synchronization/mutex.h" | ||||
| #include "rtc_base/thread_annotations.h" | ||||
| #include "rtc_base/thread_checker.h" | ||||
| #include "rtc_base/time_utils.h" | ||||
| #include "rtc_base/trace_event.h" | ||||
|  | ||||
| @@ -79,19 +80,12 @@ namespace rtc { | ||||
| namespace tracing { | ||||
| namespace { | ||||
|  | ||||
| static void EventTracingThreadFunc(void* params); | ||||
|  | ||||
| // Atomic-int fast path for avoiding logging when disabled. | ||||
| static volatile int g_event_logging_active = 0; | ||||
| static std::atomic<int> g_event_logging_active(0); | ||||
|  | ||||
| // TODO(pbos): Log metadata for all threads, etc. | ||||
| class EventLogger final { | ||||
|  public: | ||||
|   EventLogger() | ||||
|       : logging_thread_(EventTracingThreadFunc, | ||||
|                         this, | ||||
|                         "EventTracingThread", | ||||
|                         kLowPriority) {} | ||||
|   ~EventLogger() { RTC_DCHECK(thread_checker_.IsCurrent()); } | ||||
|  | ||||
|   void AddTraceEvent(const char* name, | ||||
| @@ -129,11 +123,12 @@ class EventLogger final { | ||||
|   // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview | ||||
|   void Log() { | ||||
|     RTC_DCHECK(output_file_); | ||||
|     static const int kLoggingIntervalMs = 100; | ||||
|     static constexpr webrtc::TimeDelta kLoggingInterval = | ||||
|         webrtc::TimeDelta::Millis(100); | ||||
|     fprintf(output_file_, "{ \"traceEvents\": [\n"); | ||||
|     bool has_logged_event = false; | ||||
|     while (true) { | ||||
|       bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs); | ||||
|       bool shutting_down = shutdown_event_.Wait(kLoggingInterval); | ||||
|       std::vector<TraceEvent> events; | ||||
|       { | ||||
|         webrtc::MutexLock lock(&mutex_); | ||||
| @@ -205,11 +200,12 @@ class EventLogger final { | ||||
|     } | ||||
|     // Enable event logging (fast-path). This should be disabled since starting | ||||
|     // shouldn't be done twice. | ||||
|     RTC_CHECK_EQ(0, | ||||
|                  rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 0, 1)); | ||||
|     int zero = 0; | ||||
|     RTC_CHECK(g_event_logging_active.compare_exchange_strong(zero, 1)); | ||||
|  | ||||
|     // Finally start, everything should be set up now. | ||||
|     logging_thread_.Start(); | ||||
|     logging_thread_ = | ||||
|         PlatformThread::SpawnJoinable([this] { Log(); }, "EventTracingThread"); | ||||
|     TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start"); | ||||
|   } | ||||
|  | ||||
| @@ -217,13 +213,14 @@ class EventLogger final { | ||||
|     RTC_DCHECK(thread_checker_.IsCurrent()); | ||||
|     TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Stop"); | ||||
|     // Try to stop. Abort if we're not currently logging. | ||||
|     if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0) | ||||
|     int one = 1; | ||||
|     if (g_event_logging_active.compare_exchange_strong(one, 0)) | ||||
|       return; | ||||
|  | ||||
|     // Wake up logging thread to finish writing. | ||||
|     shutdown_event_.Set(); | ||||
|     // Join the logging thread. | ||||
|     logging_thread_.Stop(); | ||||
|     logging_thread_.Finalize(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
| @@ -321,16 +318,12 @@ class EventLogger final { | ||||
|   std::vector<TraceEvent> trace_events_ RTC_GUARDED_BY(mutex_); | ||||
|   rtc::PlatformThread logging_thread_; | ||||
|   rtc::Event shutdown_event_; | ||||
|   rtc::ThreadChecker thread_checker_; | ||||
|   webrtc::SequenceChecker thread_checker_; | ||||
|   FILE* output_file_ = nullptr; | ||||
|   bool output_file_owned_ = false; | ||||
| }; | ||||
|  | ||||
| static void EventTracingThreadFunc(void* params) { | ||||
|   static_cast<EventLogger*>(params)->Log(); | ||||
| } | ||||
|  | ||||
| static EventLogger* volatile g_event_logger = nullptr; | ||||
| static std::atomic<EventLogger*> g_event_logger(nullptr); | ||||
| static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT(""); | ||||
| const unsigned char* InternalGetCategoryEnabled(const char* name) { | ||||
|   const char* prefix_ptr = &kDisabledTracePrefix[0]; | ||||
| @@ -344,6 +337,10 @@ const unsigned char* InternalGetCategoryEnabled(const char* name) { | ||||
|                                                                     : name); | ||||
| } | ||||
|  | ||||
| const unsigned char* InternalEnableAllCategories(const char* name) { | ||||
|   return reinterpret_cast<const unsigned char*>(name); | ||||
| } | ||||
|  | ||||
| void InternalAddTraceEvent(char phase, | ||||
|                            const unsigned char* category_enabled, | ||||
|                            const char* name, | ||||
| @@ -354,56 +351,59 @@ void InternalAddTraceEvent(char phase, | ||||
|                            const unsigned long long* arg_values, | ||||
|                            unsigned char flags) { | ||||
|   // Fast path for when event tracing is inactive. | ||||
|   if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) | ||||
|   if (g_event_logging_active.load() == 0) | ||||
|     return; | ||||
|  | ||||
|   g_event_logger->AddTraceEvent(name, category_enabled, phase, num_args, | ||||
|                                 arg_names, arg_types, arg_values, | ||||
|                                 rtc::TimeMicros(), 1, rtc::CurrentThreadId()); | ||||
|   g_event_logger.load()->AddTraceEvent( | ||||
|       name, category_enabled, phase, num_args, arg_names, arg_types, arg_values, | ||||
|       rtc::TimeMicros(), 1, rtc::CurrentThreadId()); | ||||
| } | ||||
|  | ||||
| }  // namespace | ||||
|  | ||||
| void SetupInternalTracer() { | ||||
|   RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( | ||||
|                 &g_event_logger, static_cast<EventLogger*>(nullptr), | ||||
|                 new EventLogger()) == nullptr); | ||||
|   webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent); | ||||
| void SetupInternalTracer(bool enable_all_categories) { | ||||
|   EventLogger* null_logger = nullptr; | ||||
|   RTC_CHECK( | ||||
|       g_event_logger.compare_exchange_strong(null_logger, new EventLogger())); | ||||
|   webrtc::SetupEventTracer(enable_all_categories ? InternalEnableAllCategories | ||||
|                                                  : InternalGetCategoryEnabled, | ||||
|                            InternalAddTraceEvent); | ||||
| } | ||||
|  | ||||
| void StartInternalCaptureToFile(FILE* file) { | ||||
|   if (g_event_logger) { | ||||
|     g_event_logger->Start(file, false); | ||||
|   EventLogger* event_logger = g_event_logger.load(); | ||||
|   if (event_logger) { | ||||
|     event_logger->Start(file, false); | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool StartInternalCapture(const char* filename) { | ||||
|   if (!g_event_logger) | ||||
| bool StartInternalCapture(absl::string_view filename) { | ||||
|   EventLogger* event_logger = g_event_logger.load(); | ||||
|   if (!event_logger) | ||||
|     return false; | ||||
|  | ||||
|   FILE* file = fopen(filename, "w"); | ||||
|   FILE* file = fopen(std::string(filename).c_str(), "w"); | ||||
|   if (!file) { | ||||
|     RTC_LOG(LS_ERROR) << "Failed to open trace file '" << filename | ||||
|                       << "' for writing."; | ||||
|     return false; | ||||
|   } | ||||
|   g_event_logger->Start(file, true); | ||||
|   event_logger->Start(file, true); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void StopInternalCapture() { | ||||
|   if (g_event_logger) { | ||||
|     g_event_logger->Stop(); | ||||
|   EventLogger* event_logger = g_event_logger.load(); | ||||
|   if (event_logger) { | ||||
|     event_logger->Stop(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ShutdownInternalTracer() { | ||||
|   StopInternalCapture(); | ||||
|   EventLogger* old_logger = rtc::AtomicOps::AcquireLoadPtr(&g_event_logger); | ||||
|   EventLogger* old_logger = g_event_logger.load(std::memory_order_acquire); | ||||
|   RTC_DCHECK(old_logger); | ||||
|   RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( | ||||
|                 &g_event_logger, old_logger, | ||||
|                 static_cast<EventLogger*>(nullptr)) == old_logger); | ||||
|   RTC_CHECK(g_event_logger.compare_exchange_strong(old_logger, nullptr)); | ||||
|   delete old_logger; | ||||
|   webrtc::SetupEventTracer(nullptr, nullptr); | ||||
| } | ||||
|   | ||||
| @@ -28,6 +28,9 @@ | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "rtc_base/system/rtc_export.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name); | ||||
| @@ -70,12 +73,12 @@ class EventTracer { | ||||
| namespace rtc { | ||||
| namespace tracing { | ||||
| // Set up internal event tracer. | ||||
| void SetupInternalTracer(); | ||||
| bool StartInternalCapture(const char* filename); | ||||
| void StartInternalCaptureToFile(FILE* file); | ||||
| void StopInternalCapture(); | ||||
| RTC_EXPORT void SetupInternalTracer(bool enable_all_categories = true); | ||||
| RTC_EXPORT bool StartInternalCapture(absl::string_view filename); | ||||
| RTC_EXPORT void StartInternalCaptureToFile(FILE* file); | ||||
| RTC_EXPORT void StopInternalCapture(); | ||||
| // Make sure we run this, this will tear down the internal tracing. | ||||
| void ShutdownInternalTracer(); | ||||
| RTC_EXPORT void ShutdownInternalTracer(); | ||||
| }  // namespace tracing | ||||
| }  // namespace rtc | ||||
|  | ||||
|   | ||||
| @@ -16,21 +16,15 @@ | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/logging.h" | ||||
| #include "rtc_base/numerics/safe_conversions.h" | ||||
|  | ||||
| namespace webrtc { | ||||
| namespace { | ||||
|  | ||||
| int FindOrEnd(std::string str, size_t start, char delimiter) { | ||||
|   size_t pos = str.find(delimiter, start); | ||||
|   pos = (pos == std::string::npos) ? str.length() : pos; | ||||
|   return static_cast<int>(pos); | ||||
| } | ||||
| }  // namespace | ||||
|  | ||||
| FieldTrialParameterInterface::FieldTrialParameterInterface(std::string key) | ||||
| FieldTrialParameterInterface::FieldTrialParameterInterface( | ||||
|     absl::string_view key) | ||||
|     : key_(key) {} | ||||
| FieldTrialParameterInterface::~FieldTrialParameterInterface() { | ||||
|   RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_ | ||||
| @@ -39,8 +33,8 @@ FieldTrialParameterInterface::~FieldTrialParameterInterface() { | ||||
|  | ||||
| void ParseFieldTrial( | ||||
|     std::initializer_list<FieldTrialParameterInterface*> fields, | ||||
|     std::string trial_string) { | ||||
|   std::map<std::string, FieldTrialParameterInterface*> field_map; | ||||
|     absl::string_view trial_string) { | ||||
|   std::map<absl::string_view, FieldTrialParameterInterface*> field_map; | ||||
|   FieldTrialParameterInterface* keyless_field = nullptr; | ||||
|   for (FieldTrialParameterInterface* field : fields) { | ||||
|     field->MarkAsUsed(); | ||||
| @@ -60,18 +54,29 @@ void ParseFieldTrial( | ||||
|       field_map[field->key_] = field; | ||||
|     } | ||||
|   } | ||||
|   bool logged_unknown_key = false; | ||||
|  | ||||
|   size_t i = 0; | ||||
|   while (i < trial_string.length()) { | ||||
|     int val_end = FindOrEnd(trial_string, i, ','); | ||||
|     int colon_pos = FindOrEnd(trial_string, i, ':'); | ||||
|     int key_end = std::min(val_end, colon_pos); | ||||
|     int val_begin = key_end + 1; | ||||
|     std::string key = trial_string.substr(i, key_end - i); | ||||
|   absl::string_view tail = trial_string; | ||||
|   while (!tail.empty()) { | ||||
|     size_t key_end = tail.find_first_of(",:"); | ||||
|     absl::string_view key = tail.substr(0, key_end); | ||||
|     absl::optional<std::string> opt_value; | ||||
|     if (val_end >= val_begin) | ||||
|       opt_value = trial_string.substr(val_begin, val_end - val_begin); | ||||
|     i = val_end + 1; | ||||
|     if (key_end == absl::string_view::npos) { | ||||
|       tail = ""; | ||||
|     } else if (tail[key_end] == ':') { | ||||
|       tail = tail.substr(key_end + 1); | ||||
|       size_t value_end = tail.find(','); | ||||
|       opt_value.emplace(tail.substr(0, value_end)); | ||||
|       if (value_end == absl::string_view::npos) { | ||||
|         tail = ""; | ||||
|       } else { | ||||
|         tail = tail.substr(value_end + 1); | ||||
|       } | ||||
|     } else { | ||||
|       RTC_DCHECK_EQ(tail[key_end], ','); | ||||
|       tail = tail.substr(key_end + 1); | ||||
|     } | ||||
|  | ||||
|     auto field = field_map.find(key); | ||||
|     if (field != field_map.end()) { | ||||
|       if (!field->second->Parse(std::move(opt_value))) { | ||||
| @@ -79,19 +84,25 @@ void ParseFieldTrial( | ||||
|                             << "' in trial: \"" << trial_string << "\""; | ||||
|       } | ||||
|     } else if (!opt_value && keyless_field && !key.empty()) { | ||||
|       if (!keyless_field->Parse(key)) { | ||||
|       if (!keyless_field->Parse(std::string(key))) { | ||||
|         RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '" | ||||
|                             << key << "' in trial: \"" << trial_string << "\""; | ||||
|       } | ||||
|     } else { | ||||
|       RTC_LOG(LS_INFO) << "No field with key: '" << key | ||||
|                        << "' (found in trial: \"" << trial_string << "\")"; | ||||
|       std::string valid_keys; | ||||
|       for (const auto& f : field_map) { | ||||
|         valid_keys += f.first; | ||||
|         valid_keys += ", "; | ||||
|     } else if (key.empty() || key[0] != '_') { | ||||
|       // "_" is be used to prefix keys that are part of the string for | ||||
|       // debugging purposes but not neccessarily used. | ||||
|       // e.g. WebRTC-Experiment/param: value, _DebuggingString | ||||
|       if (!logged_unknown_key) { | ||||
|         RTC_LOG(LS_INFO) << "No field with key: '" << key | ||||
|                          << "' (found in trial: \"" << trial_string << "\")"; | ||||
|         std::string valid_keys; | ||||
|         for (const auto& f : field_map) { | ||||
|           valid_keys.append(f.first.data(), f.first.size()); | ||||
|           valid_keys += ", "; | ||||
|         } | ||||
|         RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys; | ||||
|         logged_unknown_key = true; | ||||
|       } | ||||
|       RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -101,7 +112,7 @@ void ParseFieldTrial( | ||||
| } | ||||
|  | ||||
| template <> | ||||
| absl::optional<bool> ParseTypedParameter<bool>(std::string str) { | ||||
| absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str) { | ||||
|   if (str == "true" || str == "1") { | ||||
|     return true; | ||||
|   } else if (str == "false" || str == "0") { | ||||
| @@ -111,10 +122,10 @@ absl::optional<bool> ParseTypedParameter<bool>(std::string str) { | ||||
| } | ||||
|  | ||||
| template <> | ||||
| absl::optional<double> ParseTypedParameter<double>(std::string str) { | ||||
| absl::optional<double> ParseTypedParameter<double>(absl::string_view str) { | ||||
|   double value; | ||||
|   char unit[2]{0, 0}; | ||||
|   if (sscanf(str.c_str(), "%lf%1s", &value, unit) >= 1) { | ||||
|   if (sscanf(std::string(str).c_str(), "%lf%1s", &value, unit) >= 1) { | ||||
|     if (unit[0] == '%') | ||||
|       return value / 100; | ||||
|     return value; | ||||
| @@ -124,9 +135,9 @@ absl::optional<double> ParseTypedParameter<double>(std::string str) { | ||||
| } | ||||
|  | ||||
| template <> | ||||
| absl::optional<int> ParseTypedParameter<int>(std::string str) { | ||||
| absl::optional<int> ParseTypedParameter<int>(absl::string_view str) { | ||||
|   int64_t value; | ||||
|   if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) { | ||||
|   if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) { | ||||
|     if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) { | ||||
|       return static_cast<int>(value); | ||||
|     } | ||||
| @@ -135,9 +146,9 @@ absl::optional<int> ParseTypedParameter<int>(std::string str) { | ||||
| } | ||||
|  | ||||
| template <> | ||||
| absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str) { | ||||
| absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str) { | ||||
|   int64_t value; | ||||
|   if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) { | ||||
|   if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) { | ||||
|     if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) { | ||||
|       return static_cast<unsigned>(value); | ||||
|     } | ||||
| @@ -146,34 +157,36 @@ absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str) { | ||||
| } | ||||
|  | ||||
| template <> | ||||
| absl::optional<std::string> ParseTypedParameter<std::string>(std::string str) { | ||||
|   return std::move(str); | ||||
| absl::optional<std::string> ParseTypedParameter<std::string>( | ||||
|     absl::string_view str) { | ||||
|   return std::string(str); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>( | ||||
|     std::string str) { | ||||
|     absl::string_view str) { | ||||
|   return ParseOptionalParameter<bool>(str); | ||||
| } | ||||
| template <> | ||||
| absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>( | ||||
|     std::string str) { | ||||
|     absl::string_view str) { | ||||
|   return ParseOptionalParameter<int>(str); | ||||
| } | ||||
| template <> | ||||
| absl::optional<absl::optional<unsigned>> | ||||
| ParseTypedParameter<absl::optional<unsigned>>(std::string str) { | ||||
| ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str) { | ||||
|   return ParseOptionalParameter<unsigned>(str); | ||||
| } | ||||
| template <> | ||||
| absl::optional<absl::optional<double>> | ||||
| ParseTypedParameter<absl::optional<double>>(std::string str) { | ||||
| ParseTypedParameter<absl::optional<double>>(absl::string_view str) { | ||||
|   return ParseOptionalParameter<double>(str); | ||||
| } | ||||
|  | ||||
| FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {} | ||||
| FieldTrialFlag::FieldTrialFlag(absl::string_view key) | ||||
|     : FieldTrialFlag(key, false) {} | ||||
|  | ||||
| FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value) | ||||
| FieldTrialFlag::FieldTrialFlag(absl::string_view key, bool default_value) | ||||
|     : FieldTrialParameterInterface(key), value_(default_value) {} | ||||
|  | ||||
| bool FieldTrialFlag::Get() const { | ||||
| @@ -198,7 +211,7 @@ bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) { | ||||
| } | ||||
|  | ||||
| AbstractFieldTrialEnum::AbstractFieldTrialEnum( | ||||
|     std::string key, | ||||
|     absl::string_view key, | ||||
|     int default_value, | ||||
|     std::map<std::string, int> mapping) | ||||
|     : FieldTrialParameterInterface(key), | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "absl/types/optional.h" | ||||
|  | ||||
| // Field trial parser functionality. Provides funcitonality to parse field trial | ||||
| @@ -45,10 +46,10 @@ class FieldTrialParameterInterface { | ||||
|   FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default; | ||||
|   FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) = | ||||
|       default; | ||||
|   explicit FieldTrialParameterInterface(std::string key); | ||||
|   explicit FieldTrialParameterInterface(absl::string_view key); | ||||
|   friend void ParseFieldTrial( | ||||
|       std::initializer_list<FieldTrialParameterInterface*> fields, | ||||
|       std::string raw_string); | ||||
|       absl::string_view trial_string); | ||||
|   void MarkAsUsed() { used_ = true; } | ||||
|   virtual bool Parse(absl::optional<std::string> str_value) = 0; | ||||
|  | ||||
| @@ -65,19 +66,19 @@ class FieldTrialParameterInterface { | ||||
| // with extracted values if available. | ||||
| void ParseFieldTrial( | ||||
|     std::initializer_list<FieldTrialParameterInterface*> fields, | ||||
|     std::string raw_string); | ||||
|     absl::string_view trial_string); | ||||
|  | ||||
| // Specialize this in code file for custom types. Should return absl::nullopt if | ||||
| // the given string cannot be properly parsed. | ||||
| template <typename T> | ||||
| absl::optional<T> ParseTypedParameter(std::string); | ||||
| absl::optional<T> ParseTypedParameter(absl::string_view); | ||||
|  | ||||
| // This class uses the ParseTypedParameter function to implement a parameter | ||||
| // implementation with an enforced default value. | ||||
| template <typename T> | ||||
| class FieldTrialParameter : public FieldTrialParameterInterface { | ||||
|  public: | ||||
|   FieldTrialParameter(std::string key, T default_value) | ||||
|   FieldTrialParameter(absl::string_view key, T default_value) | ||||
|       : FieldTrialParameterInterface(key), value_(default_value) {} | ||||
|   T Get() const { return value_; } | ||||
|   operator T() const { return Get(); } | ||||
| @@ -107,7 +108,7 @@ class FieldTrialParameter : public FieldTrialParameterInterface { | ||||
| template <typename T> | ||||
| class FieldTrialConstrained : public FieldTrialParameterInterface { | ||||
|  public: | ||||
|   FieldTrialConstrained(std::string key, | ||||
|   FieldTrialConstrained(absl::string_view key, | ||||
|                         T default_value, | ||||
|                         absl::optional<T> lower_limit, | ||||
|                         absl::optional<T> upper_limit) | ||||
| @@ -140,7 +141,7 @@ class FieldTrialConstrained : public FieldTrialParameterInterface { | ||||
|  | ||||
| class AbstractFieldTrialEnum : public FieldTrialParameterInterface { | ||||
|  public: | ||||
|   AbstractFieldTrialEnum(std::string key, | ||||
|   AbstractFieldTrialEnum(absl::string_view key, | ||||
|                          int default_value, | ||||
|                          std::map<std::string, int> mapping); | ||||
|   ~AbstractFieldTrialEnum() override; | ||||
| @@ -161,7 +162,7 @@ class AbstractFieldTrialEnum : public FieldTrialParameterInterface { | ||||
| template <typename T> | ||||
| class FieldTrialEnum : public AbstractFieldTrialEnum { | ||||
|  public: | ||||
|   FieldTrialEnum(std::string key, | ||||
|   FieldTrialEnum(absl::string_view key, | ||||
|                  T default_value, | ||||
|                  std::map<std::string, T> mapping) | ||||
|       : AbstractFieldTrialEnum(key, | ||||
| @@ -184,9 +185,9 @@ class FieldTrialEnum : public AbstractFieldTrialEnum { | ||||
| template <typename T> | ||||
| class FieldTrialOptional : public FieldTrialParameterInterface { | ||||
|  public: | ||||
|   explicit FieldTrialOptional(std::string key) | ||||
|   explicit FieldTrialOptional(absl::string_view key) | ||||
|       : FieldTrialParameterInterface(key) {} | ||||
|   FieldTrialOptional(std::string key, absl::optional<T> default_value) | ||||
|   FieldTrialOptional(absl::string_view key, absl::optional<T> default_value) | ||||
|       : FieldTrialParameterInterface(key), value_(default_value) {} | ||||
|   absl::optional<T> GetOptional() const { return value_; } | ||||
|   const T& Value() const { return value_.value(); } | ||||
| @@ -216,10 +217,10 @@ class FieldTrialOptional : public FieldTrialParameterInterface { | ||||
| // explicit value is provided, the flag evaluates to true. | ||||
| class FieldTrialFlag : public FieldTrialParameterInterface { | ||||
|  public: | ||||
|   explicit FieldTrialFlag(std::string key); | ||||
|   FieldTrialFlag(std::string key, bool default_value); | ||||
|   explicit FieldTrialFlag(absl::string_view key); | ||||
|   FieldTrialFlag(absl::string_view key, bool default_value); | ||||
|   bool Get() const; | ||||
|   operator bool() const; | ||||
|   explicit operator bool() const; | ||||
|  | ||||
|  protected: | ||||
|   bool Parse(absl::optional<std::string> str_value) override; | ||||
| @@ -229,7 +230,8 @@ class FieldTrialFlag : public FieldTrialParameterInterface { | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) { | ||||
| absl::optional<absl::optional<T>> ParseOptionalParameter( | ||||
|     absl::string_view str) { | ||||
|   if (str.empty()) | ||||
|     return absl::optional<T>(); | ||||
|   auto parsed = ParseTypedParameter<T>(str); | ||||
| @@ -239,28 +241,29 @@ absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) { | ||||
| } | ||||
|  | ||||
| template <> | ||||
| absl::optional<bool> ParseTypedParameter<bool>(std::string str); | ||||
| absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str); | ||||
| template <> | ||||
| absl::optional<double> ParseTypedParameter<double>(std::string str); | ||||
| absl::optional<double> ParseTypedParameter<double>(absl::string_view str); | ||||
| template <> | ||||
| absl::optional<int> ParseTypedParameter<int>(std::string str); | ||||
| absl::optional<int> ParseTypedParameter<int>(absl::string_view str); | ||||
| template <> | ||||
| absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str); | ||||
| absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str); | ||||
| template <> | ||||
| absl::optional<std::string> ParseTypedParameter<std::string>(std::string str); | ||||
| absl::optional<std::string> ParseTypedParameter<std::string>( | ||||
|     absl::string_view str); | ||||
|  | ||||
| template <> | ||||
| absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>( | ||||
|     std::string str); | ||||
|     absl::string_view str); | ||||
| template <> | ||||
| absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>( | ||||
|     std::string str); | ||||
|     absl::string_view str); | ||||
| template <> | ||||
| absl::optional<absl::optional<unsigned>> | ||||
| ParseTypedParameter<absl::optional<unsigned>>(std::string str); | ||||
| ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str); | ||||
| template <> | ||||
| absl::optional<absl::optional<double>> | ||||
| ParseTypedParameter<absl::optional<double>>(std::string str); | ||||
| ParseTypedParameter<absl::optional<double>>(absl::string_view str); | ||||
|  | ||||
| // Accepts true, false, else parsed with sscanf %i, true if != 0. | ||||
| extern template class FieldTrialParameter<bool>; | ||||
|   | ||||
| @@ -15,7 +15,6 @@ | ||||
| #if RTC_LOG_ENABLED() | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| #include <winsock2.h> | ||||
| #include <windows.h> | ||||
| #if _MSC_VER < 1900 | ||||
| #define snprintf _snprintf | ||||
| @@ -43,6 +42,8 @@ static const int kMaxLogLineSize = 1024 - 60; | ||||
| #include <vector> | ||||
|  | ||||
| #include "absl/base/attributes.h" | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "api/units/timestamp.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/platform_thread_types.h" | ||||
| #include "rtc_base/string_encode.h" | ||||
| @@ -54,15 +55,18 @@ static const int kMaxLogLineSize = 1024 - 60; | ||||
|  | ||||
| namespace rtc { | ||||
| namespace { | ||||
|  | ||||
| // By default, release builds don't log, debug builds at info level | ||||
| #if !defined(NDEBUG) | ||||
| static LoggingSeverity g_min_sev = LS_INFO; | ||||
| static LoggingSeverity g_dbg_sev = LS_INFO; | ||||
| constexpr LoggingSeverity kDefaultLoggingSeverity = LS_INFO; | ||||
| #else | ||||
| static LoggingSeverity g_min_sev = LS_NONE; | ||||
| static LoggingSeverity g_dbg_sev = LS_NONE; | ||||
| constexpr LoggingSeverity kDefaultLoggingSeverity = LS_NONE; | ||||
| #endif | ||||
|  | ||||
| // Note: `g_min_sev` and `g_dbg_sev` can be changed while running. | ||||
| LoggingSeverity g_min_sev = kDefaultLoggingSeverity; | ||||
| LoggingSeverity g_dbg_sev = kDefaultLoggingSeverity; | ||||
|  | ||||
| // Return the filename portion of the string (that following the last slash). | ||||
| const char* FilenameFromPath(const char* file) { | ||||
|   const char* end1 = ::strrchr(file, '/'); | ||||
| @@ -74,11 +78,38 @@ const char* FilenameFromPath(const char* file) { | ||||
| } | ||||
|  | ||||
| // Global lock for log subsystem, only needed to serialize access to streams_. | ||||
| // TODO(bugs.webrtc.org/11665): this is not currently constant initialized and | ||||
| // trivially destructible. | ||||
| webrtc::Mutex g_log_mutex_; | ||||
| webrtc::Mutex& GetLoggingLock() { | ||||
|   static webrtc::Mutex& mutex = *new webrtc::Mutex(); | ||||
|   return mutex; | ||||
| } | ||||
|  | ||||
| }  // namespace | ||||
|  | ||||
| std::string LogLineRef::DefaultLogLine() const { | ||||
|   rtc::StringBuilder log_output; | ||||
|   if (timestamp_ != webrtc::Timestamp::MinusInfinity()) { | ||||
|     // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok. | ||||
|     char timestamp[50];  // Maximum string length of an int64_t is 20. | ||||
|     int len = | ||||
|         snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]", | ||||
|                  timestamp_.ms() / 1000, timestamp_.ms() % 1000); | ||||
|     RTC_DCHECK_LT(len, sizeof(timestamp)); | ||||
|     log_output << timestamp; | ||||
|   } | ||||
|   if (thread_id_.has_value()) { | ||||
|     log_output << "[" << *thread_id_ << "] "; | ||||
|   } | ||||
|   if (!filename_.empty()) { | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|     log_output << "(line " << line_ << "): "; | ||||
| #else | ||||
|     log_output << "(" << filename_ << ":" << line_ << "): "; | ||||
| #endif | ||||
|   } | ||||
|   log_output << message_; | ||||
|   return log_output.Release(); | ||||
| } | ||||
|  | ||||
| ///////////////////////////////////////////////////////////////////////////// | ||||
| // LogMessage | ||||
| ///////////////////////////////////////////////////////////////////////////// | ||||
| @@ -89,12 +120,13 @@ bool LogMessage::log_to_stderr_ = true; | ||||
| // Note: we explicitly do not clean this up, because of the uncertain ordering | ||||
| // of destructors at program exit.  Let the person who sets the stream trigger | ||||
| // cleanup by setting to null, or let it leak (safe at program exit). | ||||
| ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_mutex_) = | ||||
| ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(GetLoggingLock()) = | ||||
|     nullptr; | ||||
| ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true}; | ||||
|  | ||||
| // Boolean options default to false (0) | ||||
| bool LogMessage::thread_, LogMessage::timestamp_; | ||||
| // Boolean options default to false. | ||||
| ABSL_CONST_INIT bool LogMessage::log_thread_ = false; | ||||
| ABSL_CONST_INIT bool LogMessage::log_timestamp_ = false; | ||||
|  | ||||
| LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev) | ||||
|     : LogMessage(file, line, sev, ERRCTX_NONE, 0) {} | ||||
| @@ -103,35 +135,28 @@ LogMessage::LogMessage(const char* file, | ||||
|                        int line, | ||||
|                        LoggingSeverity sev, | ||||
|                        LogErrorContext err_ctx, | ||||
|                        int err) | ||||
|     : severity_(sev) { | ||||
|   if (timestamp_) { | ||||
|                        int err) { | ||||
|   log_line_.set_severity(sev); | ||||
|   if (log_timestamp_) { | ||||
|     int64_t log_start_time = LogStartTime(); | ||||
|     // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp | ||||
|     // in log messages represents the real system time. | ||||
|     int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime()); | ||||
|     int64_t time = TimeDiff(SystemTimeMillis(), log_start_time); | ||||
|     // Also ensure WallClockStartTime is initialized, so that it matches | ||||
|     // LogStartTime. | ||||
|     WallClockStartTime(); | ||||
|     // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok. | ||||
|     char timestamp[50];  // Maximum string length of an int64_t is 20. | ||||
|     int len = | ||||
|         snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]", | ||||
|                  time / 1000, time % 1000); | ||||
|     RTC_DCHECK_LT(len, sizeof(timestamp)); | ||||
|     print_stream_ << timestamp; | ||||
|     log_line_.set_timestamp(webrtc::Timestamp::Millis(time)); | ||||
|   } | ||||
|  | ||||
|   if (thread_) { | ||||
|     PlatformThreadId id = CurrentThreadId(); | ||||
|     print_stream_ << "[" << id << "] "; | ||||
|   if (log_thread_) { | ||||
|     log_line_.set_thread_id(CurrentThreadId()); | ||||
|   } | ||||
|  | ||||
|   if (file != nullptr) { | ||||
|     log_line_.set_filename(FilenameFromPath(file)); | ||||
|     log_line_.set_line(line); | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|     tag_ = FilenameFromPath(file); | ||||
|     print_stream_ << "(line " << line << "): "; | ||||
| #else | ||||
|     print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): "; | ||||
|     log_line_.set_tag(log_line_.filename()); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
| @@ -172,51 +197,32 @@ LogMessage::LogMessage(const char* file, | ||||
|                        int line, | ||||
|                        LoggingSeverity sev, | ||||
|                        const char* tag) | ||||
|     : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) { | ||||
|   tag_ = tag; | ||||
|     : LogMessage(file, line, sev, ERRCTX_NONE, /*err=*/0) { | ||||
|   log_line_.set_tag(tag); | ||||
|   print_stream_ << tag << ": "; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| // DEPRECATED. Currently only used by downstream projects that use | ||||
| // implementation details of logging.h. Work is ongoing to remove those | ||||
| // dependencies. | ||||
| LogMessage::LogMessage(const char* file, | ||||
|                        int line, | ||||
|                        LoggingSeverity sev, | ||||
|                        const std::string& tag) | ||||
|     : LogMessage(file, line, sev) { | ||||
|   print_stream_ << tag << ": "; | ||||
| } | ||||
|  | ||||
| LogMessage::~LogMessage() { | ||||
|   FinishPrintStream(); | ||||
|  | ||||
|   const std::string str = print_stream_.Release(); | ||||
|   log_line_.set_message(print_stream_.Release()); | ||||
|  | ||||
|   if (severity_ >= g_dbg_sev) { | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|     OutputToDebug(str, severity_, tag_); | ||||
| #else | ||||
|     OutputToDebug(str, severity_); | ||||
| #endif | ||||
|   if (log_line_.severity() >= g_dbg_sev) { | ||||
|     OutputToDebug(log_line_); | ||||
|   } | ||||
|  | ||||
|   webrtc::MutexLock lock(&g_log_mutex_); | ||||
|   webrtc::MutexLock lock(&GetLoggingLock()); | ||||
|   for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { | ||||
|     if (severity_ >= entry->min_severity_) { | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|       entry->OnLogMessage(str, severity_, tag_); | ||||
| #else | ||||
|       entry->OnLogMessage(str, severity_); | ||||
| #endif | ||||
|     if (log_line_.severity() >= entry->min_severity_) { | ||||
|       entry->OnLogMessage(log_line_); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void LogMessage::AddTag(const char* tag) { | ||||
| #ifdef WEBRTC_ANDROID | ||||
|   tag_ = tag; | ||||
|   log_line_.set_tag(tag); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @@ -242,16 +248,16 @@ uint32_t LogMessage::WallClockStartTime() { | ||||
| } | ||||
|  | ||||
| void LogMessage::LogThreads(bool on) { | ||||
|   thread_ = on; | ||||
|   log_thread_ = on; | ||||
| } | ||||
|  | ||||
| void LogMessage::LogTimestamps(bool on) { | ||||
|   timestamp_ = on; | ||||
|   log_timestamp_ = on; | ||||
| } | ||||
|  | ||||
| void LogMessage::LogToDebug(LoggingSeverity min_sev) { | ||||
|   g_dbg_sev = min_sev; | ||||
|   webrtc::MutexLock lock(&g_log_mutex_); | ||||
|   webrtc::MutexLock lock(&GetLoggingLock()); | ||||
|   UpdateMinLogSeverity(); | ||||
| } | ||||
|  | ||||
| @@ -260,7 +266,7 @@ void LogMessage::SetLogToStderr(bool log_to_stderr) { | ||||
| } | ||||
|  | ||||
| int LogMessage::GetLogToStream(LogSink* stream) { | ||||
|   webrtc::MutexLock lock(&g_log_mutex_); | ||||
|   webrtc::MutexLock lock(&GetLoggingLock()); | ||||
|   LoggingSeverity sev = LS_NONE; | ||||
|   for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { | ||||
|     if (stream == nullptr || stream == entry) { | ||||
| @@ -271,7 +277,7 @@ int LogMessage::GetLogToStream(LogSink* stream) { | ||||
| } | ||||
|  | ||||
| void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) { | ||||
|   webrtc::MutexLock lock(&g_log_mutex_); | ||||
|   webrtc::MutexLock lock(&GetLoggingLock()); | ||||
|   stream->min_severity_ = min_sev; | ||||
|   stream->next_ = streams_; | ||||
|   streams_ = stream; | ||||
| @@ -280,7 +286,7 @@ void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) { | ||||
| } | ||||
|  | ||||
| void LogMessage::RemoveLogToStream(LogSink* stream) { | ||||
|   webrtc::MutexLock lock(&g_log_mutex_); | ||||
|   webrtc::MutexLock lock(&GetLoggingLock()); | ||||
|   for (LogSink** entry = &streams_; *entry != nullptr; | ||||
|        entry = &(*entry)->next_) { | ||||
|     if (*entry == stream) { | ||||
| @@ -292,7 +298,7 @@ void LogMessage::RemoveLogToStream(LogSink* stream) { | ||||
|   UpdateMinLogSeverity(); | ||||
| } | ||||
|  | ||||
| void LogMessage::ConfigureLogging(const char* params) { | ||||
| void LogMessage::ConfigureLogging(absl::string_view params) { | ||||
|   LoggingSeverity current_level = LS_VERBOSE; | ||||
|   LoggingSeverity debug_level = GetLogToDebug(); | ||||
|  | ||||
| @@ -342,7 +348,7 @@ void LogMessage::ConfigureLogging(const char* params) { | ||||
| } | ||||
|  | ||||
| void LogMessage::UpdateMinLogSeverity() | ||||
|     RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) { | ||||
|     RTC_EXCLUSIVE_LOCKS_REQUIRED(GetLoggingLock()) { | ||||
|   LoggingSeverity min_sev = g_dbg_sev; | ||||
|   for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { | ||||
|     min_sev = std::min(min_sev, entry->min_severity_); | ||||
| @@ -350,46 +356,35 @@ void LogMessage::UpdateMinLogSeverity() | ||||
|   g_min_sev = min_sev; | ||||
| } | ||||
|  | ||||
| #if defined(WEBRTC_ANDROID) | ||||
| void LogMessage::OutputToDebug(const std::string& str, | ||||
|                                LoggingSeverity severity, | ||||
|                                const char* tag) { | ||||
| #else | ||||
| void LogMessage::OutputToDebug(const std::string& str, | ||||
|                                LoggingSeverity severity) { | ||||
| #endif | ||||
| void LogMessage::OutputToDebug(const LogLineRef& log_line) { | ||||
|   std::string msg_str = log_line.DefaultLogLine(); | ||||
|   bool log_to_stderr = log_to_stderr_; | ||||
| #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG) | ||||
|   // On the Mac, all stderr output goes to the Console log and causes clutter. | ||||
|   // So in opt builds, don't log to stderr unless the user specifically sets | ||||
|   // a preference to do so. | ||||
|   CFStringRef key = CFStringCreateWithCString( | ||||
|       kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8); | ||||
|   CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle()); | ||||
|   if (key != nullptr && domain != nullptr) { | ||||
|   if (domain != nullptr) { | ||||
|     Boolean exists_and_is_valid; | ||||
|     Boolean should_log = | ||||
|         CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid); | ||||
|     Boolean should_log = CFPreferencesGetAppBooleanValue( | ||||
|         CFSTR("logToStdErr"), domain, &exists_and_is_valid); | ||||
|     // If the key doesn't exist or is invalid or is false, we will not log to | ||||
|     // stderr. | ||||
|     log_to_stderr = exists_and_is_valid && should_log; | ||||
|   } | ||||
|   if (key != nullptr) { | ||||
|     CFRelease(key); | ||||
|   } | ||||
| #endif  // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG) | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
|   // Always log to the debugger. | ||||
|   // Perhaps stderr should be controlled by a preference, as on Mac? | ||||
|   OutputDebugStringA(str.c_str()); | ||||
|   OutputDebugStringA(msg_str.c_str()); | ||||
|   if (log_to_stderr) { | ||||
|     // This handles dynamically allocated consoles, too. | ||||
|     if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) { | ||||
|       log_to_stderr = false; | ||||
|       DWORD written = 0; | ||||
|       ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()), | ||||
|                   &written, 0); | ||||
|       ::WriteFile(error_handle, msg_str.c_str(), | ||||
|                   static_cast<DWORD>(msg_str.size()), &written, 0); | ||||
|     } | ||||
|   } | ||||
| #endif  // WEBRTC_WIN | ||||
| @@ -400,7 +395,7 @@ void LogMessage::OutputToDebug(const std::string& str, | ||||
|   // Also write to stderr which maybe available to executable started | ||||
|   // from the shell. | ||||
|   int prio; | ||||
|   switch (severity) { | ||||
|   switch (log_line.severity()) { | ||||
|     case LS_VERBOSE: | ||||
|       prio = ANDROID_LOG_VERBOSE; | ||||
|       break; | ||||
| @@ -417,27 +412,29 @@ void LogMessage::OutputToDebug(const std::string& str, | ||||
|       prio = ANDROID_LOG_UNKNOWN; | ||||
|   } | ||||
|  | ||||
|   int size = str.size(); | ||||
|   int line = 0; | ||||
|   int size = msg_str.size(); | ||||
|   int current_line = 0; | ||||
|   int idx = 0; | ||||
|   const int max_lines = size / kMaxLogLineSize + 1; | ||||
|   if (max_lines == 1) { | ||||
|     __android_log_print(prio, tag, "%.*s", size, str.c_str()); | ||||
|     __android_log_print(prio, log_line.tag().data(), "%.*s", size, | ||||
|                         msg_str.c_str()); | ||||
|   } else { | ||||
|     while (size > 0) { | ||||
|       const int len = std::min(size, kMaxLogLineSize); | ||||
|       // Use the size of the string in the format (str may have \0 in the | ||||
|       // Use the size of the string in the format (msg may have \0 in the | ||||
|       // middle). | ||||
|       __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len, | ||||
|                           str.c_str() + idx); | ||||
|       __android_log_print(prio, log_line.tag().data(), "[%d/%d] %.*s", | ||||
|                           current_line + 1, max_lines, len, | ||||
|                           msg_str.c_str() + idx); | ||||
|       idx += len; | ||||
|       size -= len; | ||||
|       ++line; | ||||
|       ++current_line; | ||||
|     } | ||||
|   } | ||||
| #endif  // WEBRTC_ANDROID | ||||
|   if (log_to_stderr) { | ||||
|     fprintf(stderr, "%s", str.c_str()); | ||||
|     fprintf(stderr, "%s", msg_str.c_str()); | ||||
|     fflush(stderr); | ||||
|   } | ||||
| } | ||||
| @@ -481,7 +478,7 @@ void Log(const LogArgType* fmt, ...) { | ||||
|     } | ||||
| #endif | ||||
|     default: { | ||||
|       RTC_NOTREACHED(); | ||||
|       RTC_DCHECK_NOTREACHED(); | ||||
|       va_end(args); | ||||
|       return; | ||||
|     } | ||||
| @@ -535,7 +532,7 @@ void Log(const LogArgType* fmt, ...) { | ||||
|             reinterpret_cast<uintptr_t>(va_arg(args, const void*))); | ||||
|         break; | ||||
|       default: | ||||
|         RTC_NOTREACHED(); | ||||
|         RTC_DCHECK_NOTREACHED(); | ||||
|         va_end(args); | ||||
|         return; | ||||
|     } | ||||
| @@ -549,6 +546,16 @@ void Log(const LogArgType* fmt, ...) { | ||||
| #endif | ||||
|  | ||||
| namespace rtc { | ||||
| // Default implementation, override is recomended. | ||||
| void LogSink::OnLogMessage(const LogLineRef& log_line) { | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   OnLogMessage(log_line.DefaultLogLine(), log_line.severity(), | ||||
|                log_line.tag().data()); | ||||
| #else | ||||
|   OnLogMessage(log_line.DefaultLogLine(), log_line.severity()); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| // Inefficient default implementation, override is recommended. | ||||
| void LogSink::OnLogMessage(const std::string& msg, | ||||
|                            LoggingSeverity severity, | ||||
| @@ -560,4 +567,20 @@ void LogSink::OnLogMessage(const std::string& msg, | ||||
|                            LoggingSeverity /* severity */) { | ||||
|   OnLogMessage(msg); | ||||
| } | ||||
|  | ||||
| // Inefficient default implementation, override is recommended. | ||||
| void LogSink::OnLogMessage(absl::string_view msg, | ||||
|                            LoggingSeverity severity, | ||||
|                            const char* tag) { | ||||
|   OnLogMessage(tag + (": " + std::string(msg)), severity); | ||||
| } | ||||
|  | ||||
| void LogSink::OnLogMessage(absl::string_view msg, | ||||
|                            LoggingSeverity /* severity */) { | ||||
|   OnLogMessage(msg); | ||||
| } | ||||
|  | ||||
| void LogSink::OnLogMessage(absl::string_view msg) { | ||||
|   OnLogMessage(std::string(msg)); | ||||
| } | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -21,9 +21,13 @@ | ||||
| // RTC_LOG(sev) logs the given stream at severity "sev", which must be a | ||||
| //     compile-time constant of the LoggingSeverity type, without the namespace | ||||
| //     prefix. | ||||
| // RTC_LOG_IF(sev, condition) logs the given stream at severitye "sev" if | ||||
| //     "condition" is true. | ||||
| // RTC_LOG_V(sev) Like RTC_LOG(), but sev is a run-time variable of the | ||||
| //     LoggingSeverity type (basically, it just doesn't prepend the namespace). | ||||
| // RTC_LOG_F(sev) Like RTC_LOG(), but includes the name of the current function. | ||||
| // RTC_LOG_IF_F(sev, condition), Like RTC_LOG_IF(), but includes the name of | ||||
| //     the current function. | ||||
| // RTC_LOG_T(sev) Like RTC_LOG(), but includes the this pointer. | ||||
| // RTC_LOG_T_F(sev) Like RTC_LOG_F(), but includes the this pointer. | ||||
| // RTC_LOG_GLE(sev [, mod]) attempt to add a string description of the | ||||
| @@ -49,12 +53,15 @@ | ||||
| #include <atomic> | ||||
| #include <sstream>  // no-presubmit-check TODO(webrtc:8982) | ||||
| #include <string> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
|  | ||||
| #include "absl/base/attributes.h" | ||||
| #include "absl/meta/type_traits.h" | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "rtc_base/constructor_magic.h" | ||||
| #include "rtc_base/deprecation.h" | ||||
| #include "absl/types/optional.h" | ||||
| #include "api/units/timestamp.h" | ||||
| #include "rtc_base/platform_thread_types.h" | ||||
| #include "rtc_base/strings/string_builder.h" | ||||
| #include "rtc_base/system/inline.h" | ||||
|  | ||||
| @@ -73,9 +80,7 @@ | ||||
| namespace rtc { | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| // Note that the non-standard LoggingSeverity aliases exist because they are | ||||
| // still in broad use.  The meanings of the levels are: | ||||
| // The meanings of the levels are: | ||||
| //  LS_VERBOSE: This level is for data which we do not want to appear in the | ||||
| //   normal debug log, but should appear in diagnostic logs. | ||||
| //  LS_INFO: Chatty level used in debugging for all sorts of things, the default | ||||
| @@ -89,9 +94,6 @@ enum LoggingSeverity { | ||||
|   LS_WARNING, | ||||
|   LS_ERROR, | ||||
|   LS_NONE, | ||||
|   INFO = LS_INFO, | ||||
|   WARNING = LS_WARNING, | ||||
|   LERROR = LS_ERROR | ||||
| }; | ||||
|  | ||||
| // LogErrorContext assists in interpreting the meaning of an error value. | ||||
| @@ -106,6 +108,50 @@ enum LogErrorContext { | ||||
| }; | ||||
|  | ||||
| class LogMessage; | ||||
|  | ||||
| // LogLineRef encapsulates all the information required to generate a log line. | ||||
| // It is used both internally to LogMessage but also as a parameter to | ||||
| // LogSink::OnLogMessage, allowing custom LogSinks to format the log in | ||||
| // the most flexible way. | ||||
| class LogLineRef { | ||||
|  public: | ||||
|   absl::string_view message() const { return message_; } | ||||
|   absl::string_view filename() const { return filename_; } | ||||
|   int line() const { return line_; } | ||||
|   absl::optional<PlatformThreadId> thread_id() const { return thread_id_; } | ||||
|   webrtc::Timestamp timestamp() const { return timestamp_; } | ||||
|   absl::string_view tag() const { return tag_; } | ||||
|   LoggingSeverity severity() const { return severity_; } | ||||
|  | ||||
| #if RTC_LOG_ENABLED() | ||||
|   std::string DefaultLogLine() const; | ||||
| #else | ||||
|   std::string DefaultLogLine() const { return ""; } | ||||
| #endif | ||||
|  | ||||
|  private: | ||||
|   friend class LogMessage; | ||||
|   void set_message(std::string message) { message_ = std::move(message); } | ||||
|   void set_filename(absl::string_view filename) { filename_ = filename; } | ||||
|   void set_line(int line) { line_ = line; } | ||||
|   void set_thread_id(absl::optional<PlatformThreadId> thread_id) { | ||||
|     thread_id_ = thread_id; | ||||
|   } | ||||
|   void set_timestamp(webrtc::Timestamp timestamp) { timestamp_ = timestamp; } | ||||
|   void set_tag(absl::string_view tag) { tag_ = tag; } | ||||
|   void set_severity(LoggingSeverity severity) { severity_ = severity; } | ||||
|  | ||||
|   std::string message_; | ||||
|   absl::string_view filename_; | ||||
|   int line_ = 0; | ||||
|   absl::optional<PlatformThreadId> thread_id_; | ||||
|   webrtc::Timestamp timestamp_ = webrtc::Timestamp::MinusInfinity(); | ||||
|   // The default Android debug output tag. | ||||
|   absl::string_view tag_ = "libjingle"; | ||||
|   // The severity level of this message | ||||
|   LoggingSeverity severity_; | ||||
| }; | ||||
|  | ||||
| // Virtual sink interface that can receive log messages. | ||||
| class LogSink { | ||||
|  public: | ||||
| @@ -118,6 +164,14 @@ class LogSink { | ||||
|                             LoggingSeverity severity); | ||||
|   virtual void OnLogMessage(const std::string& message) = 0; | ||||
|  | ||||
|   virtual void OnLogMessage(absl::string_view msg, | ||||
|                             LoggingSeverity severity, | ||||
|                             const char* tag); | ||||
|   virtual void OnLogMessage(absl::string_view message, | ||||
|                             LoggingSeverity severity); | ||||
|   virtual void OnLogMessage(absl::string_view message); | ||||
|   virtual void OnLogMessage(const LogLineRef& line); | ||||
|  | ||||
|  private: | ||||
|   friend class ::rtc::LogMessage; | ||||
| #if RTC_LOG_ENABLED() | ||||
| @@ -276,8 +330,15 @@ inline Val<LogArgType::kLogMetadataTag, LogMetadataTag> MakeVal( | ||||
| template <typename T, class = void> | ||||
| struct has_to_log_string : std::false_type {}; | ||||
| template <typename T> | ||||
| struct has_to_log_string<T, decltype(ToLogString(std::declval<T>()))> | ||||
|     : std::true_type {}; | ||||
| struct has_to_log_string<T, | ||||
|                          absl::enable_if_t<std::is_convertible< | ||||
|                              decltype(ToLogString(std::declval<T>())), | ||||
|                              std::string>::value>> : std::true_type {}; | ||||
|  | ||||
| template <typename T, absl::enable_if_t<has_to_log_string<T>::value>* = nullptr> | ||||
| ToStringVal MakeVal(const T& x) { | ||||
|   return {ToLogString(x)}; | ||||
| } | ||||
|  | ||||
| // Handle arbitrary types other than the above by falling back to stringstream. | ||||
| // TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need | ||||
| @@ -299,11 +360,6 @@ ToStringVal MakeVal(const T& x) { | ||||
|   return {os.str()}; | ||||
| } | ||||
|  | ||||
| template <typename T, absl::enable_if_t<has_to_log_string<T>::value>* = nullptr> | ||||
| ToStringVal MakeVal(const T& x) { | ||||
|   return {ToLogString(x)}; | ||||
| } | ||||
|  | ||||
| #if RTC_LOG_ENABLED() | ||||
| void Log(const LogArgType* fmt, ...); | ||||
| #else | ||||
| @@ -431,16 +487,11 @@ class LogMessage { | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag); | ||||
| #endif | ||||
|   // DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS. | ||||
|   // Android code should use the 'const char*' version since tags are static | ||||
|   // and we want to avoid allocating a std::string copy per log line. | ||||
|   RTC_DEPRECATED | ||||
|   LogMessage(const char* file, | ||||
|              int line, | ||||
|              LoggingSeverity sev, | ||||
|              const std::string& tag); | ||||
|   ~LogMessage(); | ||||
|  | ||||
|   LogMessage(const LogMessage&) = delete; | ||||
|   LogMessage& operator=(const LogMessage&) = delete; | ||||
|  | ||||
|   void AddTag(const char* tag); | ||||
|   rtc::StringBuilder& stream(); | ||||
|   // Returns the time at which this function was called for the first time. | ||||
| @@ -449,7 +500,7 @@ class LogMessage { | ||||
|   // which case the logging start time will be the time of the first LogMessage | ||||
|   // instance is created. | ||||
|   static int64_t LogStartTime(); | ||||
|   // Returns the wall clock equivalent of |LogStartTime|, in seconds from the | ||||
|   // Returns the wall clock equivalent of `LogStartTime`, in seconds from the | ||||
|   // epoch. | ||||
|   static uint32_t WallClockStartTime(); | ||||
|   //  LogThreads: Display the thread identifier of the current thread | ||||
| @@ -463,14 +514,14 @@ class LogMessage { | ||||
|   // Sets whether logs will be directed to stderr in debug mode. | ||||
|   static void SetLogToStderr(bool log_to_stderr); | ||||
|   // Stream: Any non-blocking stream interface. | ||||
|   // Installs the |stream| to collect logs with severtiy |min_sev| or higher. | ||||
|   // |stream| must live until deinstalled by RemoveLogToStream. | ||||
|   // If |stream| is the first stream added to the system, we might miss some | ||||
|   // Installs the `stream` to collect logs with severtiy `min_sev` or higher. | ||||
|   // `stream` must live until deinstalled by RemoveLogToStream. | ||||
|   // If `stream` is the first stream added to the system, we might miss some | ||||
|   // early concurrent log statement happening from another thread happening near | ||||
|   // this instant. | ||||
|   static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev); | ||||
|   // Removes the specified stream, without destroying it. When the method | ||||
|   // has completed, it's guaranteed that |stream| will receive no more logging | ||||
|   // has completed, it's guaranteed that `stream` will receive no more logging | ||||
|   // calls. | ||||
|   static void RemoveLogToStream(LogSink* stream); | ||||
|   // Returns the severity for the specified stream, of if none is specified, | ||||
| @@ -481,10 +532,10 @@ class LogMessage { | ||||
|   static int GetMinLogSeverity(); | ||||
|   // Parses the provided parameter stream to configure the options above. | ||||
|   // Useful for configuring logging from the command line. | ||||
|   static void ConfigureLogging(const char* params); | ||||
|   // Checks the current global debug severity and if the |streams_| collection | ||||
|   // is empty. If |severity| is smaller than the global severity and if the | ||||
|   // |streams_| collection is empty, the LogMessage will be considered a noop | ||||
|   static void ConfigureLogging(absl::string_view params); | ||||
|   // Checks the current global debug severity and if the `streams_` collection | ||||
|   // is empty. If `severity` is smaller than the global severity and if the | ||||
|   // `streams_` collection is empty, the LogMessage will be considered a noop | ||||
|   // LogMessage. | ||||
|   static bool IsNoop(LoggingSeverity severity); | ||||
|   // Version of IsNoop that uses fewer instructions at the call site, since the | ||||
| @@ -505,14 +556,6 @@ class LogMessage { | ||||
|   LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag) { | ||||
|   } | ||||
| #endif | ||||
|   // DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS. | ||||
|   // Android code should use the 'const char*' version since tags are static | ||||
|   // and we want to avoid allocating a std::string copy per log line. | ||||
|   RTC_DEPRECATED | ||||
|   LogMessage(const char* file, | ||||
|              int line, | ||||
|              LoggingSeverity sev, | ||||
|              const std::string& tag) {} | ||||
|   ~LogMessage() = default; | ||||
|  | ||||
|   inline void AddTag(const char* tag) {} | ||||
| @@ -530,7 +573,7 @@ class LogMessage { | ||||
|   inline static void RemoveLogToStream(LogSink* stream) {} | ||||
|   inline static int GetLogToStream(LogSink* stream = nullptr) { return 0; } | ||||
|   inline static int GetMinLogSeverity() { return 0; } | ||||
|   inline static void ConfigureLogging(const char* params) {} | ||||
|   inline static void ConfigureLogging(absl::string_view params) {} | ||||
|   static constexpr bool IsNoop(LoggingSeverity severity) { return true; } | ||||
|   template <LoggingSeverity S> | ||||
|   static constexpr bool IsNoop() { | ||||
| @@ -545,26 +588,14 @@ class LogMessage { | ||||
|   // Updates min_sev_ appropriately when debug sinks change. | ||||
|   static void UpdateMinLogSeverity(); | ||||
|  | ||||
| // These write out the actual log messages. | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   static void OutputToDebug(const std::string& msg, | ||||
|                             LoggingSeverity severity, | ||||
|                             const char* tag); | ||||
| #else | ||||
|   static void OutputToDebug(const std::string& msg, LoggingSeverity severity); | ||||
| #endif  // defined(WEBRTC_ANDROID) | ||||
|   // This writes out the actual log messages. | ||||
|   static void OutputToDebug(const LogLineRef& log_line_ref); | ||||
|  | ||||
|   // Called from the dtor (or from a test) to append optional extra error | ||||
|   // information to the log stream and a newline character. | ||||
|   void FinishPrintStream(); | ||||
|  | ||||
|   // The severity level of this message | ||||
|   LoggingSeverity severity_; | ||||
|  | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   // The default Android debug output tag. | ||||
|   const char* tag_ = "libjingle"; | ||||
| #endif | ||||
|   LogLineRef log_line_; | ||||
|  | ||||
|   // String data generated in the constructor, that should be appended to | ||||
|   // the message before output. | ||||
| @@ -573,14 +604,15 @@ class LogMessage { | ||||
|   // The output streams and their associated severities | ||||
|   static LogSink* streams_; | ||||
|  | ||||
|   // Holds true with high probability if |streams_| is empty, false with high | ||||
|   // Holds true with high probability if `streams_` is empty, false with high | ||||
|   // probability otherwise. Operated on with std::memory_order_relaxed because | ||||
|   // it's ok to lose or log some additional statements near the instant streams | ||||
|   // are added/removed. | ||||
|   static std::atomic<bool> streams_empty_; | ||||
|  | ||||
|   // Flags for formatting options | ||||
|   static bool thread_, timestamp_; | ||||
|   // Flags for formatting options and their potential values. | ||||
|   static bool log_thread_; | ||||
|   static bool log_timestamp_; | ||||
|  | ||||
|   // Determines if logs will be directed to stderr in debug mode. | ||||
|   static bool log_to_stderr_; | ||||
| @@ -588,11 +620,15 @@ class LogMessage { | ||||
|   // Next methods do nothing; no one will call these functions. | ||||
|   inline static void UpdateMinLogSeverity() {} | ||||
| #if defined(WEBRTC_ANDROID) | ||||
|   inline static void OutputToDebug(const std::string& msg, | ||||
|   inline static void OutputToDebug(absl::string_view filename, | ||||
|                                    int line, | ||||
|                                    absl::string_view msg, | ||||
|                                    LoggingSeverity severity, | ||||
|                                    const char* tag) {} | ||||
| #else | ||||
|   inline static void OutputToDebug(const std::string& msg, | ||||
|   inline static void OutputToDebug(absl::string_view filename, | ||||
|                                    int line, | ||||
|                                    absl::string_view msg, | ||||
|                                    LoggingSeverity severity) {} | ||||
| #endif  // defined(WEBRTC_ANDROID) | ||||
|   inline void FinishPrintStream() {} | ||||
| @@ -600,8 +636,6 @@ class LogMessage { | ||||
|  | ||||
|   // The stringbuilder that buffers the formatted message before output | ||||
|   rtc::StringBuilder print_stream_; | ||||
|  | ||||
|   RTC_DISALLOW_COPY_AND_ASSIGN(LogMessage); | ||||
| }; | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////// | ||||
| @@ -613,21 +647,29 @@ class LogMessage { | ||||
|       ::rtc::webrtc_logging_impl::LogStreamer<>() \ | ||||
|           << ::rtc::webrtc_logging_impl::LogMetadata(file, line, sev) | ||||
|  | ||||
| #define RTC_LOG(sev)                        \ | ||||
|   !rtc::LogMessage::IsNoop<::rtc::sev>() && \ | ||||
| #define RTC_LOG(sev)                          \ | ||||
|   !::rtc::LogMessage::IsNoop<::rtc::sev>() && \ | ||||
|       RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__) | ||||
|  | ||||
| #define RTC_LOG_IF(sev, condition)                           \ | ||||
|   !::rtc::LogMessage::IsNoop<::rtc::sev>() && (condition) && \ | ||||
|       RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__) | ||||
|  | ||||
| // The _V version is for when a variable is passed in. | ||||
| #define RTC_LOG_V(sev) \ | ||||
|   !rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__) | ||||
|   !::rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__) | ||||
|  | ||||
| // The _F version prefixes the message with the current function name. | ||||
| #if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F) | ||||
| #define RTC_LOG_F(sev) RTC_LOG(sev) << __PRETTY_FUNCTION__ << ": " | ||||
| #define RTC_LOG_IF_F(sev, condition) \ | ||||
|   RTC_LOG_IF(sev, condition) << __PRETTY_FUNCTION__ << ": " | ||||
| #define RTC_LOG_T_F(sev) \ | ||||
|   RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": " | ||||
| #else | ||||
| #define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": " | ||||
| #define RTC_LOG_IF_F(sev, condition) \ | ||||
|   RTC_LOG_IF(sev, condition) << __FUNCTION__ << ": " | ||||
| #define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": " | ||||
| #endif | ||||
|  | ||||
| @@ -639,7 +681,7 @@ inline bool LogCheckLevel(LoggingSeverity sev) { | ||||
| } | ||||
|  | ||||
| #define RTC_LOG_E(sev, ctx, err)                                 \ | ||||
|   !rtc::LogMessage::IsNoop<::rtc::sev>() &&                      \ | ||||
|   !::rtc::LogMessage::IsNoop<::rtc::sev>() &&                    \ | ||||
|       ::rtc::webrtc_logging_impl::LogCall() &                    \ | ||||
|           ::rtc::webrtc_logging_impl::LogStreamer<>()            \ | ||||
|               << ::rtc::webrtc_logging_impl::LogMetadataErr {    \ | ||||
| @@ -677,7 +719,7 @@ inline const char* AdaptString(const std::string& str) { | ||||
| }  // namespace webrtc_logging_impl | ||||
|  | ||||
| #define RTC_LOG_TAG(sev, tag)                                 \ | ||||
|   !rtc::LogMessage::IsNoop(sev) &&                            \ | ||||
|   !::rtc::LogMessage::IsNoop(sev) &&                          \ | ||||
|       ::rtc::webrtc_logging_impl::LogCall() &                 \ | ||||
|           ::rtc::webrtc_logging_impl::LogStreamer<>()         \ | ||||
|               << ::rtc::webrtc_logging_impl::LogMetadataTag { \ | ||||
| @@ -695,16 +737,20 @@ inline const char* AdaptString(const std::string& str) { | ||||
| // they only generate code in debug builds. | ||||
| #if RTC_DLOG_IS_ON | ||||
| #define RTC_DLOG(sev) RTC_LOG(sev) | ||||
| #define RTC_DLOG_IF(sev, condition) RTC_LOG_IF(sev, condition) | ||||
| #define RTC_DLOG_V(sev) RTC_LOG_V(sev) | ||||
| #define RTC_DLOG_F(sev) RTC_LOG_F(sev) | ||||
| #define RTC_DLOG_IF_F(sev, condition) RTC_LOG_IF_F(sev, condition) | ||||
| #else | ||||
| #define RTC_DLOG_EAT_STREAM_PARAMS()                \ | ||||
|   while (false)                                     \ | ||||
|   ::rtc::webrtc_logging_impl::LogMessageVoidify() & \ | ||||
|       (::rtc::webrtc_logging_impl::LogStreamer<>()) | ||||
| #define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS() | ||||
| #define RTC_DLOG_IF(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS() | ||||
| #define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS() | ||||
| #define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS() | ||||
| #define RTC_DLOG_IF_F(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS() | ||||
| #endif | ||||
|  | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -21,24 +21,22 @@ rtc_library("aligned_malloc") { | ||||
| } | ||||
|  | ||||
| # Test only utility. | ||||
| # TODO: Tag with `testonly = true` once all depending targets are correctly | ||||
| # tagged. | ||||
| rtc_library("fifo_buffer") { | ||||
|   testonly = true | ||||
|   visibility = [ | ||||
|     ":unittests", | ||||
|     "..:rtc_base_tests_utils", | ||||
|     "..:rtc_base_unittests", | ||||
|     "../../p2p:rtc_p2p",  # This needs to be fixed. | ||||
|   ] | ||||
|   sources = [ | ||||
|     "fifo_buffer.cc", | ||||
|     "fifo_buffer.h", | ||||
|   ] | ||||
|   deps = [ | ||||
|     "..:rtc_base", | ||||
|     "..:stream", | ||||
|     "..:threading", | ||||
|     "../../api/task_queue:pending_task_safety_flag", | ||||
|     "../synchronization:mutex", | ||||
|     "../task_utils:pending_task_safety_flag", | ||||
|     "../task_utils:to_queued_task", | ||||
|   ] | ||||
| } | ||||
|  | ||||
| @@ -46,11 +44,18 @@ rtc_library("unittests") { | ||||
|   testonly = true | ||||
|   sources = [ | ||||
|     "aligned_malloc_unittest.cc", | ||||
|     "always_valid_pointer_unittest.cc", | ||||
|     "fifo_buffer_unittest.cc", | ||||
|   ] | ||||
|   deps = [ | ||||
|     ":aligned_malloc", | ||||
|     ":always_valid_pointer", | ||||
|     ":fifo_buffer", | ||||
|     "../../test:test_support", | ||||
|   ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("always_valid_pointer") { | ||||
|   sources = [ "always_valid_pointer.h" ] | ||||
|   deps = [ "..:checks" ] | ||||
| } | ||||
|   | ||||
| @@ -26,7 +26,7 @@ | ||||
| namespace webrtc { | ||||
|  | ||||
| uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) { | ||||
|   // The pointer should be aligned with |alignment| bytes. The - 1 guarantees | ||||
|   // The pointer should be aligned with `alignment` bytes. The - 1 guarantees | ||||
|   // that it is aligned towards the closest higher (right) address. | ||||
|   return (start_pos + alignment - 1) & ~(alignment - 1); | ||||
| } | ||||
|   | ||||
| @@ -21,13 +21,13 @@ | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| // Returns a pointer to the first boundry of |alignment| bytes following the | ||||
| // address of |ptr|. | ||||
| // Returns a pointer to the first boundry of `alignment` bytes following the | ||||
| // address of `ptr`. | ||||
| // Note that there is no guarantee that the memory in question is available. | ||||
| // |ptr| has no requirements other than it can't be NULL. | ||||
| // `ptr` has no requirements other than it can't be NULL. | ||||
| void* GetRightAlign(const void* ptr, size_t alignment); | ||||
|  | ||||
| // Allocates memory of |size| bytes aligned on an |alignment| boundry. | ||||
| // Allocates memory of `size` bytes aligned on an `alignment` boundry. | ||||
| // The return value is a pointer to the memory. Note that the memory must | ||||
| // be de-allocated using AlignedFree. | ||||
| void* AlignedMalloc(size_t size, size_t alignment); | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| base_sources = [ | ||||
|   'checks.cc', | ||||
|   'containers/flat_tree.cc', | ||||
|   'event.cc', | ||||
|   'event_tracer.cc', | ||||
|   'experiments/field_trial_parser.cc', | ||||
| @@ -8,15 +9,16 @@ base_sources = [ | ||||
|   'platform_thread.cc', | ||||
|   'platform_thread_types.cc', | ||||
|   'race_checker.cc', | ||||
|   'random.cc', | ||||
|   'string_encode.cc', | ||||
|   'string_to_number.cc', | ||||
|   'string_utils.cc', | ||||
|   'strings/string_builder.cc', | ||||
|   'synchronization/mutex.cc', | ||||
|   'synchronization/rw_lock_wrapper.cc', | ||||
|   'synchronization/sequence_checker_internal.cc', | ||||
|   'synchronization/yield.cc', | ||||
|   'synchronization/yield_policy.cc', | ||||
|   'system/file_wrapper.cc', | ||||
|   'system_time.cc', | ||||
|   'time_utils.cc', | ||||
|   'zero_memory.cc', | ||||
| ] | ||||
| @@ -24,8 +26,6 @@ base_sources = [ | ||||
| base_headers = [ | ||||
|   [ '', 'arraysize.h' ], | ||||
|   [ '', 'checks.h' ], | ||||
|   [ '', 'constructor_magic.h' ], | ||||
|   [ '', 'deprecation.h' ], | ||||
|   [ '', 'ref_count.h' ], | ||||
|   [ '', 'type_traits.h' ], | ||||
|   [ 'numerics', 'safe_compare.h' ], | ||||
| @@ -34,16 +34,6 @@ base_headers = [ | ||||
|   [ 'system', 'rtc_export.h' ], | ||||
| ] | ||||
|  | ||||
| if have_posix | ||||
|   base_sources += [ | ||||
|     'synchronization/rw_lock_posix.cc', | ||||
|   ] | ||||
| elif have_win | ||||
|   base_sources += [ | ||||
|     'synchronization/rw_lock_win.cc', | ||||
|   ] | ||||
| endif | ||||
|  | ||||
| foreach h : base_headers | ||||
|   install_headers( | ||||
|     join_paths(h[0], h[1]), | ||||
| @@ -64,6 +54,10 @@ elif host_system == 'ios' | ||||
|       'UIKit', | ||||
|     ] | ||||
|   ) | ||||
| elif host_system == 'android' | ||||
|   base_sources += [ | ||||
|     'system/warn_current_thread_is_deadlocked.cc', | ||||
|   ] | ||||
| endif | ||||
|  | ||||
| libbase = static_library('libbase', | ||||
|   | ||||
							
								
								
									
										60
									
								
								webrtc/rtc_base/numerics/divide_round.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								webrtc/rtc_base/numerics/divide_round.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| /* | ||||
|  *  Copyright 2019 The WebRTC Project Authors. All rights reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_NUMERICS_DIVIDE_ROUND_H_ | ||||
| #define RTC_BASE_NUMERICS_DIVIDE_ROUND_H_ | ||||
|  | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/numerics/safe_compare.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| template <typename Dividend, typename Divisor> | ||||
| inline auto constexpr DivideRoundUp(Dividend dividend, Divisor divisor) { | ||||
|   static_assert(std::is_integral<Dividend>(), ""); | ||||
|   static_assert(std::is_integral<Divisor>(), ""); | ||||
|   RTC_DCHECK_GE(dividend, 0); | ||||
|   RTC_DCHECK_GT(divisor, 0); | ||||
|  | ||||
|   auto quotient = dividend / divisor; | ||||
|   auto remainder = dividend % divisor; | ||||
|   return quotient + (remainder > 0 ? 1 : 0); | ||||
| } | ||||
|  | ||||
| template <typename Dividend, typename Divisor> | ||||
| inline auto constexpr DivideRoundToNearest(Dividend dividend, Divisor divisor) { | ||||
|   static_assert(std::is_integral<Dividend>(), ""); | ||||
|   static_assert(std::is_integral<Divisor>(), ""); | ||||
|   RTC_DCHECK_GT(divisor, 0); | ||||
|  | ||||
|   if (dividend < Dividend{0}) { | ||||
|     auto half_of_divisor = divisor / 2; | ||||
|     auto quotient = dividend / divisor; | ||||
|     auto remainder = dividend % divisor; | ||||
|     if (rtc::SafeGt(-remainder, half_of_divisor)) { | ||||
|       --quotient; | ||||
|     } | ||||
|     return quotient; | ||||
|   } | ||||
|  | ||||
|   auto half_of_divisor = (divisor - 1) / 2; | ||||
|   auto quotient = dividend / divisor; | ||||
|   auto remainder = dividend % divisor; | ||||
|   if (rtc::SafeGt(remainder, half_of_divisor)) { | ||||
|     ++quotient; | ||||
|   } | ||||
|   return quotient; | ||||
| } | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_NUMERICS_DIVIDE_ROUND_H_ | ||||
| @@ -63,12 +63,10 @@ inline constexpr Dst saturated_cast(Src value) { | ||||
|  | ||||
|     // Should fail only on attempting to assign NaN to a saturated integer. | ||||
|     case internal::TYPE_INVALID: | ||||
|       FATAL(); | ||||
|       return std::numeric_limits<Dst>::max(); | ||||
|       RTC_CHECK_NOTREACHED(); | ||||
|   } | ||||
|  | ||||
|   FATAL(); | ||||
|   return static_cast<Dst>(value); | ||||
|   RTC_CHECK_NOTREACHED(); | ||||
| } | ||||
|  | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -325,9 +325,9 @@ R2 SafeClamp(T x, L min, H max) { | ||||
|   static_assert(IsIntlike<L>::value || std::is_floating_point<L>::value, | ||||
|                 "The third argument must be integral or floating-point"); | ||||
|   RTC_DCHECK_LE(min, max); | ||||
|   return SafeLe(x, min) | ||||
|              ? static_cast<R2>(min) | ||||
|              : SafeGe(x, max) ? static_cast<R2>(max) : static_cast<R2>(x); | ||||
|   return SafeLe(x, min)   ? static_cast<R2>(min) | ||||
|          : SafeGe(x, max) ? static_cast<R2>(max) | ||||
|                           : static_cast<R2>(x); | ||||
| } | ||||
|  | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -10,131 +10,37 @@ | ||||
|  | ||||
| #include "rtc_base/platform_thread.h" | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <memory> | ||||
|  | ||||
| #if !defined(WEBRTC_WIN) | ||||
| #include <sched.h> | ||||
| #endif | ||||
| #include <stdint.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include <algorithm> | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
|  | ||||
| namespace rtc { | ||||
| namespace { | ||||
| #if !defined(WEBRTC_WIN) | ||||
| struct ThreadAttributes { | ||||
|   ThreadAttributes() { pthread_attr_init(&attr); } | ||||
|   ~ThreadAttributes() { pthread_attr_destroy(&attr); } | ||||
|   pthread_attr_t* operator&() { return &attr; } | ||||
|   pthread_attr_t attr; | ||||
| }; | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
| }  // namespace | ||||
|  | ||||
| PlatformThread::PlatformThread(ThreadRunFunction func, | ||||
|                                void* obj, | ||||
|                                absl::string_view thread_name, | ||||
|                                ThreadPriority priority /*= kNormalPriority*/) | ||||
|     : run_function_(func), priority_(priority), obj_(obj), name_(thread_name) { | ||||
|   RTC_DCHECK(func); | ||||
|   RTC_DCHECK(!name_.empty()); | ||||
|   // TODO(tommi): Consider lowering the limit to 15 (limit on Linux). | ||||
|   RTC_DCHECK(name_.length() < 64); | ||||
|   spawned_thread_checker_.Detach(); | ||||
| } | ||||
|  | ||||
| PlatformThread::~PlatformThread() { | ||||
|   RTC_DCHECK(thread_checker_.IsCurrent()); | ||||
| #if defined(WEBRTC_WIN) | ||||
|   RTC_DCHECK(!thread_); | ||||
|   RTC_DCHECK(!thread_id_); | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
| } | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| DWORD WINAPI PlatformThread::StartThread(void* param) { | ||||
|   // The GetLastError() function only returns valid results when it is called | ||||
|   // after a Win32 API function that returns a "failed" result. A crash dump | ||||
|   // contains the result from GetLastError() and to make sure it does not | ||||
|   // falsely report a Windows error we call SetLastError here. | ||||
|   ::SetLastError(ERROR_SUCCESS); | ||||
|   static_cast<PlatformThread*>(param)->Run(); | ||||
|   return 0; | ||||
| int Win32PriorityFromThreadPriority(ThreadPriority priority) { | ||||
|   switch (priority) { | ||||
|     case ThreadPriority::kLow: | ||||
|       return THREAD_PRIORITY_BELOW_NORMAL; | ||||
|     case ThreadPriority::kNormal: | ||||
|       return THREAD_PRIORITY_NORMAL; | ||||
|     case ThreadPriority::kHigh: | ||||
|       return THREAD_PRIORITY_ABOVE_NORMAL; | ||||
|     case ThreadPriority::kRealtime: | ||||
|       return THREAD_PRIORITY_TIME_CRITICAL; | ||||
|   } | ||||
| } | ||||
| #else | ||||
| void* PlatformThread::StartThread(void* param) { | ||||
|   static_cast<PlatformThread*>(param)->Run(); | ||||
|   return 0; | ||||
| } | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
| #endif | ||||
|  | ||||
| void PlatformThread::Start() { | ||||
|   RTC_DCHECK(thread_checker_.IsCurrent()); | ||||
|   RTC_DCHECK(!thread_) << "Thread already started?"; | ||||
| bool SetPriority(ThreadPriority priority) { | ||||
| #if defined(WEBRTC_WIN) | ||||
|   // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION. | ||||
|   // Set the reserved stack stack size to 1M, which is the default on Windows | ||||
|   // and Linux. | ||||
|   thread_ = ::CreateThread(nullptr, 1024 * 1024, &StartThread, this, | ||||
|                            STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id_); | ||||
|   RTC_CHECK(thread_) << "CreateThread failed"; | ||||
|   RTC_DCHECK(thread_id_); | ||||
| #else | ||||
|   ThreadAttributes attr; | ||||
|   // Set the stack stack size to 1M. | ||||
|   pthread_attr_setstacksize(&attr, 1024 * 1024); | ||||
|   RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this)); | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
| } | ||||
|  | ||||
| bool PlatformThread::IsRunning() const { | ||||
|   RTC_DCHECK(thread_checker_.IsCurrent()); | ||||
| #if defined(WEBRTC_WIN) | ||||
|   return thread_ != nullptr; | ||||
| #else | ||||
|   return thread_ != 0; | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
| } | ||||
|  | ||||
| PlatformThreadRef PlatformThread::GetThreadRef() const { | ||||
| #if defined(WEBRTC_WIN) | ||||
|   return thread_id_; | ||||
| #else | ||||
|   return thread_; | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
| } | ||||
|  | ||||
| void PlatformThread::Stop() { | ||||
|   RTC_DCHECK(thread_checker_.IsCurrent()); | ||||
|   if (!IsRunning()) | ||||
|     return; | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
|   WaitForSingleObject(thread_, INFINITE); | ||||
|   CloseHandle(thread_); | ||||
|   thread_ = nullptr; | ||||
|   thread_id_ = 0; | ||||
| #else | ||||
|   RTC_CHECK_EQ(0, pthread_join(thread_, nullptr)); | ||||
|   thread_ = 0; | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
|   spawned_thread_checker_.Detach(); | ||||
| } | ||||
|  | ||||
| void PlatformThread::Run() { | ||||
|   // Attach the worker thread checker to this thread. | ||||
|   RTC_DCHECK(spawned_thread_checker_.IsCurrent()); | ||||
|   rtc::SetCurrentThreadName(name_.c_str()); | ||||
|   SetPriority(priority_); | ||||
|   run_function_(obj_); | ||||
| } | ||||
|  | ||||
| bool PlatformThread::SetPriority(ThreadPriority priority) { | ||||
|   RTC_DCHECK(spawned_thread_checker_.IsCurrent()); | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
|   return SetThreadPriority(thread_, priority) != FALSE; | ||||
|   return SetThreadPriority(GetCurrentThread(), | ||||
|                            Win32PriorityFromThreadPriority(priority)) != FALSE; | ||||
| #elif defined(__native_client__) || defined(WEBRTC_FUCHSIA) | ||||
|   // Setting thread priorities is not supported in NaCl or Fuchsia. | ||||
|   return true; | ||||
| @@ -158,35 +64,148 @@ bool PlatformThread::SetPriority(ThreadPriority priority) { | ||||
|   const int top_prio = max_prio - 1; | ||||
|   const int low_prio = min_prio + 1; | ||||
|   switch (priority) { | ||||
|     case kLowPriority: | ||||
|     case ThreadPriority::kLow: | ||||
|       param.sched_priority = low_prio; | ||||
|       break; | ||||
|     case kNormalPriority: | ||||
|     case ThreadPriority::kNormal: | ||||
|       // The -1 ensures that the kHighPriority is always greater or equal to | ||||
|       // kNormalPriority. | ||||
|       param.sched_priority = (low_prio + top_prio - 1) / 2; | ||||
|       break; | ||||
|     case kHighPriority: | ||||
|     case ThreadPriority::kHigh: | ||||
|       param.sched_priority = std::max(top_prio - 2, low_prio); | ||||
|       break; | ||||
|     case kHighestPriority: | ||||
|       param.sched_priority = std::max(top_prio - 1, low_prio); | ||||
|       break; | ||||
|     case kRealtimePriority: | ||||
|     case ThreadPriority::kRealtime: | ||||
|       param.sched_priority = top_prio; | ||||
|       break; | ||||
|   } | ||||
|   return pthread_setschedparam(thread_, policy, ¶m) == 0; | ||||
|   return pthread_setschedparam(pthread_self(), policy, ¶m) == 0; | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
| } | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) { | ||||
|   RTC_DCHECK(thread_checker_.IsCurrent()); | ||||
|   RTC_DCHECK(IsRunning()); | ||||
| DWORD WINAPI RunPlatformThread(void* param) { | ||||
|   // The GetLastError() function only returns valid results when it is called | ||||
|   // after a Win32 API function that returns a "failed" result. A crash dump | ||||
|   // contains the result from GetLastError() and to make sure it does not | ||||
|   // falsely report a Windows error we call SetLastError here. | ||||
|   ::SetLastError(ERROR_SUCCESS); | ||||
|   auto function = static_cast<std::function<void()>*>(param); | ||||
|   (*function)(); | ||||
|   delete function; | ||||
|   return 0; | ||||
| } | ||||
| #else | ||||
| void* RunPlatformThread(void* param) { | ||||
|   auto function = static_cast<std::function<void()>*>(param); | ||||
|   (*function)(); | ||||
|   delete function; | ||||
|   return 0; | ||||
| } | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
|  | ||||
|   return QueueUserAPC(function, thread_, data) != FALSE; | ||||
| }  // namespace | ||||
|  | ||||
| PlatformThread::PlatformThread(Handle handle, bool joinable) | ||||
|     : handle_(handle), joinable_(joinable) {} | ||||
|  | ||||
| PlatformThread::PlatformThread(PlatformThread&& rhs) | ||||
|     : handle_(rhs.handle_), joinable_(rhs.joinable_) { | ||||
|   rhs.handle_ = absl::nullopt; | ||||
| } | ||||
|  | ||||
| PlatformThread& PlatformThread::operator=(PlatformThread&& rhs) { | ||||
|   Finalize(); | ||||
|   handle_ = rhs.handle_; | ||||
|   joinable_ = rhs.joinable_; | ||||
|   rhs.handle_ = absl::nullopt; | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| PlatformThread::~PlatformThread() { | ||||
|   Finalize(); | ||||
| } | ||||
|  | ||||
| PlatformThread PlatformThread::SpawnJoinable( | ||||
|     std::function<void()> thread_function, | ||||
|     absl::string_view name, | ||||
|     ThreadAttributes attributes) { | ||||
|   return SpawnThread(std::move(thread_function), name, attributes, | ||||
|                      /*joinable=*/true); | ||||
| } | ||||
|  | ||||
| PlatformThread PlatformThread::SpawnDetached( | ||||
|     std::function<void()> thread_function, | ||||
|     absl::string_view name, | ||||
|     ThreadAttributes attributes) { | ||||
|   return SpawnThread(std::move(thread_function), name, attributes, | ||||
|                      /*joinable=*/false); | ||||
| } | ||||
|  | ||||
| absl::optional<PlatformThread::Handle> PlatformThread::GetHandle() const { | ||||
|   return handle_; | ||||
| } | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) { | ||||
|   RTC_DCHECK(handle_.has_value()); | ||||
|   return handle_.has_value() ? QueueUserAPC(function, *handle_, data) != FALSE | ||||
|                              : false; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void PlatformThread::Finalize() { | ||||
|   if (!handle_.has_value()) | ||||
|     return; | ||||
| #if defined(WEBRTC_WIN) | ||||
|   if (joinable_) | ||||
|     WaitForSingleObject(*handle_, INFINITE); | ||||
|   CloseHandle(*handle_); | ||||
| #else | ||||
|   if (joinable_) | ||||
|     RTC_CHECK_EQ(0, pthread_join(*handle_, nullptr)); | ||||
| #endif | ||||
|   handle_ = absl::nullopt; | ||||
| } | ||||
|  | ||||
| PlatformThread PlatformThread::SpawnThread( | ||||
|     std::function<void()> thread_function, | ||||
|     absl::string_view name, | ||||
|     ThreadAttributes attributes, | ||||
|     bool joinable) { | ||||
|   RTC_DCHECK(thread_function); | ||||
|   RTC_DCHECK(!name.empty()); | ||||
|   // TODO(tommi): Consider lowering the limit to 15 (limit on Linux). | ||||
|   RTC_DCHECK(name.length() < 64); | ||||
|   auto start_thread_function_ptr = | ||||
|       new std::function<void()>([thread_function = std::move(thread_function), | ||||
|                                  name = std::string(name), attributes] { | ||||
|         rtc::SetCurrentThreadName(name.c_str()); | ||||
|         SetPriority(attributes.priority); | ||||
|         thread_function(); | ||||
|       }); | ||||
| #if defined(WEBRTC_WIN) | ||||
|   // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION. | ||||
|   // Set the reserved stack stack size to 1M, which is the default on Windows | ||||
|   // and Linux. | ||||
|   DWORD thread_id = 0; | ||||
|   PlatformThread::Handle handle = ::CreateThread( | ||||
|       nullptr, 1024 * 1024, &RunPlatformThread, start_thread_function_ptr, | ||||
|       STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id); | ||||
|   RTC_CHECK(handle) << "CreateThread failed"; | ||||
| #else | ||||
|   pthread_attr_t attr; | ||||
|   pthread_attr_init(&attr); | ||||
|   // Set the stack stack size to 1M. | ||||
|   pthread_attr_setstacksize(&attr, 1024 * 1024); | ||||
|   pthread_attr_setdetachstate( | ||||
|       &attr, joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED); | ||||
|   PlatformThread::Handle handle; | ||||
|   RTC_CHECK_EQ(0, pthread_create(&handle, &attr, &RunPlatformThread, | ||||
|                                  start_thread_function_ptr)); | ||||
|   pthread_attr_destroy(&attr); | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
|   return PlatformThread(handle, joinable); | ||||
| } | ||||
|  | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -11,92 +11,108 @@ | ||||
| #ifndef RTC_BASE_PLATFORM_THREAD_H_ | ||||
| #define RTC_BASE_PLATFORM_THREAD_H_ | ||||
|  | ||||
| #ifndef WEBRTC_WIN | ||||
| #include <functional> | ||||
| #include <string> | ||||
| #if !defined(WEBRTC_WIN) | ||||
| #include <pthread.h> | ||||
| #endif | ||||
| #include <string> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "rtc_base/constructor_magic.h" | ||||
| #include "absl/types/optional.h" | ||||
| #include "rtc_base/platform_thread_types.h" | ||||
| #include "rtc_base/thread_checker.h" | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| // Callback function that the spawned thread will enter once spawned. | ||||
| typedef void (*ThreadRunFunction)(void*); | ||||
|  | ||||
| enum ThreadPriority { | ||||
| #ifdef WEBRTC_WIN | ||||
|   kLowPriority = THREAD_PRIORITY_BELOW_NORMAL, | ||||
|   kNormalPriority = THREAD_PRIORITY_NORMAL, | ||||
|   kHighPriority = THREAD_PRIORITY_ABOVE_NORMAL, | ||||
|   kHighestPriority = THREAD_PRIORITY_HIGHEST, | ||||
|   kRealtimePriority = THREAD_PRIORITY_TIME_CRITICAL | ||||
| #else | ||||
|   kLowPriority = 1, | ||||
|   kNormalPriority = 2, | ||||
|   kHighPriority = 3, | ||||
|   kHighestPriority = 4, | ||||
|   kRealtimePriority = 5 | ||||
| #endif | ||||
| enum class ThreadPriority { | ||||
|   kLow = 1, | ||||
|   kNormal, | ||||
|   kHigh, | ||||
|   kRealtime, | ||||
| }; | ||||
|  | ||||
| // Represents a simple worker thread.  The implementation must be assumed | ||||
| // to be single threaded, meaning that all methods of the class, must be | ||||
| // called from the same thread, including instantiation. | ||||
| class PlatformThread { | ||||
| struct ThreadAttributes { | ||||
|   ThreadPriority priority = ThreadPriority::kNormal; | ||||
|   ThreadAttributes& SetPriority(ThreadPriority priority_param) { | ||||
|     priority = priority_param; | ||||
|     return *this; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // Represents a simple worker thread. | ||||
| class PlatformThread final { | ||||
|  public: | ||||
|   PlatformThread(ThreadRunFunction func, | ||||
|                  void* obj, | ||||
|                  absl::string_view thread_name, | ||||
|                  ThreadPriority priority = kNormalPriority); | ||||
|   // Handle is the base platform thread handle. | ||||
| #if defined(WEBRTC_WIN) | ||||
|   using Handle = HANDLE; | ||||
| #else | ||||
|   using Handle = pthread_t; | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
|   // This ctor creates the PlatformThread with an unset handle (returning true | ||||
|   // in empty()) and is provided for convenience. | ||||
|   // TODO(bugs.webrtc.org/12727) Look into if default and move support can be | ||||
|   // removed. | ||||
|   PlatformThread() = default; | ||||
|  | ||||
|   // Moves `rhs` into this, storing an empty state in `rhs`. | ||||
|   // TODO(bugs.webrtc.org/12727) Look into if default and move support can be | ||||
|   // removed. | ||||
|   PlatformThread(PlatformThread&& rhs); | ||||
|  | ||||
|   // Copies won't work since we'd have problems with joinable threads. | ||||
|   PlatformThread(const PlatformThread&) = delete; | ||||
|   PlatformThread& operator=(const PlatformThread&) = delete; | ||||
|  | ||||
|   // Moves `rhs` into this, storing an empty state in `rhs`. | ||||
|   // TODO(bugs.webrtc.org/12727) Look into if default and move support can be | ||||
|   // removed. | ||||
|   PlatformThread& operator=(PlatformThread&& rhs); | ||||
|  | ||||
|   // For a PlatformThread that's been spawned joinable, the destructor suspends | ||||
|   // the calling thread until the created thread exits unless the thread has | ||||
|   // already exited. | ||||
|   virtual ~PlatformThread(); | ||||
|  | ||||
|   const std::string& name() const { return name_; } | ||||
|   // Finalizes any allocated resources. | ||||
|   // For a PlatformThread that's been spawned joinable, Finalize() suspends | ||||
|   // the calling thread until the created thread exits unless the thread has | ||||
|   // already exited. | ||||
|   // empty() returns true after completion. | ||||
|   void Finalize(); | ||||
|  | ||||
|   // Spawns a thread and tries to set thread priority according to the priority | ||||
|   // from when CreateThread was called. | ||||
|   void Start(); | ||||
|   // Returns true if default constructed, moved from, or Finalize()ed. | ||||
|   bool empty() const { return !handle_.has_value(); } | ||||
|  | ||||
|   bool IsRunning() const; | ||||
|   // Creates a started joinable thread which will be joined when the returned | ||||
|   // PlatformThread destructs or Finalize() is called. | ||||
|   static PlatformThread SpawnJoinable( | ||||
|       std::function<void()> thread_function, | ||||
|       absl::string_view name, | ||||
|       ThreadAttributes attributes = ThreadAttributes()); | ||||
|  | ||||
|   // Returns an identifier for the worker thread that can be used to do | ||||
|   // thread checks. | ||||
|   PlatformThreadRef GetThreadRef() const; | ||||
|   // Creates a started detached thread. The caller has to use external | ||||
|   // synchronization as nothing is provided by the PlatformThread construct. | ||||
|   static PlatformThread SpawnDetached( | ||||
|       std::function<void()> thread_function, | ||||
|       absl::string_view name, | ||||
|       ThreadAttributes attributes = ThreadAttributes()); | ||||
|  | ||||
|   // Stops (joins) the spawned thread. | ||||
|   void Stop(); | ||||
|   // Returns the base platform thread handle of this thread. | ||||
|   absl::optional<Handle> GetHandle() const; | ||||
|  | ||||
|  protected: | ||||
| #if defined(WEBRTC_WIN) | ||||
|   // Exposed to derived classes to allow for special cases specific to Windows. | ||||
|   // Queue a Windows APC function that runs when the thread is alertable. | ||||
|   bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data); | ||||
| #endif | ||||
|  | ||||
|  private: | ||||
|   void Run(); | ||||
|   bool SetPriority(ThreadPriority priority); | ||||
|   PlatformThread(Handle handle, bool joinable); | ||||
|   static PlatformThread SpawnThread(std::function<void()> thread_function, | ||||
|                                     absl::string_view name, | ||||
|                                     ThreadAttributes attributes, | ||||
|                                     bool joinable); | ||||
|  | ||||
|   ThreadRunFunction const run_function_ = nullptr; | ||||
|   const ThreadPriority priority_ = kNormalPriority; | ||||
|   void* const obj_; | ||||
|   // TODO(pbos): Make sure call sites use string literals and update to a const | ||||
|   // char* instead of a std::string. | ||||
|   const std::string name_; | ||||
|   rtc::ThreadChecker thread_checker_; | ||||
|   rtc::ThreadChecker spawned_thread_checker_; | ||||
| #if defined(WEBRTC_WIN) | ||||
|   static DWORD WINAPI StartThread(void* param); | ||||
|  | ||||
|   HANDLE thread_ = nullptr; | ||||
|   DWORD thread_id_ = 0; | ||||
| #else | ||||
|   static void* StartThread(void* param); | ||||
|  | ||||
|   pthread_t thread_ = 0; | ||||
| #endif  // defined(WEBRTC_WIN) | ||||
|   RTC_DISALLOW_COPY_AND_ASSIGN(PlatformThread); | ||||
|   absl::optional<Handle> handle_; | ||||
|   bool joinable_ = false; | ||||
| }; | ||||
|  | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -25,6 +25,13 @@ typedef HRESULT(WINAPI* RTC_SetThreadDescription)(HANDLE hThread, | ||||
|                                                   PCWSTR lpThreadDescription); | ||||
| #endif | ||||
|  | ||||
| #if defined(WEBRTC_FUCHSIA) | ||||
| #include <string.h> | ||||
| #include <zircon/syscalls.h> | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #endif | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| PlatformThreadId CurrentThreadId() { | ||||
| @@ -99,18 +106,20 @@ void SetCurrentThreadName(const char* name) { | ||||
|  | ||||
| #pragma warning(push) | ||||
| #pragma warning(disable : 6320 6322) | ||||
| #ifndef __MINGW32__ | ||||
|   __try { | ||||
|     ::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(ULONG_PTR), | ||||
|                      reinterpret_cast<ULONG_PTR*>(&threadname_info)); | ||||
|   } __except (EXCEPTION_EXECUTE_HANDLER) {  // NOLINT | ||||
|   } | ||||
| #endif | ||||
| #pragma warning(pop) | ||||
| #elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID) | ||||
|   prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name));  // NOLINT | ||||
| #elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS) | ||||
|   pthread_setname_np(name); | ||||
| #elif defined(WEBRTC_FUCHSIA) | ||||
|   zx_status_t status = zx_object_set_property(zx_thread_self(), ZX_PROP_NAME, | ||||
|                                               name, strlen(name)); | ||||
|   RTC_DCHECK_EQ(status, ZX_OK); | ||||
| #endif | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -25,7 +25,9 @@ RaceChecker::RaceChecker() {} | ||||
| bool RaceChecker::Acquire() const { | ||||
|   const PlatformThreadRef current_thread = CurrentThreadRef(); | ||||
|   // Set new accessing thread if this is a new use. | ||||
|   if (access_count_++ == 0) | ||||
|   const int current_access_count = access_count_; | ||||
|   access_count_ = access_count_ + 1; | ||||
|   if (current_access_count == 0) | ||||
|     accessing_thread_ = current_thread; | ||||
|   // If this is being used concurrently this check will fail for the second | ||||
|   // thread entering since it won't set the thread. Recursive use of checked | ||||
| @@ -35,7 +37,7 @@ bool RaceChecker::Acquire() const { | ||||
| } | ||||
|  | ||||
| void RaceChecker::Release() const { | ||||
|   --access_count_; | ||||
|   access_count_ = access_count_ - 1; | ||||
| } | ||||
|  | ||||
| namespace internal { | ||||
|   | ||||
							
								
								
									
										87
									
								
								webrtc/rtc_base/random.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								webrtc/rtc_base/random.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
| #include "rtc_base/random.h" | ||||
|  | ||||
| #include <math.h> | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/numerics/safe_conversions.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| Random::Random(uint64_t seed) { | ||||
|   RTC_DCHECK(seed != 0x0ull); | ||||
|   state_ = seed; | ||||
| } | ||||
|  | ||||
| uint32_t Random::Rand(uint32_t t) { | ||||
|   // Casting the output to 32 bits will give an almost uniform number. | ||||
|   // Pr[x=0] = (2^32-1) / (2^64-1) | ||||
|   // Pr[x=k] = 2^32 / (2^64-1) for k!=0 | ||||
|   // Uniform would be Pr[x=k] = 2^32 / 2^64 for all 32-bit integers k. | ||||
|   uint32_t x = NextOutput(); | ||||
|   // If x / 2^32 is uniform on [0,1), then x / 2^32 * (t+1) is uniform on | ||||
|   // the interval [0,t+1), so the integer part is uniform on [0,t]. | ||||
|   uint64_t result = x * (static_cast<uint64_t>(t) + 1); | ||||
|   result >>= 32; | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| uint32_t Random::Rand(uint32_t low, uint32_t high) { | ||||
|   RTC_DCHECK(low <= high); | ||||
|   return Rand(high - low) + low; | ||||
| } | ||||
|  | ||||
| int32_t Random::Rand(int32_t low, int32_t high) { | ||||
|   RTC_DCHECK(low <= high); | ||||
|   const int64_t low_i64{low}; | ||||
|   return rtc::dchecked_cast<int32_t>( | ||||
|       Rand(rtc::dchecked_cast<uint32_t>(high - low_i64)) + low_i64); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| float Random::Rand<float>() { | ||||
|   double result = NextOutput() - 1; | ||||
|   result = result / static_cast<double>(0xFFFFFFFFFFFFFFFFull); | ||||
|   return static_cast<float>(result); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| double Random::Rand<double>() { | ||||
|   double result = NextOutput() - 1; | ||||
|   result = result / static_cast<double>(0xFFFFFFFFFFFFFFFFull); | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| template <> | ||||
| bool Random::Rand<bool>() { | ||||
|   return Rand(0, 1) == 1; | ||||
| } | ||||
|  | ||||
| double Random::Gaussian(double mean, double standard_deviation) { | ||||
|   // Creating a Normal distribution variable from two independent uniform | ||||
|   // variables based on the Box-Muller transform, which is defined on the | ||||
|   // interval (0, 1]. Note that we rely on NextOutput to generate integers | ||||
|   // in the range [1, 2^64-1]. Normally this behavior is a bit frustrating, | ||||
|   // but here it is exactly what we need. | ||||
|   const double kPi = 3.14159265358979323846; | ||||
|   double u1 = static_cast<double>(NextOutput()) / | ||||
|               static_cast<double>(0xFFFFFFFFFFFFFFFFull); | ||||
|   double u2 = static_cast<double>(NextOutput()) / | ||||
|               static_cast<double>(0xFFFFFFFFFFFFFFFFull); | ||||
|   return mean + standard_deviation * sqrt(-2 * log(u1)) * cos(2 * kPi * u2); | ||||
| } | ||||
|  | ||||
| double Random::Exponential(double lambda) { | ||||
|   double uniform = Rand<double>(); | ||||
|   return -log(uniform) / lambda; | ||||
| } | ||||
|  | ||||
| }  // namespace webrtc | ||||
							
								
								
									
										96
									
								
								webrtc/rtc_base/random.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								webrtc/rtc_base/random.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_RANDOM_H_ | ||||
| #define RTC_BASE_RANDOM_H_ | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| #include <limits> | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| class Random { | ||||
|  public: | ||||
|   // TODO(tommi): Change this so that the seed can be initialized internally, | ||||
|   // e.g. by offering two ways of constructing or offer a static method that | ||||
|   // returns a seed that's suitable for initialization. | ||||
|   // The problem now is that callers are calling clock_->TimeInMicroseconds() | ||||
|   // which calls TickTime::Now().Ticks(), which can return a very low value on | ||||
|   // Mac and can result in a seed of 0 after conversion to microseconds. | ||||
|   // Besides the quality of the random seed being poor, this also requires | ||||
|   // the client to take on extra dependencies to generate a seed. | ||||
|   // If we go for a static seed generator in Random, we can use something from | ||||
|   // webrtc/rtc_base and make sure that it works the same way across platforms. | ||||
|   // See also discussion here: https://codereview.webrtc.org/1623543002/ | ||||
|   explicit Random(uint64_t seed); | ||||
|  | ||||
|   Random() = delete; | ||||
|   Random(const Random&) = delete; | ||||
|   Random& operator=(const Random&) = delete; | ||||
|  | ||||
|   // Return pseudo-random integer of the specified type. | ||||
|   // We need to limit the size to 32 bits to keep the output close to uniform. | ||||
|   template <typename T> | ||||
|   T Rand() { | ||||
|     static_assert(std::numeric_limits<T>::is_integer && | ||||
|                       std::numeric_limits<T>::radix == 2 && | ||||
|                       std::numeric_limits<T>::digits <= 32, | ||||
|                   "Rand is only supported for built-in integer types that are " | ||||
|                   "32 bits or smaller."); | ||||
|     return static_cast<T>(NextOutput()); | ||||
|   } | ||||
|  | ||||
|   // Uniformly distributed pseudo-random number in the interval [0, t]. | ||||
|   uint32_t Rand(uint32_t t); | ||||
|  | ||||
|   // Uniformly distributed pseudo-random number in the interval [low, high]. | ||||
|   uint32_t Rand(uint32_t low, uint32_t high); | ||||
|  | ||||
|   // Uniformly distributed pseudo-random number in the interval [low, high]. | ||||
|   int32_t Rand(int32_t low, int32_t high); | ||||
|  | ||||
|   // Normal Distribution. | ||||
|   double Gaussian(double mean, double standard_deviation); | ||||
|  | ||||
|   // Exponential Distribution. | ||||
|   double Exponential(double lambda); | ||||
|  | ||||
|  private: | ||||
|   // Outputs a nonzero 64-bit random number using Xorshift algorithm. | ||||
|   // https://en.wikipedia.org/wiki/Xorshift | ||||
|   uint64_t NextOutput() { | ||||
|     state_ ^= state_ >> 12; | ||||
|     state_ ^= state_ << 25; | ||||
|     state_ ^= state_ >> 27; | ||||
|     RTC_DCHECK(state_ != 0x0ULL); | ||||
|     return state_ * 2685821657736338717ull; | ||||
|   } | ||||
|  | ||||
|   uint64_t state_; | ||||
| }; | ||||
|  | ||||
| // Return pseudo-random number in the interval [0.0, 1.0). | ||||
| template <> | ||||
| float Random::Rand<float>(); | ||||
|  | ||||
| // Return pseudo-random number in the interval [0.0, 1.0). | ||||
| template <> | ||||
| double Random::Rand<double>(); | ||||
|  | ||||
| // Return pseudo-random boolean value. | ||||
| template <> | ||||
| bool Random::Rand<bool>(); | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_RANDOM_H_ | ||||
| @@ -10,10 +10,7 @@ | ||||
| #ifndef RTC_BASE_REF_COUNTED_OBJECT_H_ | ||||
| #define RTC_BASE_REF_COUNTED_OBJECT_H_ | ||||
|  | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
|  | ||||
| #include "rtc_base/constructor_magic.h" | ||||
| #include "api/scoped_refptr.h" | ||||
| #include "rtc_base/ref_count.h" | ||||
| #include "rtc_base/ref_counter.h" | ||||
|  | ||||
| @@ -24,6 +21,9 @@ class RefCountedObject : public T { | ||||
|  public: | ||||
|   RefCountedObject() {} | ||||
|  | ||||
|   RefCountedObject(const RefCountedObject&) = delete; | ||||
|   RefCountedObject& operator=(const RefCountedObject&) = delete; | ||||
|  | ||||
|   template <class P0> | ||||
|   explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {} | ||||
|  | ||||
| @@ -33,9 +33,9 @@ class RefCountedObject : public T { | ||||
|           std::forward<P1>(p1), | ||||
|           std::forward<Args>(args)...) {} | ||||
|  | ||||
|   virtual void AddRef() const { ref_count_.IncRef(); } | ||||
|   void AddRef() const override { ref_count_.IncRef(); } | ||||
|  | ||||
|   virtual RefCountReleaseStatus Release() const { | ||||
|   RefCountReleaseStatus Release() const override { | ||||
|     const auto status = ref_count_.DecRef(); | ||||
|     if (status == RefCountReleaseStatus::kDroppedLastRef) { | ||||
|       delete this; | ||||
| @@ -52,11 +52,36 @@ class RefCountedObject : public T { | ||||
|   virtual bool HasOneRef() const { return ref_count_.HasOneRef(); } | ||||
|  | ||||
|  protected: | ||||
|   virtual ~RefCountedObject() {} | ||||
|   ~RefCountedObject() override {} | ||||
|  | ||||
|   mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; | ||||
| }; | ||||
|  | ||||
|   RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject); | ||||
| template <class T> | ||||
| class FinalRefCountedObject final : public T { | ||||
|  public: | ||||
|   using T::T; | ||||
|   // Above using declaration propagates a default move constructor | ||||
|   // FinalRefCountedObject(FinalRefCountedObject&& other), but we also need | ||||
|   // move construction from T. | ||||
|   explicit FinalRefCountedObject(T&& other) : T(std::move(other)) {} | ||||
|   FinalRefCountedObject(const FinalRefCountedObject&) = delete; | ||||
|   FinalRefCountedObject& operator=(const FinalRefCountedObject&) = delete; | ||||
|  | ||||
|   void AddRef() const { ref_count_.IncRef(); } | ||||
|   RefCountReleaseStatus Release() const { | ||||
|     const auto status = ref_count_.DecRef(); | ||||
|     if (status == RefCountReleaseStatus::kDroppedLastRef) { | ||||
|       delete this; | ||||
|     } | ||||
|     return status; | ||||
|   } | ||||
|   bool HasOneRef() const { return ref_count_.HasOneRef(); } | ||||
|  | ||||
|  private: | ||||
|   ~FinalRefCountedObject() = default; | ||||
|  | ||||
|   mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; | ||||
| }; | ||||
|  | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -12,6 +12,8 @@ | ||||
|  | ||||
| #include <cstdio> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "api/array_view.h" | ||||
| #include "rtc_base/arraysize.h" | ||||
| #include "rtc_base/checks.h" | ||||
|  | ||||
| @@ -49,18 +51,18 @@ size_t hex_encode_output_length(size_t srclen, char delimiter) { | ||||
| } | ||||
|  | ||||
| // hex_encode shows the hex representation of binary data in ascii, with | ||||
| // |delimiter| between bytes, or none if |delimiter| == 0. | ||||
| // `delimiter` between bytes, or none if `delimiter` == 0. | ||||
| void hex_encode_with_delimiter(char* buffer, | ||||
|                                const char* csource, | ||||
|                                size_t srclen, | ||||
|                                absl::string_view source, | ||||
|                                char delimiter) { | ||||
|   RTC_DCHECK(buffer); | ||||
|  | ||||
|   // Init and check bounds. | ||||
|   const unsigned char* bsource = | ||||
|       reinterpret_cast<const unsigned char*>(csource); | ||||
|       reinterpret_cast<const unsigned char*>(source.data()); | ||||
|   size_t srcpos = 0, bufpos = 0; | ||||
|  | ||||
|   size_t srclen = source.length(); | ||||
|   while (srcpos < srclen) { | ||||
|     unsigned char ch = bsource[srcpos++]; | ||||
|     buffer[bufpos] = hex_encode((ch >> 4) & 0xF); | ||||
| @@ -77,43 +79,30 @@ void hex_encode_with_delimiter(char* buffer, | ||||
|  | ||||
| }  // namespace | ||||
|  | ||||
| std::string hex_encode(const std::string& str) { | ||||
|   return hex_encode(str.c_str(), str.size()); | ||||
| std::string hex_encode(absl::string_view str) { | ||||
|   return hex_encode_with_delimiter(str, 0); | ||||
| } | ||||
|  | ||||
| std::string hex_encode(const char* source, size_t srclen) { | ||||
|   return hex_encode_with_delimiter(source, srclen, 0); | ||||
| } | ||||
|  | ||||
| std::string hex_encode_with_delimiter(const char* source, | ||||
|                                       size_t srclen, | ||||
| std::string hex_encode_with_delimiter(absl::string_view source, | ||||
|                                       char delimiter) { | ||||
|   std::string s(hex_encode_output_length(srclen, delimiter), 0); | ||||
|   hex_encode_with_delimiter(&s[0], source, srclen, delimiter); | ||||
|   std::string s(hex_encode_output_length(source.length(), delimiter), 0); | ||||
|   hex_encode_with_delimiter(&s[0], source, delimiter); | ||||
|   return s; | ||||
| } | ||||
|  | ||||
| size_t hex_decode(char* cbuffer, | ||||
|                   size_t buflen, | ||||
|                   const char* source, | ||||
|                   size_t srclen) { | ||||
|   return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0); | ||||
| } | ||||
|  | ||||
| size_t hex_decode_with_delimiter(char* cbuffer, | ||||
|                                  size_t buflen, | ||||
|                                  const char* source, | ||||
|                                  size_t srclen, | ||||
| size_t hex_decode_with_delimiter(ArrayView<char> cbuffer, | ||||
|                                  absl::string_view source, | ||||
|                                  char delimiter) { | ||||
|   RTC_DCHECK(cbuffer);  // TODO(kwiberg): estimate output size | ||||
|   if (buflen == 0) | ||||
|   if (cbuffer.empty()) | ||||
|     return 0; | ||||
|  | ||||
|   // Init and bounds check. | ||||
|   unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer); | ||||
|   unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer.data()); | ||||
|   size_t srcpos = 0, bufpos = 0; | ||||
|   size_t srclen = source.length(); | ||||
|  | ||||
|   size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2; | ||||
|   if (buflen < needed) | ||||
|   if (cbuffer.size() < needed) | ||||
|     return 0; | ||||
|  | ||||
|   while (srcpos < srclen) { | ||||
| @@ -141,18 +130,11 @@ size_t hex_decode_with_delimiter(char* cbuffer, | ||||
|   return bufpos; | ||||
| } | ||||
|  | ||||
| size_t hex_decode(char* buffer, size_t buflen, const std::string& source) { | ||||
|   return hex_decode_with_delimiter(buffer, buflen, source, 0); | ||||
| } | ||||
| size_t hex_decode_with_delimiter(char* buffer, | ||||
|                                  size_t buflen, | ||||
|                                  const std::string& source, | ||||
|                                  char delimiter) { | ||||
|   return hex_decode_with_delimiter(buffer, buflen, source.c_str(), | ||||
|                                    source.length(), delimiter); | ||||
| size_t hex_decode(ArrayView<char> buffer, absl::string_view source) { | ||||
|   return hex_decode_with_delimiter(buffer, source, 0); | ||||
| } | ||||
|  | ||||
| size_t tokenize(const std::string& source, | ||||
| size_t tokenize(absl::string_view source, | ||||
|                 char delimiter, | ||||
|                 std::vector<std::string>* fields) { | ||||
|   fields->clear(); | ||||
| @@ -160,146 +142,61 @@ size_t tokenize(const std::string& source, | ||||
|   for (size_t i = 0; i < source.length(); ++i) { | ||||
|     if (source[i] == delimiter) { | ||||
|       if (i != last) { | ||||
|         fields->push_back(source.substr(last, i - last)); | ||||
|         fields->emplace_back(source.substr(last, i - last)); | ||||
|       } | ||||
|       last = i + 1; | ||||
|     } | ||||
|   } | ||||
|   if (last != source.length()) { | ||||
|     fields->push_back(source.substr(last, source.length() - last)); | ||||
|     fields->emplace_back(source.substr(last, source.length() - last)); | ||||
|   } | ||||
|   return fields->size(); | ||||
| } | ||||
|  | ||||
| size_t tokenize_with_empty_tokens(const std::string& source, | ||||
|                                   char delimiter, | ||||
|                                   std::vector<std::string>* fields) { | ||||
|   fields->clear(); | ||||
|   size_t last = 0; | ||||
|   for (size_t i = 0; i < source.length(); ++i) { | ||||
|     if (source[i] == delimiter) { | ||||
|       fields->push_back(source.substr(last, i - last)); | ||||
|       last = i + 1; | ||||
|     } | ||||
|   } | ||||
|   fields->push_back(source.substr(last, source.length() - last)); | ||||
|   return fields->size(); | ||||
| } | ||||
|  | ||||
| size_t tokenize_append(const std::string& source, | ||||
|                        char delimiter, | ||||
|                        std::vector<std::string>* fields) { | ||||
|   if (!fields) | ||||
|     return 0; | ||||
|  | ||||
|   std::vector<std::string> new_fields; | ||||
|   tokenize(source, delimiter, &new_fields); | ||||
|   fields->insert(fields->end(), new_fields.begin(), new_fields.end()); | ||||
|   return fields->size(); | ||||
| } | ||||
|  | ||||
| size_t tokenize(const std::string& source, | ||||
|                 char delimiter, | ||||
|                 char start_mark, | ||||
|                 char end_mark, | ||||
|                 std::vector<std::string>* fields) { | ||||
|   if (!fields) | ||||
|     return 0; | ||||
|   fields->clear(); | ||||
|  | ||||
|   std::string remain_source = source; | ||||
|   while (!remain_source.empty()) { | ||||
|     size_t start_pos = remain_source.find(start_mark); | ||||
|     if (std::string::npos == start_pos) | ||||
|       break; | ||||
|     std::string pre_mark; | ||||
|     if (start_pos > 0) { | ||||
|       pre_mark = remain_source.substr(0, start_pos - 1); | ||||
|     } | ||||
|  | ||||
|     ++start_pos; | ||||
|     size_t end_pos = remain_source.find(end_mark, start_pos); | ||||
|     if (std::string::npos == end_pos) | ||||
|       break; | ||||
|  | ||||
|     // We have found the matching marks. First tokenize the pre-mask. Then add | ||||
|     // the marked part as a single field. Finally, loop back for the post-mark. | ||||
|     tokenize_append(pre_mark, delimiter, fields); | ||||
|     fields->push_back(remain_source.substr(start_pos, end_pos - start_pos)); | ||||
|     remain_source = remain_source.substr(end_pos + 1); | ||||
|   } | ||||
|  | ||||
|   return tokenize_append(remain_source, delimiter, fields); | ||||
| } | ||||
|  | ||||
| bool tokenize_first(const std::string& source, | ||||
| bool tokenize_first(absl::string_view source, | ||||
|                     const char delimiter, | ||||
|                     std::string* token, | ||||
|                     std::string* rest) { | ||||
|   // Find the first delimiter | ||||
|   size_t left_pos = source.find(delimiter); | ||||
|   if (left_pos == std::string::npos) { | ||||
|   if (left_pos == absl::string_view::npos) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // Look for additional occurrances of delimiter. | ||||
|   size_t right_pos = left_pos + 1; | ||||
|   while (source[right_pos] == delimiter) { | ||||
|   while (right_pos < source.size() && source[right_pos] == delimiter) { | ||||
|     right_pos++; | ||||
|   } | ||||
|  | ||||
|   *token = source.substr(0, left_pos); | ||||
|   *rest = source.substr(right_pos); | ||||
|   *token = std::string(source.substr(0, left_pos)); | ||||
|   *rest = std::string(source.substr(right_pos)); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| std::string join(const std::vector<std::string>& source, char delimiter) { | ||||
|   if (source.size() == 0) { | ||||
|     return std::string(); | ||||
|   } | ||||
|   // Find length of the string to be returned to pre-allocate memory. | ||||
|   size_t source_string_length = 0; | ||||
|   for (size_t i = 0; i < source.size(); ++i) { | ||||
|     source_string_length += source[i].length(); | ||||
|   } | ||||
|  | ||||
|   // Build the joined string. | ||||
|   std::string joined_string; | ||||
|   joined_string.reserve(source_string_length + source.size() - 1); | ||||
|   for (size_t i = 0; i < source.size(); ++i) { | ||||
|     if (i != 0) { | ||||
|       joined_string += delimiter; | ||||
|     } | ||||
|     joined_string += source[i]; | ||||
|   } | ||||
|   return joined_string; | ||||
| } | ||||
|  | ||||
| size_t split(const std::string& source, | ||||
|              char delimiter, | ||||
|              std::vector<std::string>* fields) { | ||||
|   RTC_DCHECK(fields); | ||||
|   fields->clear(); | ||||
| std::vector<absl::string_view> split(absl::string_view source, char delimiter) { | ||||
|   std::vector<absl::string_view> fields; | ||||
|   size_t last = 0; | ||||
|   for (size_t i = 0; i < source.length(); ++i) { | ||||
|     if (source[i] == delimiter) { | ||||
|       fields->push_back(source.substr(last, i - last)); | ||||
|       fields.push_back(source.substr(last, i - last)); | ||||
|       last = i + 1; | ||||
|     } | ||||
|   } | ||||
|   fields->push_back(source.substr(last, source.length() - last)); | ||||
|   return fields->size(); | ||||
|   fields.push_back(source.substr(last)); | ||||
|   return fields; | ||||
| } | ||||
|  | ||||
| std::string ToString(const bool b) { | ||||
|   return b ? "true" : "false"; | ||||
| } | ||||
|  | ||||
| std::string ToString(const char* const s) { | ||||
| std::string ToString(absl::string_view s) { | ||||
|   return std::string(s); | ||||
| } | ||||
| std::string ToString(const std::string s) { | ||||
|   return s; | ||||
|  | ||||
| std::string ToString(const char* s) { | ||||
|   return std::string(s); | ||||
| } | ||||
|  | ||||
| std::string ToString(const short s) { | ||||
| @@ -372,7 +269,7 @@ std::string ToString(const void* const p) { | ||||
|   return std::string(&buf[0], len); | ||||
| } | ||||
|  | ||||
| bool FromString(const std::string& s, bool* b) { | ||||
| bool FromString(absl::string_view s, bool* b) { | ||||
|   if (s == "false") { | ||||
|     *b = false; | ||||
|     return true; | ||||
|   | ||||
| @@ -17,7 +17,9 @@ | ||||
| #include <type_traits> | ||||
| #include <vector> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "absl/types/optional.h" | ||||
| #include "api/array_view.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/string_to_number.h" | ||||
|  | ||||
| @@ -27,79 +29,36 @@ namespace rtc { | ||||
| // String Encoding Utilities | ||||
| ////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| std::string hex_encode(const std::string& str); | ||||
| std::string hex_encode(const char* source, size_t srclen); | ||||
| std::string hex_encode_with_delimiter(const char* source, | ||||
|                                       size_t srclen, | ||||
|                                       char delimiter); | ||||
| std::string hex_encode(absl::string_view str); | ||||
| std::string hex_encode_with_delimiter(absl::string_view source, char delimiter); | ||||
|  | ||||
| // hex_decode converts ascii hex to binary. | ||||
| size_t hex_decode(char* buffer, | ||||
|                   size_t buflen, | ||||
|                   const char* source, | ||||
|                   size_t srclen); | ||||
| size_t hex_decode(ArrayView<char> buffer, absl::string_view source); | ||||
|  | ||||
| // hex_decode, assuming that there is a delimiter between every byte | ||||
| // pair. | ||||
| // |delimiter| == 0 means no delimiter | ||||
| // `delimiter` == 0 means no delimiter | ||||
| // If the buffer is too short or the data is invalid, we return 0. | ||||
| size_t hex_decode_with_delimiter(char* buffer, | ||||
|                                  size_t buflen, | ||||
|                                  const char* source, | ||||
|                                  size_t srclen, | ||||
| size_t hex_decode_with_delimiter(ArrayView<char> buffer, | ||||
|                                  absl::string_view source, | ||||
|                                  char delimiter); | ||||
|  | ||||
| // Helper functions for hex_decode. | ||||
| size_t hex_decode(char* buffer, size_t buflen, const std::string& source); | ||||
| size_t hex_decode_with_delimiter(char* buffer, | ||||
|                                  size_t buflen, | ||||
|                                  const std::string& source, | ||||
|                                  char delimiter); | ||||
|  | ||||
| // Joins the source vector of strings into a single string, with each | ||||
| // field in source being separated by delimiter. No trailing delimiter is added. | ||||
| std::string join(const std::vector<std::string>& source, char delimiter); | ||||
|  | ||||
| // Splits the source string into multiple fields separated by delimiter, | ||||
| // with duplicates of delimiter creating empty fields. | ||||
| size_t split(const std::string& source, | ||||
|              char delimiter, | ||||
|              std::vector<std::string>* fields); | ||||
| // with duplicates of delimiter creating empty fields. Empty input produces a | ||||
| // single, empty, field. | ||||
| std::vector<absl::string_view> split(absl::string_view source, char delimiter); | ||||
|  | ||||
| // Splits the source string into multiple fields separated by delimiter, | ||||
| // with duplicates of delimiter ignored.  Trailing delimiter ignored. | ||||
| size_t tokenize(const std::string& source, | ||||
| size_t tokenize(absl::string_view source, | ||||
|                 char delimiter, | ||||
|                 std::vector<std::string>* fields); | ||||
|  | ||||
| // Tokenize, including the empty tokens. | ||||
| size_t tokenize_with_empty_tokens(const std::string& source, | ||||
|                                   char delimiter, | ||||
|                                   std::vector<std::string>* fields); | ||||
|  | ||||
| // Tokenize and append the tokens to fields. Return the new size of fields. | ||||
| size_t tokenize_append(const std::string& source, | ||||
|                        char delimiter, | ||||
|                        std::vector<std::string>* fields); | ||||
|  | ||||
| // Splits the source string into multiple fields separated by delimiter, with | ||||
| // duplicates of delimiter ignored. Trailing delimiter ignored. A substring in | ||||
| // between the start_mark and the end_mark is treated as a single field. Return | ||||
| // the size of fields. For example, if source is "filename | ||||
| // \"/Library/Application Support/media content.txt\"", delimiter is ' ', and | ||||
| // the start_mark and end_mark are '"', this method returns two fields: | ||||
| // "filename" and "/Library/Application Support/media content.txt". | ||||
| size_t tokenize(const std::string& source, | ||||
|                 char delimiter, | ||||
|                 char start_mark, | ||||
|                 char end_mark, | ||||
|                 std::vector<std::string>* fields); | ||||
|  | ||||
| // Extract the first token from source as separated by delimiter, with | ||||
| // duplicates of delimiter ignored. Return false if the delimiter could not be | ||||
| // found, otherwise return true. | ||||
| bool tokenize_first(const std::string& source, | ||||
|                     const char delimiter, | ||||
| bool tokenize_first(absl::string_view source, | ||||
|                     char delimiter, | ||||
|                     std::string* token, | ||||
|                     std::string* rest); | ||||
|  | ||||
| @@ -107,8 +66,10 @@ bool tokenize_first(const std::string& source, | ||||
| // TODO(jonasolsson): Remove these when absl::StrCat becomes available. | ||||
| std::string ToString(bool b); | ||||
|  | ||||
| std::string ToString(absl::string_view s); | ||||
| // The const char* overload is needed for correct overload resolution because of | ||||
| // the const void* version of ToString() below. | ||||
| std::string ToString(const char* s); | ||||
| std::string ToString(std::string t); | ||||
|  | ||||
| std::string ToString(short s); | ||||
| std::string ToString(unsigned short s); | ||||
| @@ -128,7 +89,7 @@ template <typename T, | ||||
|           typename std::enable_if<std::is_arithmetic<T>::value && | ||||
|                                       !std::is_same<T, bool>::value, | ||||
|                                   int>::type = 0> | ||||
| static bool FromString(const std::string& s, T* t) { | ||||
| static bool FromString(absl::string_view s, T* t) { | ||||
|   RTC_DCHECK(t); | ||||
|   absl::optional<T> result = StringToNumber<T>(s); | ||||
|  | ||||
| @@ -138,10 +99,10 @@ static bool FromString(const std::string& s, T* t) { | ||||
|   return result.has_value(); | ||||
| } | ||||
|  | ||||
| bool FromString(const std::string& s, bool* b); | ||||
| bool FromString(absl::string_view s, bool* b); | ||||
|  | ||||
| template <typename T> | ||||
| static inline T FromString(const std::string& str) { | ||||
| static inline T FromString(absl::string_view str) { | ||||
|   T val; | ||||
|   FromString(str, &val); | ||||
|   return val; | ||||
|   | ||||
| @@ -20,30 +20,41 @@ | ||||
| namespace rtc { | ||||
| namespace string_to_number_internal { | ||||
|  | ||||
| absl::optional<signed_type> ParseSigned(const char* str, int base) { | ||||
|   RTC_DCHECK(str); | ||||
|   if (isdigit(str[0]) || str[0] == '-') { | ||||
| absl::optional<signed_type> ParseSigned(absl::string_view str, int base) { | ||||
|   if (str.empty()) | ||||
|     return absl::nullopt; | ||||
|  | ||||
|   if (isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-') { | ||||
|     std::string str_str(str); | ||||
|     char* end = nullptr; | ||||
|     errno = 0; | ||||
|     const signed_type value = std::strtoll(str, &end, base); | ||||
|     if (end && *end == '\0' && errno == 0) { | ||||
|     const signed_type value = std::strtoll(str_str.c_str(), &end, base); | ||||
|     // Check for errors and also make sure that there were no embedded nuls in | ||||
|     // the input string. | ||||
|     if (end == str_str.c_str() + str_str.size() && errno == 0) { | ||||
|       return value; | ||||
|     } | ||||
|   } | ||||
|   return absl::nullopt; | ||||
| } | ||||
|  | ||||
| absl::optional<unsigned_type> ParseUnsigned(const char* str, int base) { | ||||
|   RTC_DCHECK(str); | ||||
|   if (isdigit(str[0]) || str[0] == '-') { | ||||
| absl::optional<unsigned_type> ParseUnsigned(absl::string_view str, int base) { | ||||
|   if (str.empty()) | ||||
|     return absl::nullopt; | ||||
|  | ||||
|   if (isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-') { | ||||
|     std::string str_str(str); | ||||
|     // Explicitly discard negative values. std::strtoull parsing causes unsigned | ||||
|     // wraparound. We cannot just reject values that start with -, though, since | ||||
|     // -0 is perfectly fine, as is -0000000000000000000000000000000. | ||||
|     const bool is_negative = str[0] == '-'; | ||||
|     char* end = nullptr; | ||||
|     errno = 0; | ||||
|     const unsigned_type value = std::strtoull(str, &end, base); | ||||
|     if (end && *end == '\0' && errno == 0 && (value == 0 || !is_negative)) { | ||||
|     const unsigned_type value = std::strtoull(str_str.c_str(), &end, base); | ||||
|     // Check for errors and also make sure that there were no embedded nuls in | ||||
|     // the input string. | ||||
|     if (end == str_str.c_str() + str_str.size() && errno == 0 && | ||||
|         (value == 0 || !is_negative)) { | ||||
|       return value; | ||||
|     } | ||||
|   } | ||||
| @@ -69,22 +80,25 @@ inline long double StrToT(const char* str, char** str_end) { | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| absl::optional<T> ParseFloatingPoint(const char* str) { | ||||
|   RTC_DCHECK(str); | ||||
|   if (*str == '\0') | ||||
| absl::optional<T> ParseFloatingPoint(absl::string_view str) { | ||||
|   if (str.empty()) | ||||
|     return absl::nullopt; | ||||
|  | ||||
|   if (str[0] == '\0') | ||||
|     return absl::nullopt; | ||||
|   std::string str_str(str); | ||||
|   char* end = nullptr; | ||||
|   errno = 0; | ||||
|   const T value = StrToT<T>(str, &end); | ||||
|   if (end && *end == '\0' && errno == 0) { | ||||
|   const T value = StrToT<T>(str_str.c_str(), &end); | ||||
|   if (end == str_str.c_str() + str_str.size() && errno == 0) { | ||||
|     return value; | ||||
|   } | ||||
|   return absl::nullopt; | ||||
| } | ||||
|  | ||||
| template absl::optional<float> ParseFloatingPoint(const char* str); | ||||
| template absl::optional<double> ParseFloatingPoint(const char* str); | ||||
| template absl::optional<long double> ParseFloatingPoint(const char* str); | ||||
| template absl::optional<float> ParseFloatingPoint(absl::string_view str); | ||||
| template absl::optional<double> ParseFloatingPoint(absl::string_view str); | ||||
| template absl::optional<long double> ParseFloatingPoint(absl::string_view str); | ||||
|  | ||||
| }  // namespace string_to_number_internal | ||||
| }  // namespace rtc | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| #include <string> | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "absl/types/optional.h" | ||||
|  | ||||
| namespace rtc { | ||||
| @@ -25,10 +26,9 @@ namespace rtc { | ||||
| // functions (std::stoi, etc.) indicate errors by throwing exceptions, which | ||||
| // are disabled in WebRTC. | ||||
| // | ||||
| // Integers are parsed using one of the following functions: | ||||
| //   absl::optional<int-type> StringToNumber(const char* str, int base = 10); | ||||
| //   absl::optional<int-type> StringToNumber(const std::string& str, | ||||
| //                                          int base = 10); | ||||
| // Integers are parsed using: | ||||
| //   absl::optional<int-type> StringToNumber(absl::string_view str, | ||||
| //                                           int base = 10); | ||||
| // | ||||
| // These functions parse a value from the beginning of a string into one of the | ||||
| // fundamental integer types, or returns an empty Optional if parsing | ||||
| @@ -38,26 +38,23 @@ namespace rtc { | ||||
| // By setting base to 0, one of octal, decimal or hexadecimal will be | ||||
| // detected from the string's prefix (0, nothing or 0x, respectively). | ||||
| // If non-zero, base can be set to a value between 2 and 36 inclusively. | ||||
| // | ||||
| // If desired, this interface could be extended with support for floating-point | ||||
| // types. | ||||
|  | ||||
| namespace string_to_number_internal { | ||||
| // These must be (unsigned) long long, to match the signature of strto(u)ll. | ||||
| using unsigned_type = unsigned long long;  // NOLINT(runtime/int) | ||||
| using signed_type = long long;             // NOLINT(runtime/int) | ||||
|  | ||||
| absl::optional<signed_type> ParseSigned(const char* str, int base); | ||||
| absl::optional<unsigned_type> ParseUnsigned(const char* str, int base); | ||||
| absl::optional<signed_type> ParseSigned(absl::string_view str, int base); | ||||
| absl::optional<unsigned_type> ParseUnsigned(absl::string_view str, int base); | ||||
|  | ||||
| template <typename T> | ||||
| absl::optional<T> ParseFloatingPoint(const char* str); | ||||
| absl::optional<T> ParseFloatingPoint(absl::string_view str); | ||||
| }  // namespace string_to_number_internal | ||||
|  | ||||
| template <typename T> | ||||
| typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, | ||||
|                         absl::optional<T>>::type | ||||
| StringToNumber(const char* str, int base = 10) { | ||||
| StringToNumber(absl::string_view str, int base = 10) { | ||||
|   using string_to_number_internal::signed_type; | ||||
|   static_assert( | ||||
|       std::numeric_limits<T>::max() <= | ||||
| @@ -78,7 +75,7 @@ template <typename T> | ||||
| typename std::enable_if<std::is_integral<T>::value && | ||||
|                             std::is_unsigned<T>::value, | ||||
|                         absl::optional<T>>::type | ||||
| StringToNumber(const char* str, int base = 10) { | ||||
| StringToNumber(absl::string_view str, int base = 10) { | ||||
|   using string_to_number_internal::unsigned_type; | ||||
|   static_assert(std::numeric_limits<T>::max() <= | ||||
|                     std::numeric_limits<unsigned_type>::max(), | ||||
| @@ -95,7 +92,7 @@ StringToNumber(const char* str, int base = 10) { | ||||
| template <typename T> | ||||
| typename std::enable_if<std::is_floating_point<T>::value, | ||||
|                         absl::optional<T>>::type | ||||
| StringToNumber(const char* str, int base = 10) { | ||||
| StringToNumber(absl::string_view str, int base = 10) { | ||||
|   static_assert( | ||||
|       std::numeric_limits<T>::max() <= std::numeric_limits<long double>::max(), | ||||
|       "StringToNumber only supports floating-point numbers as large " | ||||
| @@ -103,14 +100,6 @@ StringToNumber(const char* str, int base = 10) { | ||||
|   return string_to_number_internal::ParseFloatingPoint<T>(str); | ||||
| } | ||||
|  | ||||
| // The std::string overloads only exists if there is a matching const char* | ||||
| // version. | ||||
| template <typename T> | ||||
| auto StringToNumber(const std::string& str, int base = 10) | ||||
|     -> decltype(StringToNumber<T>(str.c_str(), base)) { | ||||
|   return StringToNumber<T>(str.c_str(), base); | ||||
| } | ||||
|  | ||||
| }  // namespace rtc | ||||
|  | ||||
| #endif  // RTC_BASE_STRING_TO_NUMBER_H_ | ||||
|   | ||||
| @@ -10,39 +10,23 @@ | ||||
|  | ||||
| #include "rtc_base/string_utils.h" | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| size_t strcpyn(char* buffer, | ||||
|                size_t buflen, | ||||
|                const char* source, | ||||
|                size_t srclen /* = SIZE_UNKNOWN */) { | ||||
| size_t strcpyn(char* buffer, size_t buflen, absl::string_view source) { | ||||
|   if (buflen <= 0) | ||||
|     return 0; | ||||
|  | ||||
|   if (srclen == SIZE_UNKNOWN) { | ||||
|     srclen = strlen(source); | ||||
|   } | ||||
|   size_t srclen = source.length(); | ||||
|   if (srclen >= buflen) { | ||||
|     srclen = buflen - 1; | ||||
|   } | ||||
|   memcpy(buffer, source, srclen); | ||||
|   memcpy(buffer, source.data(), srclen); | ||||
|   buffer[srclen] = 0; | ||||
|   return srclen; | ||||
| } | ||||
|  | ||||
| static const char kWhitespace[] = " \n\r\t"; | ||||
|  | ||||
| std::string string_trim(const std::string& s) { | ||||
|   std::string::size_type first = s.find_first_not_of(kWhitespace); | ||||
|   std::string::size_type last = s.find_last_not_of(kWhitespace); | ||||
|  | ||||
|   if (first == std::string::npos || last == std::string::npos) { | ||||
|     return std::string(""); | ||||
|   } | ||||
|  | ||||
|   return s.substr(first, last - first + 1); | ||||
| } | ||||
|  | ||||
| std::string ToHex(const int i) { | ||||
|   char buffer[50]; | ||||
|   snprintf(buffer, sizeof(buffer), "%x", i); | ||||
|   | ||||
| @@ -11,11 +11,11 @@ | ||||
| #ifndef RTC_BASE_STRING_UTILS_H_ | ||||
| #define RTC_BASE_STRING_UTILS_H_ | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| #include <malloc.h> | ||||
| #include <wchar.h> | ||||
| @@ -30,15 +30,26 @@ | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| const size_t SIZE_UNKNOWN = static_cast<size_t>(-1); | ||||
|  | ||||
| // An absl::string_view comparator functor for use with container types such as | ||||
| // std::map that support heterogenous lookup. | ||||
| // | ||||
| // Example usage: | ||||
| // std::map<std::string, int, rtc::AbslStringViewCmp> my_map; | ||||
| struct AbslStringViewCmp { | ||||
|   using is_transparent = void; | ||||
|   bool operator()(absl::string_view a, absl::string_view b) const { | ||||
|     return a < b; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // Safe version of strncpy that always nul-terminate. | ||||
| size_t strcpyn(char* buffer, | ||||
|                size_t buflen, | ||||
|                const char* source, | ||||
|                size_t srclen = SIZE_UNKNOWN); | ||||
| size_t strcpyn(char* buffer, size_t buflen, absl::string_view source); | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // UTF helpers (Windows only) | ||||
| @@ -57,7 +68,7 @@ inline std::wstring ToUtf16(const char* utf8, size_t len) { | ||||
|   return ws; | ||||
| } | ||||
|  | ||||
| inline std::wstring ToUtf16(const std::string& str) { | ||||
| inline std::wstring ToUtf16(absl::string_view str) { | ||||
|   return ToUtf16(str.data(), str.length()); | ||||
| } | ||||
|  | ||||
| @@ -82,11 +93,45 @@ inline std::string ToUtf8(const std::wstring& wstr) { | ||||
|  | ||||
| #endif  // WEBRTC_WIN | ||||
|  | ||||
| // Remove leading and trailing whitespaces. | ||||
| std::string string_trim(const std::string& s); | ||||
|  | ||||
| // TODO(jonasolsson): replace with absl::Hex when that becomes available. | ||||
| std::string ToHex(const int i); | ||||
| std::string ToHex(int i); | ||||
|  | ||||
| // CompileTimeString comprises of a string-like object which can be used as a | ||||
| // regular const char* in compile time and supports concatenation. Useful for | ||||
| // concatenating constexpr strings in for example macro declarations. | ||||
| namespace rtc_base_string_utils_internal { | ||||
| template <int NPlus1> | ||||
| struct CompileTimeString { | ||||
|   char string[NPlus1] = {0}; | ||||
|   constexpr CompileTimeString() = default; | ||||
|   template <int MPlus1> | ||||
|   explicit constexpr CompileTimeString(const char (&chars)[MPlus1]) { | ||||
|     char* chars_pointer = string; | ||||
|     for (auto c : chars) | ||||
|       *chars_pointer++ = c; | ||||
|   } | ||||
|   template <int MPlus1> | ||||
|   constexpr auto Concat(CompileTimeString<MPlus1> b) { | ||||
|     CompileTimeString<NPlus1 + MPlus1 - 1> result; | ||||
|     char* chars_pointer = result.string; | ||||
|     for (auto c : string) | ||||
|       *chars_pointer++ = c; | ||||
|     chars_pointer = result.string + NPlus1 - 1; | ||||
|     for (auto c : b.string) | ||||
|       *chars_pointer++ = c; | ||||
|     result.string[NPlus1 + MPlus1 - 2] = 0; | ||||
|     return result; | ||||
|   } | ||||
|   constexpr operator const char*() { return string; } | ||||
| }; | ||||
| }  // namespace rtc_base_string_utils_internal | ||||
|  | ||||
| // Makes a constexpr CompileTimeString<X> without having to specify X | ||||
| // explicitly. | ||||
| template <int N> | ||||
| constexpr auto MakeCompileTimeString(const char (&a)[N]) { | ||||
|   return rtc_base_string_utils_internal::CompileTimeString<N>(a); | ||||
| } | ||||
|  | ||||
| }  // namespace rtc | ||||
|  | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| #include <cstdio> | ||||
| #include <cstring> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/numerics/safe_minmax.h" | ||||
|  | ||||
| @@ -26,16 +27,20 @@ SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView<char> buffer) | ||||
|   RTC_DCHECK(IsConsistent()); | ||||
| } | ||||
|  | ||||
| SimpleStringBuilder& SimpleStringBuilder::operator<<(const char* str) { | ||||
|   return Append(str, strlen(str)); | ||||
| } | ||||
|  | ||||
| SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) { | ||||
|   return Append(&ch, 1); | ||||
|   return operator<<(absl::string_view(&ch, 1)); | ||||
| } | ||||
|  | ||||
| SimpleStringBuilder& SimpleStringBuilder::operator<<(const std::string& str) { | ||||
|   return Append(str.c_str(), str.length()); | ||||
| SimpleStringBuilder& SimpleStringBuilder::operator<<(absl::string_view str) { | ||||
|   RTC_DCHECK_LT(size_ + str.length(), buffer_.size()) | ||||
|       << "Buffer size was insufficient"; | ||||
|   const size_t chars_added = | ||||
|       rtc::SafeMin(str.length(), buffer_.size() - size_ - 1); | ||||
|   memcpy(&buffer_[size_], str.data(), chars_added); | ||||
|   size_ += chars_added; | ||||
|   buffer_[size_] = '\0'; | ||||
|   RTC_DCHECK(IsConsistent()); | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| // Numeric conversion routines. | ||||
| @@ -98,7 +103,7 @@ SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) { | ||||
|   } else { | ||||
|     // This should never happen, but we're paranoid, so re-write the | ||||
|     // terminator in case vsnprintf() overwrote it. | ||||
|     RTC_NOTREACHED(); | ||||
|     RTC_DCHECK_NOTREACHED(); | ||||
|     buffer_[size_] = '\0'; | ||||
|   } | ||||
|   va_end(args); | ||||
| @@ -106,18 +111,6 @@ SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) { | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| SimpleStringBuilder& SimpleStringBuilder::Append(const char* str, | ||||
|                                                  size_t length) { | ||||
|   RTC_DCHECK_LT(size_ + length, buffer_.size()) | ||||
|       << "Buffer size was insufficient"; | ||||
|   const size_t chars_added = rtc::SafeMin(length, buffer_.size() - size_ - 1); | ||||
|   memcpy(&buffer_[size_], str, chars_added); | ||||
|   size_ += chars_added; | ||||
|   buffer_[size_] = '\0'; | ||||
|   RTC_DCHECK(IsConsistent()); | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) { | ||||
|   va_list args, copy; | ||||
|   va_start(args, fmt); | ||||
|   | ||||
| @@ -25,16 +25,15 @@ namespace rtc { | ||||
| // when you might otherwise be tempted to use a stringstream (discouraged for | ||||
| // anything except logging). It uses a fixed-size buffer provided by the caller | ||||
| // and concatenates strings and numbers into it, allowing the results to be | ||||
| // read via |str()|. | ||||
| // read via `str()`. | ||||
| class SimpleStringBuilder { | ||||
|  public: | ||||
|   explicit SimpleStringBuilder(rtc::ArrayView<char> buffer); | ||||
|   SimpleStringBuilder(const SimpleStringBuilder&) = delete; | ||||
|   SimpleStringBuilder& operator=(const SimpleStringBuilder&) = delete; | ||||
|  | ||||
|   SimpleStringBuilder& operator<<(const char* str); | ||||
|   SimpleStringBuilder& operator<<(char ch); | ||||
|   SimpleStringBuilder& operator<<(const std::string& str); | ||||
|   SimpleStringBuilder& operator<<(absl::string_view str); | ||||
|   SimpleStringBuilder& operator<<(int i); | ||||
|   SimpleStringBuilder& operator<<(unsigned i); | ||||
|   SimpleStringBuilder& operator<<(long i);                // NOLINT | ||||
| @@ -45,12 +44,12 @@ class SimpleStringBuilder { | ||||
|   SimpleStringBuilder& operator<<(double f); | ||||
|   SimpleStringBuilder& operator<<(long double f); | ||||
|  | ||||
|   // Returns a pointer to the built string. The name |str()| is borrowed for | ||||
|   // Returns a pointer to the built string. The name `str()` is borrowed for | ||||
|   // compatibility reasons as we replace usage of stringstream throughout the | ||||
|   // code base. | ||||
|   const char* str() const { return buffer_.data(); } | ||||
|  | ||||
|   // Returns the length of the string. The name |size()| is picked for STL | ||||
|   // Returns the length of the string. The name `size()` is picked for STL | ||||
|   // compatibility reasons. | ||||
|   size_t size() const { return size_; } | ||||
|  | ||||
| @@ -61,10 +60,6 @@ class SimpleStringBuilder { | ||||
|   SimpleStringBuilder& | ||||
|   AppendFormat(const char* fmt, ...); | ||||
|  | ||||
|   // An alternate way from operator<<() to append a string. This variant is | ||||
|   // slightly more efficient when the length of the string to append, is known. | ||||
|   SimpleStringBuilder& Append(const char* str, size_t length); | ||||
|  | ||||
|  private: | ||||
|   bool IsConsistent() const { | ||||
|     return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0'; | ||||
|   | ||||
| @@ -17,8 +17,8 @@ | ||||
| #include <utility> | ||||
| #include <vector> | ||||
|  | ||||
| #include "absl/base/attributes.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/system/unused.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| @@ -127,7 +127,7 @@ class SwapQueue { | ||||
|   // When specified, the T given in *input must pass the ItemVerifier() test. | ||||
|   // The contents of *input after the call are then also guaranteed to pass the | ||||
|   // ItemVerifier() test. | ||||
|   bool Insert(T* input) RTC_WARN_UNUSED_RESULT { | ||||
|   ABSL_MUST_USE_RESULT bool Insert(T* input) { | ||||
|     RTC_DCHECK(input); | ||||
|  | ||||
|     RTC_DCHECK(queue_item_verifier_(*input)); | ||||
| @@ -168,7 +168,7 @@ class SwapQueue { | ||||
|   // empty). When specified, The T given in *output must pass the ItemVerifier() | ||||
|   // test and the contents of *output after the call are then also guaranteed to | ||||
|   // pass the ItemVerifier() test. | ||||
|   bool Remove(T* output) RTC_WARN_UNUSED_RESULT { | ||||
|   ABSL_MUST_USE_RESULT bool Remove(T* output) { | ||||
|     RTC_DCHECK(output); | ||||
|  | ||||
|     RTC_DCHECK(queue_item_verifier_(*output)); | ||||
|   | ||||
| @@ -20,9 +20,8 @@ rtc_library("yield") { | ||||
|   deps = [] | ||||
| } | ||||
|  | ||||
| rtc_library("mutex") { | ||||
| rtc_source_set("mutex") { | ||||
|   sources = [ | ||||
|     "mutex.cc", | ||||
|     "mutex.h", | ||||
|     "mutex_critical_section.h", | ||||
|     "mutex_pthread.h", | ||||
| @@ -36,7 +35,7 @@ rtc_library("mutex") { | ||||
|     "..:checks", | ||||
|     "..:macromagic", | ||||
|     "..:platform_thread_types", | ||||
|     "../system:unused", | ||||
|     "../system:no_unique_address", | ||||
|   ] | ||||
|   absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] | ||||
|   if (rtc_use_absl_mutex) { | ||||
| @@ -44,33 +43,15 @@ rtc_library("mutex") { | ||||
|   } | ||||
| } | ||||
|  | ||||
| rtc_library("rw_lock_wrapper") { | ||||
|   public = [ "rw_lock_wrapper.h" ] | ||||
|   sources = [ "rw_lock_wrapper.cc" ] | ||||
|   deps = [ "..:macromagic" ] | ||||
|   if (is_win) { | ||||
|     sources += [ | ||||
|       "rw_lock_win.cc", | ||||
|       "rw_lock_win.h", | ||||
|     ] | ||||
|     deps += [ "..:logging" ] | ||||
|   } else { | ||||
|     sources += [ | ||||
|       "rw_lock_posix.cc", | ||||
|       "rw_lock_posix.h", | ||||
|     ] | ||||
|   } | ||||
| } | ||||
|  | ||||
| rtc_library("sequence_checker") { | ||||
| rtc_library("sequence_checker_internal") { | ||||
|   visibility = [ "../../api:sequence_checker" ] | ||||
|   sources = [ | ||||
|     "sequence_checker.cc", | ||||
|     "sequence_checker.h", | ||||
|     "sequence_checker_internal.cc", | ||||
|     "sequence_checker_internal.h", | ||||
|   ] | ||||
|   deps = [ | ||||
|     ":mutex", | ||||
|     "..:checks", | ||||
|     "..:criticalsection", | ||||
|     "..:macromagic", | ||||
|     "..:platform_thread_types", | ||||
|     "..:stringutils", | ||||
| @@ -91,7 +72,7 @@ rtc_library("yield_policy") { | ||||
|   ] | ||||
| } | ||||
|  | ||||
| if (rtc_include_tests) { | ||||
| if (rtc_include_tests && rtc_enable_google_benchmarks) { | ||||
|   rtc_library("synchronization_unittests") { | ||||
|     testonly = true | ||||
|     sources = [ | ||||
| @@ -104,8 +85,9 @@ if (rtc_include_tests) { | ||||
|       ":yield_policy", | ||||
|       "..:checks", | ||||
|       "..:macromagic", | ||||
|       "..:rtc_base", | ||||
|       "..:platform_thread", | ||||
|       "..:rtc_event", | ||||
|       "..:threading", | ||||
|       "../../test:test_support", | ||||
|       "//third_party/google_benchmark", | ||||
|     ] | ||||
| @@ -120,19 +102,4 @@ if (rtc_include_tests) { | ||||
|       "//third_party/google_benchmark", | ||||
|     ] | ||||
|   } | ||||
|  | ||||
|   rtc_library("sequence_checker_unittests") { | ||||
|     testonly = true | ||||
|  | ||||
|     sources = [ "sequence_checker_unittest.cc" ] | ||||
|     deps = [ | ||||
|       ":sequence_checker", | ||||
|       "..:checks", | ||||
|       "..:rtc_base_approved", | ||||
|       "..:task_queue_for_test", | ||||
|       "../../api:function_view", | ||||
|       "../../test:test_main", | ||||
|       "../../test:test_support", | ||||
|     ] | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,39 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright 2020 The WebRTC Project Authors. All rights reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #include "rtc_base/synchronization/mutex.h" | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/synchronization/yield.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| #if !defined(WEBRTC_ABSL_MUTEX) | ||||
| void GlobalMutex::Lock() { | ||||
|   while (mutex_locked_.exchange(1)) { | ||||
|     YieldCurrentThread(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void GlobalMutex::Unlock() { | ||||
|   int old = mutex_locked_.exchange(0); | ||||
|   RTC_DCHECK_EQ(old, 1) << "Unlock called without calling Lock first"; | ||||
| } | ||||
|  | ||||
| GlobalMutexLock::GlobalMutexLock(GlobalMutex* mutex) : mutex_(mutex) { | ||||
|   mutex_->Lock(); | ||||
| } | ||||
|  | ||||
| GlobalMutexLock::~GlobalMutexLock() { | ||||
|   mutex_->Unlock(); | ||||
| } | ||||
| #endif  // #if !defined(WEBRTC_ABSL_MUTEX) | ||||
|  | ||||
| }  // namespace webrtc | ||||
| @@ -13,9 +13,9 @@ | ||||
|  | ||||
| #include <atomic> | ||||
|  | ||||
| #include "absl/base/attributes.h" | ||||
| #include "absl/base/const_init.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/system/unused.h" | ||||
| #include "rtc_base/thread_annotations.h" | ||||
|  | ||||
| #if defined(WEBRTC_ABSL_MUTEX) | ||||
| @@ -38,15 +38,15 @@ class RTC_LOCKABLE Mutex final { | ||||
|   Mutex(const Mutex&) = delete; | ||||
|   Mutex& operator=(const Mutex&) = delete; | ||||
|  | ||||
|   void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { | ||||
|     impl_.Lock(); | ||||
|   } | ||||
|   RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { | ||||
|   void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { impl_.Lock(); } | ||||
|   ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { | ||||
|     return impl_.TryLock(); | ||||
|   } | ||||
|   void Unlock() RTC_UNLOCK_FUNCTION() { | ||||
|     impl_.Unlock(); | ||||
|   } | ||||
|   // Return immediately if this thread holds the mutex, or RTC_DCHECK_IS_ON==0. | ||||
|   // Otherwise, may report an error (typically by crashing with a diagnostic), | ||||
|   // or may return immediately. | ||||
|   void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { impl_.AssertHeld(); } | ||||
|   void Unlock() RTC_UNLOCK_FUNCTION() { impl_.Unlock(); } | ||||
|  | ||||
|  private: | ||||
|   MutexImpl impl_; | ||||
| @@ -68,41 +68,6 @@ class RTC_SCOPED_LOCKABLE MutexLock final { | ||||
|   Mutex* mutex_; | ||||
| }; | ||||
|  | ||||
| // A mutex used to protect global variables. Do NOT use for other purposes. | ||||
| #if defined(WEBRTC_ABSL_MUTEX) | ||||
| using GlobalMutex = absl::Mutex; | ||||
| using GlobalMutexLock = absl::MutexLock; | ||||
| #else | ||||
| class RTC_LOCKABLE GlobalMutex final { | ||||
|  public: | ||||
|   GlobalMutex(const GlobalMutex&) = delete; | ||||
|   GlobalMutex& operator=(const GlobalMutex&) = delete; | ||||
|  | ||||
|   constexpr explicit GlobalMutex(absl::ConstInitType /*unused*/) | ||||
|       : mutex_locked_(0) {} | ||||
|  | ||||
|   void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION(); | ||||
|   void Unlock() RTC_UNLOCK_FUNCTION(); | ||||
|  | ||||
|  private: | ||||
|   std::atomic<int> mutex_locked_;  // 0 means lock not taken, 1 means taken. | ||||
| }; | ||||
|  | ||||
| // GlobalMutexLock, for serializing execution through a scope. | ||||
| class RTC_SCOPED_LOCKABLE GlobalMutexLock final { | ||||
|  public: | ||||
|   GlobalMutexLock(const GlobalMutexLock&) = delete; | ||||
|   GlobalMutexLock& operator=(const GlobalMutexLock&) = delete; | ||||
|  | ||||
|   explicit GlobalMutexLock(GlobalMutex* mutex) | ||||
|       RTC_EXCLUSIVE_LOCK_FUNCTION(mutex_); | ||||
|   ~GlobalMutexLock() RTC_UNLOCK_FUNCTION(); | ||||
|  | ||||
|  private: | ||||
|   GlobalMutex* mutex_; | ||||
| }; | ||||
| #endif  // if defined(WEBRTC_ABSL_MUTEX) | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_SYNCHRONIZATION_MUTEX_H_ | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| #include <sal.h>  // must come after windows headers. | ||||
| // clang-format on | ||||
|  | ||||
| #include "absl/base/attributes.h" | ||||
| #include "rtc_base/thread_annotations.h" | ||||
|  | ||||
| namespace webrtc { | ||||
| @@ -37,9 +38,10 @@ class RTC_LOCKABLE MutexImpl final { | ||||
|   void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { | ||||
|     EnterCriticalSection(&critical_section_); | ||||
|   } | ||||
|   RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { | ||||
|   ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { | ||||
|     return TryEnterCriticalSection(&critical_section_) != FALSE; | ||||
|   } | ||||
|   void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() {} | ||||
|   void Unlock() RTC_UNLOCK_FUNCTION() { | ||||
|     LeaveCriticalSection(&critical_section_); | ||||
|   } | ||||
|   | ||||
| @@ -18,6 +18,8 @@ | ||||
| #include <pthread_spis.h> | ||||
| #endif | ||||
|  | ||||
| #include "absl/base/attributes.h" | ||||
| #include "rtc_base/system/no_unique_address.h" | ||||
| #include "rtc_base/thread_annotations.h" | ||||
|  | ||||
| namespace webrtc { | ||||
| @@ -38,14 +40,60 @@ class RTC_LOCKABLE MutexImpl final { | ||||
|   MutexImpl& operator=(const MutexImpl&) = delete; | ||||
|   ~MutexImpl() { pthread_mutex_destroy(&mutex_); } | ||||
|  | ||||
|   void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { pthread_mutex_lock(&mutex_); } | ||||
|   RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { | ||||
|     return pthread_mutex_trylock(&mutex_) == 0; | ||||
|   void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { | ||||
|     pthread_mutex_lock(&mutex_); | ||||
|     owner_.SetOwner(); | ||||
|   } | ||||
|   ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { | ||||
|     if (pthread_mutex_trylock(&mutex_) != 0) { | ||||
|       return false; | ||||
|     } | ||||
|     owner_.SetOwner(); | ||||
|     return true; | ||||
|   } | ||||
|   void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { owner_.AssertOwned(); } | ||||
|   void Unlock() RTC_UNLOCK_FUNCTION() { | ||||
|     owner_.ClearOwner(); | ||||
|     pthread_mutex_unlock(&mutex_); | ||||
|   } | ||||
|   void Unlock() RTC_UNLOCK_FUNCTION() { pthread_mutex_unlock(&mutex_); } | ||||
|  | ||||
|  private: | ||||
|   class OwnerRecord { | ||||
|    public: | ||||
| #if !RTC_DCHECK_IS_ON | ||||
|     void SetOwner() {} | ||||
|     void ClearOwner() {} | ||||
|     void AssertOwned() const {} | ||||
| #else | ||||
|     void SetOwner() { | ||||
|       latest_owner_ = pthread_self(); | ||||
|       is_owned_ = true; | ||||
|     } | ||||
|     void ClearOwner() { is_owned_ = false; } | ||||
|     void AssertOwned() const { | ||||
|       RTC_CHECK(is_owned_); | ||||
|       RTC_CHECK(pthread_equal(latest_owner_, pthread_self())); | ||||
|     } | ||||
|  | ||||
|    private: | ||||
|     // Use two separate primitive types, rather than absl::optional, since the | ||||
|     // data race described below might invalidate absl::optional invariants. | ||||
|     bool is_owned_ = false; | ||||
|     pthread_t latest_owner_ = pthread_self(); | ||||
| #endif | ||||
|   }; | ||||
|  | ||||
|   pthread_mutex_t mutex_; | ||||
|   // This record is modified only with the mutex held, and hence, calls to | ||||
|   // AssertHeld where mutex is held are race-free and will always succeed. | ||||
|   // | ||||
|   // The failure case is more subtle: If AssertHeld is called from some thread | ||||
|   // not holding the mutex, and RTC_DCHECK_IS_ON==1, we have a data race. It is | ||||
|   // highly likely that the calling thread will see `is_owned_` false or | ||||
|   // `latest_owner_` different from itself, and crash. But it may fail to crash, | ||||
|   // and invoke some other undefined behavior (still, this race can happen only | ||||
|   // when RTC_DCHECK_IS_ON==1). | ||||
|   RTC_NO_UNIQUE_ADDRESS OwnerRecord owner_; | ||||
| }; | ||||
|  | ||||
| }  // namespace webrtc | ||||
|   | ||||
| @@ -1,52 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #include "rtc_base/synchronization/rw_lock_posix.h" | ||||
|  | ||||
| #include <stddef.h> | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| RWLockPosix::RWLockPosix() : lock_() {} | ||||
|  | ||||
| RWLockPosix::~RWLockPosix() { | ||||
|   pthread_rwlock_destroy(&lock_); | ||||
| } | ||||
|  | ||||
| RWLockPosix* RWLockPosix::Create() { | ||||
|   RWLockPosix* ret_val = new RWLockPosix(); | ||||
|   if (!ret_val->Init()) { | ||||
|     delete ret_val; | ||||
|     return NULL; | ||||
|   } | ||||
|   return ret_val; | ||||
| } | ||||
|  | ||||
| bool RWLockPosix::Init() { | ||||
|   return pthread_rwlock_init(&lock_, 0) == 0; | ||||
| } | ||||
|  | ||||
| void RWLockPosix::AcquireLockExclusive() { | ||||
|   pthread_rwlock_wrlock(&lock_); | ||||
| } | ||||
|  | ||||
| void RWLockPosix::ReleaseLockExclusive() { | ||||
|   pthread_rwlock_unlock(&lock_); | ||||
| } | ||||
|  | ||||
| void RWLockPosix::AcquireLockShared() { | ||||
|   pthread_rwlock_rdlock(&lock_); | ||||
| } | ||||
|  | ||||
| void RWLockPosix::ReleaseLockShared() { | ||||
|   pthread_rwlock_unlock(&lock_); | ||||
| } | ||||
|  | ||||
| }  // namespace webrtc | ||||
| @@ -1,40 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_ | ||||
| #define RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_ | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| #include "rtc_base/synchronization/rw_lock_wrapper.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| class RWLockPosix : public RWLockWrapper { | ||||
|  public: | ||||
|   static RWLockPosix* Create(); | ||||
|   ~RWLockPosix() override; | ||||
|  | ||||
|   void AcquireLockExclusive() override; | ||||
|   void ReleaseLockExclusive() override; | ||||
|  | ||||
|   void AcquireLockShared() override; | ||||
|   void ReleaseLockShared() override; | ||||
|  | ||||
|  private: | ||||
|   RWLockPosix(); | ||||
|   bool Init(); | ||||
|  | ||||
|   pthread_rwlock_t lock_; | ||||
| }; | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_ | ||||
| @@ -1,41 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #include "rtc_base/synchronization/rw_lock_win.h" | ||||
|  | ||||
| #include "rtc_base/logging.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| RWLockWin::RWLockWin() { | ||||
|   InitializeSRWLock(&lock_); | ||||
| } | ||||
|  | ||||
| RWLockWin* RWLockWin::Create() { | ||||
|   return new RWLockWin(); | ||||
| } | ||||
|  | ||||
| void RWLockWin::AcquireLockExclusive() { | ||||
|   AcquireSRWLockExclusive(&lock_); | ||||
| } | ||||
|  | ||||
| void RWLockWin::ReleaseLockExclusive() { | ||||
|   ReleaseSRWLockExclusive(&lock_); | ||||
| } | ||||
|  | ||||
| void RWLockWin::AcquireLockShared() { | ||||
|   AcquireSRWLockShared(&lock_); | ||||
| } | ||||
|  | ||||
| void RWLockWin::ReleaseLockShared() { | ||||
|   ReleaseSRWLockShared(&lock_); | ||||
| } | ||||
|  | ||||
| }  // namespace webrtc | ||||
| @@ -1,38 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_ | ||||
| #define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_ | ||||
|  | ||||
| #include <windows.h> | ||||
|  | ||||
| #include "rtc_base/synchronization/rw_lock_wrapper.h" | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| class RWLockWin : public RWLockWrapper { | ||||
|  public: | ||||
|   static RWLockWin* Create(); | ||||
|  | ||||
|   void AcquireLockExclusive() override; | ||||
|   void ReleaseLockExclusive() override; | ||||
|  | ||||
|   void AcquireLockShared() override; | ||||
|   void ReleaseLockShared() override; | ||||
|  | ||||
|  private: | ||||
|   RWLockWin(); | ||||
|  | ||||
|   SRWLOCK lock_; | ||||
| }; | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_ | ||||
| @@ -1,66 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_ | ||||
| #define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_ | ||||
|  | ||||
| #include "rtc_base/thread_annotations.h" | ||||
|  | ||||
| // Note, Windows pre-Vista version of RW locks are not supported natively. For | ||||
| // these OSs regular critical sections have been used to approximate RW lock | ||||
| // functionality and will therefore have worse performance. | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| class RTC_LOCKABLE RWLockWrapper { | ||||
|  public: | ||||
|   static RWLockWrapper* CreateRWLock(); | ||||
|   virtual ~RWLockWrapper() {} | ||||
|  | ||||
|   virtual void AcquireLockExclusive() RTC_EXCLUSIVE_LOCK_FUNCTION() = 0; | ||||
|   virtual void ReleaseLockExclusive() RTC_UNLOCK_FUNCTION() = 0; | ||||
|  | ||||
|   virtual void AcquireLockShared() RTC_SHARED_LOCK_FUNCTION() = 0; | ||||
|   virtual void ReleaseLockShared() RTC_UNLOCK_FUNCTION() = 0; | ||||
| }; | ||||
|  | ||||
| // RAII extensions of the RW lock. Prevents Acquire/Release missmatches and | ||||
| // provides more compact locking syntax. | ||||
| class RTC_SCOPED_LOCKABLE ReadLockScoped { | ||||
|  public: | ||||
|   explicit ReadLockScoped(RWLockWrapper& rw_lock) | ||||
|       RTC_SHARED_LOCK_FUNCTION(rw_lock) | ||||
|       : rw_lock_(rw_lock) { | ||||
|     rw_lock_.AcquireLockShared(); | ||||
|   } | ||||
|  | ||||
|   ~ReadLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockShared(); } | ||||
|  | ||||
|  private: | ||||
|   RWLockWrapper& rw_lock_; | ||||
| }; | ||||
|  | ||||
| class RTC_SCOPED_LOCKABLE WriteLockScoped { | ||||
|  public: | ||||
|   explicit WriteLockScoped(RWLockWrapper& rw_lock) | ||||
|       RTC_EXCLUSIVE_LOCK_FUNCTION(rw_lock) | ||||
|       : rw_lock_(rw_lock) { | ||||
|     rw_lock_.AcquireLockExclusive(); | ||||
|   } | ||||
|  | ||||
|   ~WriteLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockExclusive(); } | ||||
|  | ||||
|  private: | ||||
|   RWLockWrapper& rw_lock_; | ||||
| }; | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_ | ||||
| @@ -1,187 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright 2019 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
| #ifndef RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ | ||||
| #define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ | ||||
|  | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "api/task_queue/task_queue_base.h" | ||||
| #include "rtc_base/platform_thread_types.h" | ||||
| #include "rtc_base/synchronization/mutex.h" | ||||
| #include "rtc_base/system/rtc_export.h" | ||||
| #include "rtc_base/thread_annotations.h" | ||||
|  | ||||
| namespace webrtc { | ||||
| // Real implementation of SequenceChecker, for use in debug mode, or | ||||
| // for temporary use in release mode (e.g. to RTC_CHECK on a threading issue | ||||
| // seen only in the wild). | ||||
| // | ||||
| // Note: You should almost always use the SequenceChecker class to get the | ||||
| // right version for your build configuration. | ||||
| class RTC_EXPORT SequenceCheckerImpl { | ||||
|  public: | ||||
|   SequenceCheckerImpl(); | ||||
|   ~SequenceCheckerImpl(); | ||||
|  | ||||
|   bool IsCurrent() const; | ||||
|   // Changes the task queue or thread that is checked for in IsCurrent. This can | ||||
|   // be useful when an object may be created on one task queue / thread and then | ||||
|   // used exclusively on another thread. | ||||
|   void Detach(); | ||||
|  | ||||
|   // Returns a string that is formatted to match with the error string printed | ||||
|   // by RTC_CHECK() when a condition is not met. | ||||
|   // This is used in conjunction with the RTC_DCHECK_RUN_ON() macro. | ||||
|   std::string ExpectationToString() const; | ||||
|  | ||||
|  private: | ||||
|   mutable Mutex lock_; | ||||
|   // These are mutable so that IsCurrent can set them. | ||||
|   mutable bool attached_ RTC_GUARDED_BY(lock_); | ||||
|   mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_); | ||||
|   mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_); | ||||
|   mutable const void* valid_system_queue_ RTC_GUARDED_BY(lock_); | ||||
| }; | ||||
|  | ||||
| // Do nothing implementation, for use in release mode. | ||||
| // | ||||
| // Note: You should almost always use the SequenceChecker class to get the | ||||
| // right version for your build configuration. | ||||
| class SequenceCheckerDoNothing { | ||||
|  public: | ||||
|   bool IsCurrent() const { return true; } | ||||
|   void Detach() {} | ||||
| }; | ||||
|  | ||||
| // SequenceChecker is a helper class used to help verify that some methods | ||||
| // of a class are called on the same task queue or thread. A | ||||
| // SequenceChecker is bound to a a task queue if the object is | ||||
| // created on a task queue, or a thread otherwise. | ||||
| // | ||||
| // | ||||
| // Example: | ||||
| // class MyClass { | ||||
| //  public: | ||||
| //   void Foo() { | ||||
| //     RTC_DCHECK_RUN_ON(sequence_checker_); | ||||
| //     ... (do stuff) ... | ||||
| //   } | ||||
| // | ||||
| //  private: | ||||
| //   SequenceChecker sequence_checker_; | ||||
| // } | ||||
| // | ||||
| // In Release mode, IsCurrent will always return true. | ||||
| #if RTC_DCHECK_IS_ON | ||||
| class RTC_LOCKABLE SequenceChecker : public SequenceCheckerImpl {}; | ||||
| #else | ||||
| class RTC_LOCKABLE SequenceChecker : public SequenceCheckerDoNothing {}; | ||||
| #endif  // RTC_ENABLE_THREAD_CHECKER | ||||
|  | ||||
| namespace webrtc_seq_check_impl { | ||||
| // Helper class used by RTC_DCHECK_RUN_ON (see example usage below). | ||||
| class RTC_SCOPED_LOCKABLE SequenceCheckerScope { | ||||
|  public: | ||||
|   template <typename ThreadLikeObject> | ||||
|   explicit SequenceCheckerScope(const ThreadLikeObject* thread_like_object) | ||||
|       RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {} | ||||
|   SequenceCheckerScope(const SequenceCheckerScope&) = delete; | ||||
|   SequenceCheckerScope& operator=(const SequenceCheckerScope&) = delete; | ||||
|   ~SequenceCheckerScope() RTC_UNLOCK_FUNCTION() {} | ||||
|  | ||||
|   template <typename ThreadLikeObject> | ||||
|   static bool IsCurrent(const ThreadLikeObject* thread_like_object) { | ||||
|     return thread_like_object->IsCurrent(); | ||||
|   } | ||||
| }; | ||||
| }  // namespace webrtc_seq_check_impl | ||||
| }  // namespace webrtc | ||||
|  | ||||
| // RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate | ||||
| // variables are accessed from same thread/task queue. | ||||
| // Using tools designed to check mutexes, it checks at compile time everywhere | ||||
| // variable is access, there is a run-time dcheck thread/task queue is correct. | ||||
| // | ||||
| // class ThreadExample { | ||||
| //  public: | ||||
| //   void NeedVar1() { | ||||
| //     RTC_DCHECK_RUN_ON(network_thread_); | ||||
| //     transport_->Send(); | ||||
| //   } | ||||
| // | ||||
| //  private: | ||||
| //   rtc::Thread* network_thread_; | ||||
| //   int transport_ RTC_GUARDED_BY(network_thread_); | ||||
| // }; | ||||
| // | ||||
| // class SequenceCheckerExample { | ||||
| //  public: | ||||
| //   int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) { | ||||
| //     return var2_; | ||||
| //   } | ||||
| // | ||||
| //   void CallMeFromPacer() { | ||||
| //     RTC_DCHECK_RUN_ON(&pacer_sequence_checker_) | ||||
| //        << "Should be called from pacer"; | ||||
| //     CalledFromPacer(); | ||||
| //   } | ||||
| // | ||||
| //  private: | ||||
| //   int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_); | ||||
| //   SequenceChecker pacer_sequence_checker_; | ||||
| // }; | ||||
| // | ||||
| // class TaskQueueExample { | ||||
| //  public: | ||||
| //   class Encoder { | ||||
| //    public: | ||||
| //     rtc::TaskQueue* Queue() { return encoder_queue_; } | ||||
| //     void Encode() { | ||||
| //       RTC_DCHECK_RUN_ON(encoder_queue_); | ||||
| //       DoSomething(var_); | ||||
| //     } | ||||
| // | ||||
| //    private: | ||||
| //     rtc::TaskQueue* const encoder_queue_; | ||||
| //     Frame var_ RTC_GUARDED_BY(encoder_queue_); | ||||
| //   }; | ||||
| // | ||||
| //   void Encode() { | ||||
| //     // Will fail at runtime when DCHECK is enabled: | ||||
| //     // encoder_->Encode(); | ||||
| //     // Will work: | ||||
| //     rtc::scoped_refptr<Encoder> encoder = encoder_; | ||||
| //     encoder_->Queue()->PostTask([encoder] { encoder->Encode(); }); | ||||
| //   } | ||||
| // | ||||
| //  private: | ||||
| //   rtc::scoped_refptr<Encoder> encoder_; | ||||
| // } | ||||
|  | ||||
| // Document if a function expected to be called from same thread/task queue. | ||||
| #define RTC_RUN_ON(x) \ | ||||
|   RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x)) | ||||
|  | ||||
| namespace webrtc { | ||||
| std::string ExpectationToString(const webrtc::SequenceChecker* checker); | ||||
|  | ||||
| // Catch-all implementation for types other than explicitly supported above. | ||||
| template <typename ThreadLikeObject> | ||||
| std::string ExpectationToString(const ThreadLikeObject*) { | ||||
|   return std::string(); | ||||
| } | ||||
|  | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #define RTC_DCHECK_RUN_ON(x)                                              \ | ||||
|   webrtc::webrtc_seq_check_impl::SequenceCheckerScope seq_check_scope(x); \ | ||||
|   RTC_DCHECK((x)->IsCurrent()) << webrtc::ExpectationToString(x) | ||||
|  | ||||
| #endif  // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_ | ||||
| @@ -7,61 +7,39 @@ | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
| #include "rtc_base/synchronization/sequence_checker.h" | ||||
| #include "rtc_base/synchronization/sequence_checker_internal.h" | ||||
| 
 | ||||
| #if defined(WEBRTC_MAC) | ||||
| #include <dispatch/dispatch.h> | ||||
| #endif | ||||
| #include <string> | ||||
| 
 | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/strings/string_builder.h" | ||||
| 
 | ||||
| namespace webrtc { | ||||
| namespace { | ||||
| // On Mac, returns the label of the current dispatch queue; elsewhere, return
 | ||||
| // null.
 | ||||
| const void* GetSystemQueueRef() { | ||||
| #if defined(WEBRTC_MAC) | ||||
|   return dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); | ||||
| #else | ||||
|   return nullptr; | ||||
| #endif | ||||
| } | ||||
| namespace webrtc_sequence_checker_internal { | ||||
| 
 | ||||
| }  // namespace
 | ||||
| 
 | ||||
| std::string ExpectationToString(const webrtc::SequenceChecker* checker) { | ||||
| #if RTC_DCHECK_IS_ON | ||||
|   return checker->ExpectationToString(); | ||||
| #endif | ||||
|   return std::string(); | ||||
| } | ||||
| 
 | ||||
| SequenceCheckerImpl::SequenceCheckerImpl() | ||||
|     : attached_(true), | ||||
| SequenceCheckerImpl::SequenceCheckerImpl(bool attach_to_current_thread) | ||||
|     : attached_(attach_to_current_thread), | ||||
|       valid_thread_(rtc::CurrentThreadRef()), | ||||
|       valid_queue_(TaskQueueBase::Current()), | ||||
|       valid_system_queue_(GetSystemQueueRef()) {} | ||||
|       valid_queue_(TaskQueueBase::Current()) {} | ||||
| 
 | ||||
| SequenceCheckerImpl::~SequenceCheckerImpl() = default; | ||||
| SequenceCheckerImpl::SequenceCheckerImpl(TaskQueueBase* attached_queue) | ||||
|     : attached_(attached_queue != nullptr), | ||||
|       valid_thread_(rtc::PlatformThreadRef()), | ||||
|       valid_queue_(attached_queue) {} | ||||
| 
 | ||||
| bool SequenceCheckerImpl::IsCurrent() const { | ||||
|   const TaskQueueBase* const current_queue = TaskQueueBase::Current(); | ||||
|   const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); | ||||
|   const void* const current_system_queue = GetSystemQueueRef(); | ||||
|   MutexLock scoped_lock(&lock_); | ||||
|   if (!attached_) {  // Previously detached.
 | ||||
|     attached_ = true; | ||||
|     valid_thread_ = current_thread; | ||||
|     valid_queue_ = current_queue; | ||||
|     valid_system_queue_ = current_system_queue; | ||||
|     return true; | ||||
|   } | ||||
|   if (valid_queue_ || current_queue) { | ||||
|   if (valid_queue_) { | ||||
|     return valid_queue_ == current_queue; | ||||
|   } | ||||
|   if (valid_system_queue_ && valid_system_queue_ == current_system_queue) { | ||||
|     return true; | ||||
|   } | ||||
|   return rtc::IsThreadRefEqual(valid_thread_, current_thread); | ||||
| } | ||||
| 
 | ||||
| @@ -76,7 +54,6 @@ void SequenceCheckerImpl::Detach() { | ||||
| std::string SequenceCheckerImpl::ExpectationToString() const { | ||||
|   const TaskQueueBase* const current_queue = TaskQueueBase::Current(); | ||||
|   const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); | ||||
|   const void* const current_system_queue = GetSystemQueueRef(); | ||||
|   MutexLock scoped_lock(&lock_); | ||||
|   if (!attached_) | ||||
|     return "Checker currently not attached."; | ||||
| @@ -90,17 +67,13 @@ std::string SequenceCheckerImpl::ExpectationToString() const { | ||||
| 
 | ||||
|   rtc::StringBuilder message; | ||||
|   message.AppendFormat( | ||||
|       "# Expected: TQ: %p SysQ: %p Thread: %p\n" | ||||
|       "# Actual:   TQ: %p SysQ: %p Thread: %p\n", | ||||
|       valid_queue_, valid_system_queue_, | ||||
|       reinterpret_cast<const void*>(valid_thread_), current_queue, | ||||
|       current_system_queue, reinterpret_cast<const void*>(current_thread)); | ||||
|       "# Expected: TQ: %p Thread: %p\n" | ||||
|       "# Actual:   TQ: %p Thread: %p\n", | ||||
|       valid_queue_, reinterpret_cast<const void*>(valid_thread_), current_queue, | ||||
|       reinterpret_cast<const void*>(current_thread)); | ||||
| 
 | ||||
|   if ((valid_queue_ || current_queue) && valid_queue_ != current_queue) { | ||||
|     message << "TaskQueue doesn't match\n"; | ||||
|   } else if (valid_system_queue_ && | ||||
|              valid_system_queue_ != current_system_queue) { | ||||
|     message << "System queue doesn't match\n"; | ||||
|   } else if (!rtc::IsThreadRefEqual(valid_thread_, current_thread)) { | ||||
|     message << "Threads don't match\n"; | ||||
|   } | ||||
| @@ -109,4 +82,5 @@ std::string SequenceCheckerImpl::ExpectationToString() const { | ||||
| } | ||||
| #endif  // RTC_DCHECK_IS_ON
 | ||||
| 
 | ||||
| }  // namespace webrtc_sequence_checker_internal
 | ||||
| }  // namespace webrtc
 | ||||
							
								
								
									
										90
									
								
								webrtc/rtc_base/synchronization/sequence_checker_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								webrtc/rtc_base/synchronization/sequence_checker_internal.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| /* | ||||
|  *  Copyright 2020 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
| #ifndef RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_ | ||||
| #define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_ | ||||
|  | ||||
| #include <string> | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "api/task_queue/task_queue_base.h" | ||||
| #include "rtc_base/platform_thread_types.h" | ||||
| #include "rtc_base/synchronization/mutex.h" | ||||
| #include "rtc_base/system/rtc_export.h" | ||||
| #include "rtc_base/thread_annotations.h" | ||||
|  | ||||
| namespace webrtc { | ||||
| namespace webrtc_sequence_checker_internal { | ||||
|  | ||||
| // Real implementation of SequenceChecker, for use in debug mode, or | ||||
| // for temporary use in release mode (e.g. to RTC_CHECK on a threading issue | ||||
| // seen only in the wild). | ||||
| // | ||||
| // Note: You should almost always use the SequenceChecker class to get the | ||||
| // right version for your build configuration. | ||||
| class RTC_EXPORT SequenceCheckerImpl { | ||||
|  public: | ||||
|   explicit SequenceCheckerImpl(bool attach_to_current_thread); | ||||
|   explicit SequenceCheckerImpl(TaskQueueBase* attached_queue); | ||||
|   ~SequenceCheckerImpl() = default; | ||||
|  | ||||
|   bool IsCurrent() const; | ||||
|   // Changes the task queue or thread that is checked for in IsCurrent. This can | ||||
|   // be useful when an object may be created on one task queue / thread and then | ||||
|   // used exclusively on another thread. | ||||
|   void Detach(); | ||||
|  | ||||
|   // Returns a string that is formatted to match with the error string printed | ||||
|   // by RTC_CHECK() when a condition is not met. | ||||
|   // This is used in conjunction with the RTC_DCHECK_RUN_ON() macro. | ||||
|   std::string ExpectationToString() const; | ||||
|  | ||||
|  private: | ||||
|   mutable Mutex lock_; | ||||
|   // These are mutable so that IsCurrent can set them. | ||||
|   mutable bool attached_ RTC_GUARDED_BY(lock_); | ||||
|   mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_); | ||||
|   mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_); | ||||
| }; | ||||
|  | ||||
| // Do nothing implementation, for use in release mode. | ||||
| // | ||||
| // Note: You should almost always use the SequenceChecker class to get the | ||||
| // right version for your build configuration. | ||||
| class SequenceCheckerDoNothing { | ||||
|  public: | ||||
|   explicit SequenceCheckerDoNothing(bool attach_to_current_thread) {} | ||||
|   explicit SequenceCheckerDoNothing(TaskQueueBase* attached_queue) {} | ||||
|   bool IsCurrent() const { return true; } | ||||
|   void Detach() {} | ||||
| }; | ||||
|  | ||||
| template <typename ThreadLikeObject> | ||||
| std::enable_if_t<std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>, | ||||
|                  std::string> | ||||
| ExpectationToString(const ThreadLikeObject* checker) { | ||||
| #if RTC_DCHECK_IS_ON | ||||
|   return checker->ExpectationToString(); | ||||
| #else | ||||
|   return std::string(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| // Catch-all implementation for types other than explicitly supported above. | ||||
| template <typename ThreadLikeObject> | ||||
| std::enable_if_t<!std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>, | ||||
|                  std::string> | ||||
| ExpectationToString(const ThreadLikeObject*) { | ||||
|   return std::string(); | ||||
| } | ||||
|  | ||||
| }  // namespace webrtc_sequence_checker_internal | ||||
| }  // namespace webrtc | ||||
|  | ||||
| #endif  // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_ | ||||
							
								
								
									
										111
									
								
								webrtc/rtc_base/system/BUILD.gn
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								webrtc/rtc_base/system/BUILD.gn
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| # Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. | ||||
| # | ||||
| # Use of this source code is governed by a BSD-style license | ||||
| # that can be found in the LICENSE file in the root of the source | ||||
| # tree. An additional intellectual property rights grant can be found | ||||
| # in the file PATENTS.  All contributing project authors may | ||||
| # be found in the AUTHORS file in the root of the source tree. | ||||
|  | ||||
| import("../../webrtc.gni") | ||||
| if (is_android) { | ||||
|   import("//build/config/android/config.gni") | ||||
|   import("//build/config/android/rules.gni") | ||||
| } | ||||
|  | ||||
| rtc_source_set("arch") { | ||||
|   sources = [ "arch.h" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("asm_defines") { | ||||
|   sources = [ "asm_defines.h" ] | ||||
| } | ||||
|  | ||||
| rtc_library("file_wrapper") { | ||||
|   sources = [ | ||||
|     "file_wrapper.cc", | ||||
|     "file_wrapper.h", | ||||
|   ] | ||||
|   deps = [ | ||||
|     "..:checks", | ||||
|     "..:criticalsection", | ||||
|     "..:safe_conversions", | ||||
|   ] | ||||
|   absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] | ||||
| } | ||||
|  | ||||
| if (rtc_include_tests) { | ||||
|   rtc_library("file_wrapper_unittests") { | ||||
|     testonly = true | ||||
|     sources = [ "file_wrapper_unittest.cc" ] | ||||
|     deps = [ | ||||
|       ":file_wrapper", | ||||
|       "//rtc_base:checks", | ||||
|       "//test:fileutils", | ||||
|       "//test:test_support", | ||||
|     ] | ||||
|   } | ||||
| } | ||||
|  | ||||
| rtc_source_set("ignore_warnings") { | ||||
|   sources = [ "ignore_warnings.h" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("inline") { | ||||
|   sources = [ "inline.h" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("unused") { | ||||
|   sources = [ "unused.h" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("assume") { | ||||
|   sources = [ "assume.h" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("rtc_export") { | ||||
|   sources = [ | ||||
|     "rtc_export.h", | ||||
|     "rtc_export_template.h", | ||||
|   ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("no_unique_address") { | ||||
|   sources = [ "no_unique_address.h" ] | ||||
| } | ||||
|  | ||||
| rtc_source_set("no_cfi_icall") { | ||||
|   sources = [ "no_cfi_icall.h" ] | ||||
|  | ||||
|   deps = [ "..:sanitizer" ] | ||||
| } | ||||
|  | ||||
| if (is_mac || is_ios) { | ||||
|   rtc_library("cocoa_threading") { | ||||
|     sources = [ | ||||
|       "cocoa_threading.h", | ||||
|       "cocoa_threading.mm", | ||||
|     ] | ||||
|     deps = [ "..:checks" ] | ||||
|     frameworks = [ "Foundation.framework" ] | ||||
|   } | ||||
|  | ||||
|   rtc_library("gcd_helpers") { | ||||
|     sources = [ | ||||
|       "gcd_helpers.h", | ||||
|       "gcd_helpers.m", | ||||
|     ] | ||||
|     include_dirs = [ "../.." ] | ||||
|   } | ||||
| } | ||||
|  | ||||
| rtc_source_set("warn_current_thread_is_deadlocked") { | ||||
|   sources = [ "warn_current_thread_is_deadlocked.h" ] | ||||
|   deps = [] | ||||
|   if (is_android && !build_with_chromium) { | ||||
|     sources += [ "warn_current_thread_is_deadlocked.cc" ] | ||||
|     deps += [ | ||||
|       "..:logging", | ||||
|       "../../sdk/android:native_api_stacktrace", | ||||
|     ] | ||||
|   } | ||||
| } | ||||
| @@ -73,6 +73,16 @@ | ||||
| #elif defined(__riscv) && __riscv_xlen == 32 | ||||
| #define WEBRTC_ARCH_32_BITS | ||||
| #define WEBRTC_ARCH_LITTLE_ENDIAN | ||||
| #elif defined(__loongarch32) | ||||
| #define WEBRTC_ARCH_LOONG_FAMILY | ||||
| #define WEBRTC_ARCH_LOONG32 | ||||
| #define WEBRTC_ARCH_32_BITS | ||||
| #define WEBRTC_ARCH_LITTLE_ENDIAN | ||||
| #elif defined(__loongarch64) | ||||
| #define WEBRTC_ARCH_LOONG_FAMILY | ||||
| #define WEBRTC_ARCH_LOONG64 | ||||
| #define WEBRTC_ARCH_64_BITS | ||||
| #define WEBRTC_ARCH_LITTLE_ENDIAN | ||||
| #elif defined(__pnacl__) | ||||
| #define WEBRTC_ARCH_32_BITS | ||||
| #define WEBRTC_ARCH_LITTLE_ENDIAN | ||||
|   | ||||
| @@ -9,28 +9,37 @@ | ||||
|  */ | ||||
|  | ||||
| #include "rtc_base/system/file_wrapper.h" | ||||
| #include "rtc_base/numerics/safe_conversions.h" | ||||
|  | ||||
| #include <stddef.h> | ||||
|  | ||||
| #include <cerrno> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/numerics/safe_conversions.h" | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #include <windows.h> | ||||
| #include <Windows.h> | ||||
| #else | ||||
| #include <string.h> | ||||
| #endif | ||||
|  | ||||
| #include <utility> | ||||
|  | ||||
| namespace webrtc { | ||||
| namespace { | ||||
| FILE* FileOpen(const char* file_name_utf8, bool read_only, int* error) { | ||||
| FILE* FileOpen(absl::string_view file_name_utf8, bool read_only, int* error) { | ||||
|   RTC_CHECK_EQ(file_name_utf8.find_first_of('\0'), absl::string_view::npos) | ||||
|       << "Invalid filename, containing NUL character"; | ||||
|   std::string file_name(file_name_utf8); | ||||
| #if defined(_WIN32) | ||||
|   int len = MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, nullptr, 0); | ||||
|   int len = MultiByteToWideChar(CP_UTF8, 0, file_name.c_str(), -1, nullptr, 0); | ||||
|   std::wstring wstr(len, 0); | ||||
|   MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, &wstr[0], len); | ||||
|   MultiByteToWideChar(CP_UTF8, 0, file_name.c_str(), -1, &wstr[0], len); | ||||
|   FILE* file = _wfopen(wstr.c_str(), read_only ? L"rb" : L"wb"); | ||||
| #else | ||||
|   FILE* file = fopen(file_name_utf8, read_only ? "rb" : "wb"); | ||||
|   FILE* file = fopen(file_name.c_str(), read_only ? "rb" : "wb"); | ||||
| #endif | ||||
|   if (!file && error) { | ||||
|     *error = errno; | ||||
| @@ -38,36 +47,19 @@ FILE* FileOpen(const char* file_name_utf8, bool read_only, int* error) { | ||||
|   return file; | ||||
| } | ||||
|  | ||||
| const char* GetCstrCheckNoEmbeddedNul(const std::string& s) { | ||||
|   const char* p = s.c_str(); | ||||
|   RTC_CHECK_EQ(strlen(p), s.size()) | ||||
|       << "Invalid filename, containing NUL character"; | ||||
|   return p; | ||||
| } | ||||
| }  // namespace | ||||
|  | ||||
| // static | ||||
| FileWrapper FileWrapper::OpenReadOnly(const char* file_name_utf8) { | ||||
| FileWrapper FileWrapper::OpenReadOnly(absl::string_view file_name_utf8) { | ||||
|   return FileWrapper(FileOpen(file_name_utf8, true, nullptr)); | ||||
| } | ||||
|  | ||||
| // static | ||||
| FileWrapper FileWrapper::OpenReadOnly(const std::string& file_name_utf8) { | ||||
|   return OpenReadOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8)); | ||||
| } | ||||
|  | ||||
| // static | ||||
| FileWrapper FileWrapper::OpenWriteOnly(const char* file_name_utf8, | ||||
| FileWrapper FileWrapper::OpenWriteOnly(absl::string_view file_name_utf8, | ||||
|                                        int* error /*=nullptr*/) { | ||||
|   return FileWrapper(FileOpen(file_name_utf8, false, error)); | ||||
| } | ||||
|  | ||||
| // static | ||||
| FileWrapper FileWrapper::OpenWriteOnly(const std::string& file_name_utf8, | ||||
|                                        int* error /*=nullptr*/) { | ||||
|   return OpenWriteOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8), error); | ||||
| } | ||||
|  | ||||
| FileWrapper::FileWrapper(FileWrapper&& other) { | ||||
|   operator=(std::move(other)); | ||||
| } | ||||
| @@ -89,6 +81,22 @@ bool FileWrapper::SeekTo(int64_t position) { | ||||
|   return fseek(file_, rtc::checked_cast<long>(position), SEEK_SET) == 0; | ||||
| } | ||||
|  | ||||
| long FileWrapper::FileSize() { | ||||
|   if (file_ == nullptr) | ||||
|     return -1; | ||||
|   long original_position = ftell(file_); | ||||
|   if (original_position < 0) | ||||
|     return -1; | ||||
|   int seek_error = fseek(file_, 0, SEEK_END); | ||||
|   if (seek_error) | ||||
|     return -1; | ||||
|   long file_size = ftell(file_); | ||||
|   seek_error = fseek(file_, original_position, SEEK_SET); | ||||
|   if (seek_error) | ||||
|     return -1; | ||||
|   return file_size; | ||||
| } | ||||
|  | ||||
| bool FileWrapper::Flush() { | ||||
|   RTC_DCHECK(file_); | ||||
|   return fflush(file_) == 0; | ||||
|   | ||||
| @@ -12,11 +12,14 @@ | ||||
| #define RTC_BASE_SYSTEM_FILE_WRAPPER_H_ | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| #include "absl/strings/string_view.h" | ||||
|  | ||||
| // Implementation that can read (exclusive) or write from/to a file. | ||||
|  | ||||
| namespace webrtc { | ||||
| @@ -33,20 +36,16 @@ class FileWrapper final { | ||||
|  public: | ||||
|   // Opens a file, in read or write mode. Use the is_open() method on the | ||||
|   // returned object to check if the open operation was successful. On failure, | ||||
|   // and if |error| is non-null, the system errno value is stored at |*error|. | ||||
|   // and if `error` is non-null, the system errno value is stored at |*error|. | ||||
|   // The file is closed by the destructor. | ||||
|   static FileWrapper OpenReadOnly(const char* file_name_utf8); | ||||
|   static FileWrapper OpenReadOnly(const std::string& file_name_utf8); | ||||
|   static FileWrapper OpenWriteOnly(const char* file_name_utf8, | ||||
|                                    int* error = nullptr); | ||||
|  | ||||
|   static FileWrapper OpenWriteOnly(const std::string& file_name_utf8, | ||||
|   static FileWrapper OpenReadOnly(absl::string_view file_name_utf8); | ||||
|   static FileWrapper OpenWriteOnly(absl::string_view file_name_utf8, | ||||
|                                    int* error = nullptr); | ||||
|  | ||||
|   FileWrapper() = default; | ||||
|  | ||||
|   // Takes over ownership of |file|, closing it on destruction. Calling with | ||||
|   // null |file| is allowed, and results in a FileWrapper with is_open() false. | ||||
|   // Takes over ownership of `file`, closing it on destruction. Calling with | ||||
|   // null `file` is allowed, and results in a FileWrapper with is_open() false. | ||||
|   explicit FileWrapper(FILE* file) : file_(file) {} | ||||
|   ~FileWrapper() { Close(); } | ||||
|  | ||||
| @@ -88,6 +87,11 @@ class FileWrapper final { | ||||
|   // Seek to given position. | ||||
|   bool SeekTo(int64_t position); | ||||
|  | ||||
|   // Returns the file size or -1 if a size could not be determined. | ||||
|   // (A file size might not exists for non-seekable files or file-like | ||||
|   // objects, for example /dev/tty on unix.) | ||||
|   long FileSize(); | ||||
|  | ||||
|   // Returns number of bytes read. Short count indicates EOF or error. | ||||
|   size_t Read(void* buf, size_t length); | ||||
|  | ||||
|   | ||||
							
								
								
									
										37
									
								
								webrtc/rtc_base/system/no_unique_address.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								webrtc/rtc_base/system/no_unique_address.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_ | ||||
| #define RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_ | ||||
|  | ||||
| // RTC_NO_UNIQUE_ADDRESS is a portable annotation to tell the compiler that | ||||
| // a data member need not have an address distinct from all other non-static | ||||
| // data members of its class. | ||||
| // It allows empty types to actually occupy zero bytes as class members, | ||||
| // instead of occupying at least one byte just so that they get their own | ||||
| // address. There is almost never any reason not to use it on class members | ||||
| // that could possibly be empty. | ||||
| // The macro expands to [[no_unique_address]] if the compiler supports the | ||||
| // attribute, it expands to nothing otherwise. | ||||
| // Clang should supports this attribute since C++11, while other compilers | ||||
| // should add support for it starting from C++20. Among clang compilers, | ||||
| // clang-cl doesn't support it yet and support is unclear also when the target | ||||
| // platform is iOS. | ||||
| #ifndef __has_cpp_attribute | ||||
| #define __has_cpp_attribute(x) 0 | ||||
| #endif | ||||
| #if __has_cpp_attribute(no_unique_address) | ||||
| // NOLINTNEXTLINE(whitespace/braces) | ||||
| #define RTC_NO_UNIQUE_ADDRESS [[no_unique_address]] | ||||
| #else | ||||
| #define RTC_NO_UNIQUE_ADDRESS | ||||
| #endif | ||||
|  | ||||
| #endif  // RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_ | ||||
| @@ -11,29 +11,18 @@ | ||||
| #ifndef RTC_BASE_SYSTEM_UNUSED_H_ | ||||
| #define RTC_BASE_SYSTEM_UNUSED_H_ | ||||
|  | ||||
| // Annotate a function indicating the caller must examine the return value. | ||||
| // Use like: | ||||
| //   int foo() RTC_WARN_UNUSED_RESULT; | ||||
| // To explicitly ignore a result, cast to void. | ||||
| // TODO(kwiberg): Remove when we can use [[nodiscard]] from C++17. | ||||
| #if defined(__clang__) | ||||
| #define RTC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) | ||||
| #elif defined(__GNUC__) | ||||
| // gcc has a __warn_unused_result__ attribute, but you can't quiet it by | ||||
| // casting to void, so we don't use it. | ||||
| #define RTC_WARN_UNUSED_RESULT | ||||
| #else | ||||
| #define RTC_WARN_UNUSED_RESULT | ||||
| #endif | ||||
|  | ||||
| // Prevent the compiler from warning about an unused variable. For example: | ||||
| //   int result = DoSomething(); | ||||
| //   assert(result == 17); | ||||
| //   RTC_DCHECK(result == 17); | ||||
| //   RTC_UNUSED(result); | ||||
| // Note: In most cases it is better to remove the unused variable rather than | ||||
| // suppressing the compiler warning. | ||||
| #ifndef RTC_UNUSED | ||||
| #ifdef __cplusplus | ||||
| #define RTC_UNUSED(x) static_cast<void>(x) | ||||
| #else | ||||
| #define RTC_UNUSED(x) (void)(x) | ||||
| #endif | ||||
| #endif  // RTC_UNUSED | ||||
|  | ||||
| #endif  // RTC_BASE_SYSTEM_UNUSED_H_ | ||||
|   | ||||
							
								
								
									
										28
									
								
								webrtc/rtc_base/system/warn_current_thread_is_deadlocked.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								webrtc/rtc_base/system/warn_current_thread_is_deadlocked.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  *  Copyright 2019 The WebRTC Project Authors. All rights reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #include "rtc_base/system/warn_current_thread_is_deadlocked.h" | ||||
|  | ||||
| #include "rtc_base/logging.h" | ||||
| #if 0 | ||||
| # commented out to prevent pulling in extra android files | ||||
| #include "sdk/android/native_api/stacktrace/stacktrace.h" | ||||
| #endif | ||||
|  | ||||
| namespace webrtc { | ||||
|  | ||||
| void WarnThatTheCurrentThreadIsProbablyDeadlocked() { | ||||
|   RTC_LOG(LS_WARNING) << "Probable deadlock:"; | ||||
| #if 0 | ||||
|   RTC_LOG(LS_WARNING) << StackTraceToString(GetStackTrace()); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| }  // namespace webrtc | ||||
| @@ -14,11 +14,7 @@ | ||||
| namespace webrtc { | ||||
|  | ||||
| #if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) | ||||
| /* webrtc-audio-processing: | ||||
|  * We don't support the Android SDK integration for this, so stub out | ||||
| void WarnThatTheCurrentThreadIsProbablyDeadlocked(); | ||||
|  */ | ||||
| inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {} | ||||
| #else | ||||
| inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {} | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										102
									
								
								webrtc/rtc_base/system_time.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								webrtc/rtc_base/system_time.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| /* | ||||
|  *  Copyright 2021 The WebRTC Project Authors. All rights reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| // If WEBRTC_EXCLUDE_SYSTEM_TIME is set, an implementation of | ||||
| // rtc::SystemTimeNanos() must be provided externally. | ||||
| #ifndef WEBRTC_EXCLUDE_SYSTEM_TIME | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| #include <limits> | ||||
|  | ||||
| #if defined(WEBRTC_POSIX) | ||||
| #include <sys/time.h> | ||||
| #if defined(WEBRTC_MAC) | ||||
| #include <mach/mach_time.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| // clang-format off | ||||
| // clang formatting would put <windows.h> last, | ||||
| // which leads to compilation failure. | ||||
| #include <windows.h> | ||||
| #include <mmsystem.h> | ||||
| #include <sys/timeb.h> | ||||
| // clang-format on | ||||
| #endif | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/numerics/safe_conversions.h" | ||||
| #include "rtc_base/system_time.h" | ||||
| #include "rtc_base/time_utils.h" | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| int64_t SystemTimeNanos() { | ||||
|   int64_t ticks; | ||||
| #if defined(WEBRTC_MAC) | ||||
|   static mach_timebase_info_data_t timebase; | ||||
|   if (timebase.denom == 0) { | ||||
|     // Get the timebase if this is the first time we run. | ||||
|     // Recommended by Apple's QA1398. | ||||
|     if (mach_timebase_info(&timebase) != KERN_SUCCESS) { | ||||
|       RTC_DCHECK_NOTREACHED(); | ||||
|     } | ||||
|   } | ||||
|   // Use timebase to convert absolute time tick units into nanoseconds. | ||||
|   const auto mul = [](uint64_t a, uint32_t b) -> int64_t { | ||||
|     RTC_DCHECK_NE(b, 0); | ||||
|     RTC_DCHECK_LE(a, std::numeric_limits<int64_t>::max() / b) | ||||
|         << "The multiplication " << a << " * " << b << " overflows"; | ||||
|     return rtc::dchecked_cast<int64_t>(a * b); | ||||
|   }; | ||||
|   ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom; | ||||
| #elif defined(WEBRTC_POSIX) | ||||
|   struct timespec ts; | ||||
|   // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not | ||||
|   // supported? | ||||
|   clock_gettime(CLOCK_MONOTONIC, &ts); | ||||
|   ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) + | ||||
|           static_cast<int64_t>(ts.tv_nsec); | ||||
| #elif defined(WINUWP) | ||||
|   ticks = WinUwpSystemTimeNanos(); | ||||
| #elif defined(WEBRTC_WIN) | ||||
|   // TODO(webrtc:14601): Fix the volatile increment instead of suppressing the | ||||
|   // warning. | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wdeprecated-volatile" | ||||
|   static volatile LONG last_timegettime = 0; | ||||
|   static volatile int64_t num_wrap_timegettime = 0; | ||||
|   volatile LONG* last_timegettime_ptr = &last_timegettime; | ||||
|   DWORD now = timeGetTime(); | ||||
|   // Atomically update the last gotten time | ||||
|   DWORD old = InterlockedExchange(last_timegettime_ptr, now); | ||||
|   if (now < old) { | ||||
|     // If now is earlier than old, there may have been a race between threads. | ||||
|     // 0x0fffffff ~3.1 days, the code will not take that long to execute | ||||
|     // so it must have been a wrap around. | ||||
|     if (old > 0xf0000000 && now < 0x0fffffff) { | ||||
|       num_wrap_timegettime++; | ||||
|     } | ||||
|   } | ||||
|   ticks = now + (num_wrap_timegettime << 32); | ||||
|   // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're | ||||
|   // just wasting a multiply and divide when doing Time() on Windows. | ||||
|   ticks = ticks * kNumNanosecsPerMillisec; | ||||
| #pragma clang diagnostic pop | ||||
| #else | ||||
| #error Unsupported platform. | ||||
| #endif | ||||
|   return ticks; | ||||
| } | ||||
|  | ||||
| }  // namespace rtc | ||||
| #endif  // WEBRTC_EXCLUDE_SYSTEM_TIME | ||||
							
								
								
									
										24
									
								
								webrtc/rtc_base/system_time.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								webrtc/rtc_base/system_time.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| /* | ||||
|  *  Copyright 2021 The WebRTC Project Authors. All rights reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| #ifndef RTC_BASE_SYSTEM_TIME_H_ | ||||
| #define RTC_BASE_SYSTEM_TIME_H_ | ||||
|  | ||||
| #include <cstdint> | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| // Returns the actual system time, even if a clock is set for testing. | ||||
| // Useful for timeouts while using a test clock, or for logging. | ||||
| int64_t SystemTimeNanos(); | ||||
|  | ||||
| }  // namespace rtc | ||||
|  | ||||
| #endif  // RTC_BASE_SYSTEM_TIME_H_ | ||||
| @@ -88,6 +88,9 @@ | ||||
| #define RTC_UNLOCK_FUNCTION(...) \ | ||||
|   RTC_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) | ||||
|  | ||||
| #define RTC_ASSERT_EXCLUSIVE_LOCK(...) \ | ||||
|   RTC_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) | ||||
|  | ||||
| // An escape hatch for thread safety analysis to ignore the annotated function. | ||||
| #define RTC_NO_THREAD_SAFETY_ANALYSIS \ | ||||
|   RTC_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) | ||||
|   | ||||
| @@ -1,27 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | ||||
|  * | ||||
|  *  Use of this source code is governed by a BSD-style license | ||||
|  *  that can be found in the LICENSE file in the root of the source | ||||
|  *  tree. An additional intellectual property rights grant can be found | ||||
|  *  in the file PATENTS.  All contributing project authors may | ||||
|  *  be found in the AUTHORS file in the root of the source tree. | ||||
|  */ | ||||
|  | ||||
| // Borrowed from Chromium's src/base/threading/thread_checker.h. | ||||
|  | ||||
| #ifndef RTC_BASE_THREAD_CHECKER_H_ | ||||
| #define RTC_BASE_THREAD_CHECKER_H_ | ||||
|  | ||||
| #include "rtc_base/deprecation.h" | ||||
| #include "rtc_base/synchronization/sequence_checker.h" | ||||
|  | ||||
| namespace rtc { | ||||
| // TODO(srte): Replace usages of this with SequenceChecker. | ||||
| class ThreadChecker : public webrtc::SequenceChecker { | ||||
|  public: | ||||
|   RTC_DEPRECATED bool CalledOnValidThread() const { return IsCurrent(); } | ||||
|   RTC_DEPRECATED void DetachFromThread() { Detach(); } | ||||
| }; | ||||
| }  // namespace rtc | ||||
| #endif  // RTC_BASE_THREAD_CHECKER_H_ | ||||
| @@ -12,27 +12,29 @@ | ||||
|  | ||||
| #if defined(WEBRTC_POSIX) | ||||
| #include <sys/time.h> | ||||
| #if defined(WEBRTC_MAC) | ||||
| #include <mach/mach_time.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(WEBRTC_WIN) | ||||
| // clang-format off | ||||
| // clang formatting would put <windows.h> last, | ||||
| // which leads to compilation failure. | ||||
| #include <windows.h> | ||||
| #include <mmsystem.h> | ||||
| #include <sys/timeb.h> | ||||
| // clang-format on | ||||
| #endif | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/numerics/safe_conversions.h" | ||||
| #include "rtc_base/system_time.h" | ||||
| #include "rtc_base/time_utils.h" | ||||
| #if defined(WEBRTC_WIN) | ||||
| #include "rtc_base/win32.h" | ||||
| #endif | ||||
| #if defined(WEBRTC_WIN) | ||||
| #include <minwinbase.h> | ||||
| #endif | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| #if defined(WEBRTC_WIN) || defined(WINUWP) | ||||
| // FileTime (January 1st 1601) to Unix time (January 1st 1970) | ||||
| // offset in units of 100ns. | ||||
| static constexpr uint64_t kFileTimeToUnixTimeEpochOffset = | ||||
|     116444736000000000ULL; | ||||
| static constexpr uint64_t kFileTimeToMicroSeconds = 10LL; | ||||
| #endif | ||||
|  | ||||
| ClockInterface* g_clock = nullptr; | ||||
|  | ||||
| ClockInterface* SetClockForTesting(ClockInterface* clock) { | ||||
| @@ -123,8 +125,6 @@ class TimeHelper final { | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   static constexpr uint64_t kFileTimeToUnixTimeEpochOffset = | ||||
|       116444736000000000ULL; | ||||
|   static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L; | ||||
|  | ||||
|   // The number of nanoseconds since unix system epoch | ||||
| @@ -141,61 +141,12 @@ void SyncWithNtp(int64_t time_from_ntp_server_ms) { | ||||
|   TimeHelper::SyncWithNtp(time_from_ntp_server_ms); | ||||
| } | ||||
|  | ||||
| #endif  // defined(WINUWP) | ||||
|  | ||||
| int64_t SystemTimeNanos() { | ||||
|   int64_t ticks; | ||||
| #if defined(WEBRTC_MAC) | ||||
|   static mach_timebase_info_data_t timebase; | ||||
|   if (timebase.denom == 0) { | ||||
|     // Get the timebase if this is the first time we run. | ||||
|     // Recommended by Apple's QA1398. | ||||
|     if (mach_timebase_info(&timebase) != KERN_SUCCESS) { | ||||
|       RTC_NOTREACHED(); | ||||
|     } | ||||
|   } | ||||
|   // Use timebase to convert absolute time tick units into nanoseconds. | ||||
|   const auto mul = [](uint64_t a, uint32_t b) -> int64_t { | ||||
|     RTC_DCHECK_NE(b, 0); | ||||
|     RTC_DCHECK_LE(a, std::numeric_limits<int64_t>::max() / b) | ||||
|         << "The multiplication " << a << " * " << b << " overflows"; | ||||
|     return rtc::dchecked_cast<int64_t>(a * b); | ||||
|   }; | ||||
|   ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom; | ||||
| #elif defined(WEBRTC_POSIX) | ||||
|   struct timespec ts; | ||||
|   // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not | ||||
|   // supported? | ||||
|   clock_gettime(CLOCK_MONOTONIC, &ts); | ||||
|   ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) + | ||||
|           static_cast<int64_t>(ts.tv_nsec); | ||||
| #elif defined(WINUWP) | ||||
|   ticks = TimeHelper::TicksNs(); | ||||
| #elif defined(WEBRTC_WIN) | ||||
|   static volatile LONG last_timegettime = 0; | ||||
|   static volatile int64_t num_wrap_timegettime = 0; | ||||
|   volatile LONG* last_timegettime_ptr = &last_timegettime; | ||||
|   DWORD now = timeGetTime(); | ||||
|   // Atomically update the last gotten time | ||||
|   DWORD old = InterlockedExchange(last_timegettime_ptr, now); | ||||
|   if (now < old) { | ||||
|     // If now is earlier than old, there may have been a race between threads. | ||||
|     // 0x0fffffff ~3.1 days, the code will not take that long to execute | ||||
|     // so it must have been a wrap around. | ||||
|     if (old > 0xf0000000 && now < 0x0fffffff) { | ||||
|       num_wrap_timegettime++; | ||||
|     } | ||||
|   } | ||||
|   ticks = now + (num_wrap_timegettime << 32); | ||||
|   // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're | ||||
|   // just wasting a multiply and divide when doing Time() on Windows. | ||||
|   ticks = ticks * kNumNanosecsPerMillisec; | ||||
| #else | ||||
| #error Unsupported platform. | ||||
| #endif | ||||
|   return ticks; | ||||
| int64_t WinUwpSystemTimeNanos() { | ||||
|   return TimeHelper::TicksNs(); | ||||
| } | ||||
|  | ||||
| #endif  // defined(WINUWP) | ||||
|  | ||||
| int64_t SystemTimeMillis() { | ||||
|   return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec); | ||||
| } | ||||
| @@ -232,28 +183,6 @@ int64_t TimeDiff(int64_t later, int64_t earlier) { | ||||
|   return later - earlier; | ||||
| } | ||||
|  | ||||
| TimestampWrapAroundHandler::TimestampWrapAroundHandler() | ||||
|     : last_ts_(0), num_wrap_(-1) {} | ||||
|  | ||||
| int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) { | ||||
|   if (num_wrap_ == -1) { | ||||
|     last_ts_ = ts; | ||||
|     num_wrap_ = 0; | ||||
|     return ts; | ||||
|   } | ||||
|  | ||||
|   if (ts < last_ts_) { | ||||
|     if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff) | ||||
|       ++num_wrap_; | ||||
|   } else if ((ts - last_ts_) > 0xf0000000) { | ||||
|     // Backwards wrap. Unwrap with last wrap count and don't update last_ts_. | ||||
|     return ts + (num_wrap_ - 1) * (int64_t{1} << 32); | ||||
|   } | ||||
|  | ||||
|   last_ts_ = ts; | ||||
|   return ts + (num_wrap_ << 32); | ||||
| } | ||||
|  | ||||
| int64_t TmToSeconds(const tm& tm) { | ||||
|   static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||||
|   static short int cumul_mdays[12] = {0,   31,  59,  90,  120, 151, | ||||
| @@ -289,11 +218,11 @@ int64_t TmToSeconds(const tm& tm) { | ||||
|  | ||||
|   // We will have added one day too much above if expiration is during a leap | ||||
|   // year, and expiration is in January or February. | ||||
|   if (expiry_in_leap_year && month <= 2 - 1)  // |month| is zero based. | ||||
|   if (expiry_in_leap_year && month <= 2 - 1)  // `month` is zero based. | ||||
|     day -= 1; | ||||
|  | ||||
|   // Combine all variables into seconds from 1970-01-01 00:00 (except |month| | ||||
|   // which was accumulated into |day| above). | ||||
|   // Combine all variables into seconds from 1970-01-01 00:00 (except `month` | ||||
|   // which was accumulated into `day` above). | ||||
|   return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 + | ||||
|           min) * | ||||
|              60 + | ||||
| @@ -310,13 +239,15 @@ int64_t TimeUTCMicros() { | ||||
|   // Convert from second (1.0) and microsecond (1e-6). | ||||
|   return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec + | ||||
|           time.tv_usec); | ||||
|  | ||||
| #elif defined(WEBRTC_WIN) | ||||
|   struct _timeb time; | ||||
|   _ftime(&time); | ||||
|   // Convert from second (1.0) and milliseconds (1e-3). | ||||
|   return (static_cast<int64_t>(time.time) * rtc::kNumMicrosecsPerSec + | ||||
|           static_cast<int64_t>(time.millitm) * rtc::kNumMicrosecsPerMillisec); | ||||
|   FILETIME ft; | ||||
|   // This will give us system file in UTC format in multiples of 100ns. | ||||
|   GetSystemTimeAsFileTime(&ft); | ||||
|   LARGE_INTEGER li; | ||||
|   li.HighPart = ft.dwHighDateTime; | ||||
|   li.LowPart = ft.dwLowDateTime; | ||||
|   return (li.QuadPart - kFileTimeToUnixTimeEpochOffset) / | ||||
|          kFileTimeToMicroSeconds; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/system/rtc_export.h" | ||||
| #include "rtc_base/system_time.h" | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| @@ -30,6 +31,12 @@ static const int64_t kNumNanosecsPerMillisec = | ||||
| static const int64_t kNumNanosecsPerMicrosec = | ||||
|     kNumNanosecsPerSec / kNumMicrosecsPerSec; | ||||
|  | ||||
| // Elapsed milliseconds between NTP base, 1900 January 1 00:00 GMT | ||||
| // (see https://tools.ietf.org/html/rfc868), and January 1 00:00 GMT 1970 | ||||
| // epoch. This is useful when converting between the NTP time base and the | ||||
| // time base used in RTCP reports. | ||||
| constexpr int64_t kNtpJan1970Millisecs = 2'208'988'800 * kNumMillisecsPerSec; | ||||
|  | ||||
| // TODO(honghaiz): Define a type for the time value specifically. | ||||
|  | ||||
| class ClockInterface { | ||||
| @@ -61,11 +68,16 @@ RTC_EXPORT ClockInterface* GetClockForTesting(); | ||||
| // Synchronizes the current clock based upon an NTP server's epoch in | ||||
| // milliseconds. | ||||
| void SyncWithNtp(int64_t time_from_ntp_server_ms); | ||||
|  | ||||
| // Returns the current time in nanoseconds. The clock is synchonized with the | ||||
| // system wall clock time upon instatiation. It may also be synchronized using | ||||
| // the SyncWithNtp() function above. Please note that the clock will most likely | ||||
| // drift away from the system wall clock time as time goes by. | ||||
| int64_t WinUwpSystemTimeNanos(); | ||||
| #endif  // defined(WINUWP) | ||||
|  | ||||
| // Returns the actual system time, even if a clock is set for testing. | ||||
| // Useful for timeouts while using a test clock, or for logging. | ||||
| int64_t SystemTimeNanos(); | ||||
| int64_t SystemTimeMillis(); | ||||
|  | ||||
| // Returns the current time in milliseconds in 32 bits. | ||||
| @@ -102,17 +114,6 @@ inline int64_t TimeUntil(int64_t later) { | ||||
|   return later - TimeMillis(); | ||||
| } | ||||
|  | ||||
| class TimestampWrapAroundHandler { | ||||
|  public: | ||||
|   TimestampWrapAroundHandler(); | ||||
|  | ||||
|   int64_t Unwrap(uint32_t ts); | ||||
|  | ||||
|  private: | ||||
|   uint32_t last_ts_; | ||||
|   int64_t num_wrap_; | ||||
| }; | ||||
|  | ||||
| // Convert from tm, which is relative to 1900-01-01 00:00 to number of | ||||
| // seconds from 1970-01-01 00:00 ("epoch"). Don't return time_t since that | ||||
| // is still 32 bits on many systems. | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -10,13 +10,14 @@ import("../../webrtc.gni") | ||||
|  | ||||
| rtc_source_set("unit_base") { | ||||
|   visibility = [ | ||||
|     "../../api/units:*", | ||||
|     ":*", | ||||
|     "../../api/units:*", | ||||
|   ] | ||||
|   sources = [ "unit_base.h" ] | ||||
|  | ||||
|   deps = [ | ||||
|     "../../rtc_base:checks", | ||||
|     "../../rtc_base:divide_round", | ||||
|     "../../rtc_base:safe_conversions", | ||||
|   ] | ||||
| } | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "rtc_base/checks.h" | ||||
| #include "rtc_base/numerics/divide_round.h" | ||||
| #include "rtc_base/numerics/safe_conversions.h" | ||||
|  | ||||
| namespace webrtc { | ||||
| @@ -50,22 +51,22 @@ class UnitBase { | ||||
|     return value_ == MinusInfinityVal(); | ||||
|   } | ||||
|  | ||||
|   constexpr bool operator==(const Unit_T& other) const { | ||||
|   constexpr bool operator==(const UnitBase<Unit_T>& other) const { | ||||
|     return value_ == other.value_; | ||||
|   } | ||||
|   constexpr bool operator!=(const Unit_T& other) const { | ||||
|   constexpr bool operator!=(const UnitBase<Unit_T>& other) const { | ||||
|     return value_ != other.value_; | ||||
|   } | ||||
|   constexpr bool operator<=(const Unit_T& other) const { | ||||
|   constexpr bool operator<=(const UnitBase<Unit_T>& other) const { | ||||
|     return value_ <= other.value_; | ||||
|   } | ||||
|   constexpr bool operator>=(const Unit_T& other) const { | ||||
|   constexpr bool operator>=(const UnitBase<Unit_T>& other) const { | ||||
|     return value_ >= other.value_; | ||||
|   } | ||||
|   constexpr bool operator>(const Unit_T& other) const { | ||||
|   constexpr bool operator>(const UnitBase<Unit_T>& other) const { | ||||
|     return value_ > other.value_; | ||||
|   } | ||||
|   constexpr bool operator<(const Unit_T& other) const { | ||||
|   constexpr bool operator<(const UnitBase<Unit_T>& other) const { | ||||
|     return value_ < other.value_; | ||||
|   } | ||||
|   constexpr Unit_T RoundTo(const Unit_T& resolution) const { | ||||
| @@ -140,10 +141,9 @@ class UnitBase { | ||||
|   template <typename T> | ||||
|   constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type | ||||
|   ToValue() const { | ||||
|     return IsPlusInfinity() | ||||
|                ? std::numeric_limits<T>::infinity() | ||||
|                : IsMinusInfinity() ? -std::numeric_limits<T>::infinity() | ||||
|                                    : value_; | ||||
|     return IsPlusInfinity()    ? std::numeric_limits<T>::infinity() | ||||
|            : IsMinusInfinity() ? -std::numeric_limits<T>::infinity() | ||||
|                                : value_; | ||||
|   } | ||||
|   template <typename T> | ||||
|   constexpr T ToValueOr(T fallback_value) const { | ||||
| @@ -154,12 +154,7 @@ class UnitBase { | ||||
|   constexpr typename std::enable_if<std::is_integral<T>::value, T>::type | ||||
|   ToFraction() const { | ||||
|     RTC_DCHECK(IsFinite()); | ||||
|     if (Unit_T::one_sided) { | ||||
|       return rtc::dchecked_cast<T>( | ||||
|           DivRoundPositiveToNearest(value_, Denominator)); | ||||
|     } else { | ||||
|       return rtc::dchecked_cast<T>(DivRoundToNearest(value_, Denominator)); | ||||
|     } | ||||
|     return rtc::dchecked_cast<T>(DivideRoundToNearest(value_, Denominator)); | ||||
|   } | ||||
|   template <int64_t Denominator, typename T> | ||||
|   constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type | ||||
| @@ -169,9 +164,7 @@ class UnitBase { | ||||
|  | ||||
|   template <int64_t Denominator> | ||||
|   constexpr int64_t ToFractionOr(int64_t fallback_value) const { | ||||
|     return IsFinite() ? Unit_T::one_sided | ||||
|                             ? DivRoundPositiveToNearest(value_, Denominator) | ||||
|                             : DivRoundToNearest(value_, Denominator) | ||||
|     return IsFinite() ? DivideRoundToNearest(value_, Denominator) | ||||
|                       : fallback_value; | ||||
|   } | ||||
|  | ||||
| @@ -205,14 +198,6 @@ class UnitBase { | ||||
|   constexpr const Unit_T& AsSubClassRef() const { | ||||
|     return static_cast<const Unit_T&>(*this); | ||||
|   } | ||||
|   // Assumes that n >= 0 and d > 0. | ||||
|   static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) { | ||||
|     return (n + d / 2) / d; | ||||
|   } | ||||
|   // Assumes that d > 0. | ||||
|   static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) { | ||||
|     return (n + (n >= 0 ? d / 2 : -d / 2)) / d; | ||||
|   } | ||||
|  | ||||
|   int64_t value_; | ||||
| }; | ||||
| @@ -266,14 +251,18 @@ class RelativeUnit : public UnitBase<Unit_T> { | ||||
|     return UnitBase<Unit_T>::template ToValue<double>() / | ||||
|            other.template ToValue<double>(); | ||||
|   } | ||||
|   template <typename T> | ||||
|   constexpr typename std::enable_if<std::is_arithmetic<T>::value, Unit_T>::type | ||||
|   operator/(const T& scalar) const { | ||||
|     return UnitBase<Unit_T>::FromValue( | ||||
|         std::round(UnitBase<Unit_T>::template ToValue<int64_t>() / scalar)); | ||||
|   template <typename T, | ||||
|             typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr> | ||||
|   constexpr Unit_T operator/(T scalar) const { | ||||
|     return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() / scalar)); | ||||
|   } | ||||
|   template <typename T, | ||||
|             typename std::enable_if_t<std::is_integral_v<T>>* = nullptr> | ||||
|   constexpr Unit_T operator/(T scalar) const { | ||||
|     return UnitBase<Unit_T>::FromValue(this->ToValue() / scalar); | ||||
|   } | ||||
|   constexpr Unit_T operator*(double scalar) const { | ||||
|     return UnitBase<Unit_T>::FromValue(std::round(this->ToValue() * scalar)); | ||||
|     return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() * scalar)); | ||||
|   } | ||||
|   constexpr Unit_T operator*(int64_t scalar) const { | ||||
|     return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); | ||||
| @@ -281,6 +270,9 @@ class RelativeUnit : public UnitBase<Unit_T> { | ||||
|   constexpr Unit_T operator*(int32_t scalar) const { | ||||
|     return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); | ||||
|   } | ||||
|   constexpr Unit_T operator*(size_t scalar) const { | ||||
|     return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   using UnitBase<Unit_T>::UnitBase; | ||||
| @@ -298,6 +290,19 @@ template <class Unit_T> | ||||
| inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) { | ||||
|   return other * scalar; | ||||
| } | ||||
| template <class Unit_T> | ||||
| inline constexpr Unit_T operator*(size_t scalar, RelativeUnit<Unit_T> other) { | ||||
|   return other * scalar; | ||||
| } | ||||
|  | ||||
| template <class Unit_T> | ||||
| inline constexpr Unit_T operator-(RelativeUnit<Unit_T> other) { | ||||
|   if (other.IsPlusInfinity()) | ||||
|     return UnitBase<Unit_T>::MinusInfinity(); | ||||
|   if (other.IsMinusInfinity()) | ||||
|     return UnitBase<Unit_T>::PlusInfinity(); | ||||
|   return -1 * other; | ||||
| } | ||||
|  | ||||
| }  // namespace rtc_units_impl | ||||
|  | ||||
|   | ||||
| @@ -20,11 +20,10 @@ | ||||
| #define NOMINMAX | ||||
| #endif | ||||
|  | ||||
| // clang-format off | ||||
| // clang formating would change include order. | ||||
| #include <winsock2.h> // must come first | ||||
| #include <winsock2.h> | ||||
|  | ||||
| // Must be after winsock2.h. | ||||
| #include <windows.h> | ||||
| // clang-format on | ||||
|  | ||||
| typedef int socklen_t; | ||||
|  | ||||
| @@ -39,66 +38,11 @@ typedef struct _TOKEN_MANDATORY_LABEL { | ||||
|  | ||||
| #undef SetPort | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| namespace rtc { | ||||
|  | ||||
| const char* win32_inet_ntop(int af, const void* src, char* dst, socklen_t size); | ||||
| int win32_inet_pton(int af, const char* src, void* dst); | ||||
|  | ||||
| enum WindowsMajorVersions { | ||||
|   kWindows2000 = 5, | ||||
|   kWindowsVista = 6, | ||||
|   kWindows10 = 10, | ||||
| }; | ||||
|  | ||||
| #if !defined(WINUWP) | ||||
| bool GetOsVersion(int* major, int* minor, int* build); | ||||
|  | ||||
| inline bool IsWindowsVistaOrLater() { | ||||
|   int major; | ||||
|   return (GetOsVersion(&major, nullptr, nullptr) && major >= kWindowsVista); | ||||
| } | ||||
|  | ||||
| inline bool IsWindowsXpOrLater() { | ||||
|   int major, minor; | ||||
|   return (GetOsVersion(&major, &minor, nullptr) && | ||||
|           (major >= kWindowsVista || (major == kWindows2000 && minor >= 1))); | ||||
| } | ||||
|  | ||||
| inline bool IsWindows8OrLater() { | ||||
|   int major, minor; | ||||
|   return (GetOsVersion(&major, &minor, nullptr) && | ||||
|           (major > kWindowsVista || (major == kWindowsVista && minor >= 2))); | ||||
| } | ||||
|  | ||||
| inline bool IsWindows10OrLater() { | ||||
|   int major; | ||||
|   return (GetOsVersion(&major, nullptr, nullptr) && (major >= kWindows10)); | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| // When targetting WinUWP the OS must be Windows 10 (or greater) as lesser | ||||
| // Windows OS targets are not supported. | ||||
| inline bool IsWindowsVistaOrLater() { | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool IsWindowsXpOrLater() { | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool IsWindows8OrLater() { | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool IsWindows10OrLater() { | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| #endif  // !defined(WINUWP) | ||||
|  | ||||
| }  // namespace rtc | ||||
|  | ||||
| #endif  // RTC_BASE_WIN32_H_ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user