diff options
Diffstat (limited to 'webrtc/base/platform_thread.cc')
-rw-r--r-- | webrtc/base/platform_thread.cc | 174 |
1 files changed, 171 insertions, 3 deletions
diff --git a/webrtc/base/platform_thread.cc b/webrtc/base/platform_thread.cc index 4167392363..05b7a258c0 100644 --- a/webrtc/base/platform_thread.cc +++ b/webrtc/base/platform_thread.cc @@ -10,8 +10,6 @@ #include "webrtc/base/platform_thread.h" -#include <string.h> - #include "webrtc/base/checks.h" #if defined(WEBRTC_LINUX) @@ -58,7 +56,6 @@ bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) { } void SetCurrentThreadName(const char* name) { - RTC_DCHECK(strlen(name) < 64); #if defined(WEBRTC_WIN) struct { DWORD dwType; @@ -79,4 +76,175 @@ void SetCurrentThreadName(const char* name) { #endif } +namespace { +#if defined(WEBRTC_WIN) +void CALLBACK RaiseFlag(ULONG_PTR param) { + *reinterpret_cast<bool*>(param) = true; +} +#else +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) +} + +PlatformThread::PlatformThread(ThreadRunFunction func, + void* obj, + const char* thread_name) + : run_function_(func), + obj_(obj), + name_(thread_name ? thread_name : "webrtc"), +#if defined(WEBRTC_WIN) + stop_(false), + thread_(NULL) { +#else + stop_event_(false, false), + thread_(0) { +#endif // defined(WEBRTC_WIN) + RTC_DCHECK(func); + RTC_DCHECK(name_.length() < 64); +} + +PlatformThread::~PlatformThread() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +#if defined(WEBRTC_WIN) + RTC_DCHECK(!thread_); +#endif // defined(WEBRTC_WIN) +} + +#if defined(WEBRTC_WIN) +DWORD WINAPI PlatformThread::StartThread(void* param) { + static_cast<PlatformThread*>(param)->Run(); + return 0; +} +#else +void* PlatformThread::StartThread(void* param) { + static_cast<PlatformThread*>(param)->Run(); + return 0; +} +#endif // defined(WEBRTC_WIN) + +void PlatformThread::Start() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(!thread_) << "Thread already started?"; +#if defined(WEBRTC_WIN) + stop_ = false; + + // 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; + thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this, + STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id); + RTC_CHECK(thread_) << "CreateThread failed"; +#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_.CalledOnValidThread()); +#if defined(WEBRTC_WIN) + return thread_ != nullptr; +#else + return thread_ != 0; +#endif // defined(WEBRTC_WIN) +} + +void PlatformThread::Stop() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (!IsRunning()) + return; + +#if defined(WEBRTC_WIN) + // Set stop_ to |true| on the worker thread. + QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_)); + WaitForSingleObject(thread_, INFINITE); + CloseHandle(thread_); + thread_ = nullptr; +#else + stop_event_.Set(); + RTC_CHECK_EQ(0, pthread_join(thread_, nullptr)); + thread_ = 0; +#endif // defined(WEBRTC_WIN) +} + +void PlatformThread::Run() { + if (!name_.empty()) + rtc::SetCurrentThreadName(name_.c_str()); + do { + // The interface contract of Start/Stop is that for a successfull call to + // Start, there should be at least one call to the run function. So we + // call the function before checking |stop_|. + if (!run_function_(obj_)) + break; +#if defined(WEBRTC_WIN) + // Alertable sleep to permit RaiseFlag to run and update |stop_|. + SleepEx(0, true); + } while (!stop_); +#else + } while (!stop_event_.Wait(0)); +#endif // defined(WEBRTC_WIN) +} + +bool PlatformThread::SetPriority(ThreadPriority priority) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(IsRunning()); +#if defined(WEBRTC_WIN) + return SetThreadPriority(thread_, priority) != FALSE; +#elif defined(__native_client__) + // Setting thread priorities is not supported in NaCl. + 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 +#ifdef WEBRTC_THREAD_RR + const int policy = SCHED_RR; +#else + const int policy = SCHED_FIFO; +#endif + const int min_prio = sched_get_priority_min(policy); + const int max_prio = sched_get_priority_max(policy); + if (min_prio == -1 || max_prio == -1) { + return false; + } + + if (max_prio - min_prio <= 2) + return false; + + // Convert webrtc priority to system priorities: + sched_param param; + const int top_prio = max_prio - 1; + const int low_prio = min_prio + 1; + switch (priority) { + case kLowPriority: + param.sched_priority = low_prio; + break; + case kNormalPriority: + // The -1 ensures that the kHighPriority is always greater or equal to + // kNormalPriority. + param.sched_priority = (low_prio + top_prio - 1) / 2; + break; + case kHighPriority: + param.sched_priority = std::max(top_prio - 2, low_prio); + break; + case kHighestPriority: + param.sched_priority = std::max(top_prio - 1, low_prio); + break; + case kRealtimePriority: + param.sched_priority = top_prio; + break; + } + return pthread_setschedparam(thread_, policy, ¶m) == 0; +#endif // defined(WEBRTC_WIN) +} + } // namespace rtc |