diff options
Diffstat (limited to 'third_party/libwebrtc/rtc_base/platform_thread.cc')
-rw-r--r-- | third_party/libwebrtc/rtc_base/platform_thread.cc | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/platform_thread.cc b/third_party/libwebrtc/rtc_base/platform_thread.cc new file mode 100644 index 0000000000..71a9f1b224 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread.cc @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/platform_thread.h" + +#include <algorithm> +#include <memory> + +#if !defined(WEBRTC_WIN) +#include <sched.h> +#endif + +#include "rtc_base/checks.h" + +#include "MicroGeckoProfiler.h" + +namespace rtc { +namespace { + +#if defined(WEBRTC_WIN) +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; + } +} +#endif + +bool SetPriority(ThreadPriority priority) { +#if defined(WEBRTC_WIN) + 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; +#elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX) + // TODO(tommi): Switch to the same mechanism as Chromium uses for changing + // thread priorities. + return true; +#else + const int policy = SCHED_FIFO; + const int min_prio = sched_get_priority_min(policy); + const int max_prio = sched_get_priority_max(policy); + if (min_prio == -1 || max_prio == -1) { + return false; + } + + if (max_prio - min_prio <= 2) + return false; + + // Convert webrtc priority to system priorities: + sched_param param; + const int top_prio = max_prio - 1; + const int low_prio = min_prio + 1; + switch (priority) { + case ThreadPriority::kLow: + param.sched_priority = low_prio; + break; + 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 ThreadPriority::kHigh: + param.sched_priority = std::max(top_prio - 2, low_prio); + break; + case ThreadPriority::kRealtime: + param.sched_priority = top_prio; + break; + } + return pthread_setschedparam(pthread_self(), policy, ¶m) == 0; +#endif // defined(WEBRTC_WIN) +} + +#if defined(WEBRTC_WIN) +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) + +} // 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()); + + char stacktop; + AutoRegisterProfiler profiler(name.c_str(), &stacktop); + + 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; + // Mozilla: Set to 256kb for consistency with nsIThreadManager.idl + PlatformThread::Handle handle = ::CreateThread( + nullptr, 256 * 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. + // Mozilla: Set to 256kb for consistency with nsIThreadManager.idl + pthread_attr_setstacksize(&attr, 256 * 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 |