aboutsummaryrefslogtreecommitdiff
path: root/webrtc/base/platform_thread.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/base/platform_thread.cc')
-rw-r--r--webrtc/base/platform_thread.cc174
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, &param) == 0;
+#endif // defined(WEBRTC_WIN)
+}
+
} // namespace rtc