blob: 4050c82bd122187e7aaf87c8e20e16d57bd61c27 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000011#include "webrtc/system_wrappers/source/thread_posix.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000013#include <algorithm>
14
niklase@google.com470e71d2011-07-07 08:21:25 +000015#include <errno.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000016#include <unistd.h>
17#ifdef WEBRTC_LINUX
niklase@google.com470e71d2011-07-07 08:21:25 +000018#include <linux/unistd.h>
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000019#include <sched.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000020#include <sys/prctl.h>
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000021#include <sys/syscall.h>
22#include <sys/types.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000023#endif
24
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000025#include "webrtc/base/checks.h"
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000026#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
27#include "webrtc/system_wrappers/interface/event_wrapper.h"
hta@webrtc.org2cec0b12013-03-21 14:02:29 +000028#include "webrtc/system_wrappers/interface/sleep.h"
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000029#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000030
31namespace webrtc {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000032namespace {
33struct ThreadAttributes {
34 ThreadAttributes() { pthread_attr_init(&attr); }
35 ~ThreadAttributes() { pthread_attr_destroy(&attr); }
36 pthread_attr_t* operator&() { return &attr; }
37 pthread_attr_t attr;
38};
39} // namespace
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000040
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000041int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
42 int max_prio) {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000043 DCHECK(max_prio - min_prio > 2);
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000044 const int top_prio = max_prio - 1;
45 const int low_prio = min_prio + 1;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000046
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000047 switch (priority) {
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000048 case kLowPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000049 return low_prio;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000050 case kNormalPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000051 // The -1 ensures that the kHighPriority is always greater or equal to
52 // kNormalPriority.
53 return (low_prio + top_prio - 1) / 2;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000054 case kHighPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000055 return std::max(top_prio - 2, low_prio);
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000056 case kHighestPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000057 return std::max(top_prio - 1, low_prio);
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000058 case kRealtimePriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000059 return top_prio;
60 }
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000061 DCHECK(false);
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000062 return low_prio;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000063}
64
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000065struct ThreadPosix::InitParams {
66 InitParams(ThreadPosix* thread)
67 : me(thread), started(EventWrapper::Create()) {
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000068 }
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000069 ThreadPosix* me;
70 rtc::scoped_ptr<EventWrapper> started;
71};
niklase@google.com470e71d2011-07-07 08:21:25 +000072
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000073// static
74void* ThreadPosix::StartThread(void* param) {
75 auto params = static_cast<InitParams*>(param);
76 params->me->Run(params);
77 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000078}
79
ajm@google.comb5c49ff2011-08-01 17:04:04 +000080ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj,
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000081 ThreadPriority prio, const char* thread_name)
82 : run_function_(func),
83 obj_(obj),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000084 prio_(prio),
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000085 stop_event_(EventWrapper::Create()),
86 name_(thread_name ? thread_name : "webrtc"),
87 thread_id_(0),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000088 thread_(0) {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000089 DCHECK(name_.length() < kThreadMaxNameLength);
niklase@google.com470e71d2011-07-07 08:21:25 +000090}
91
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +000092uint32_t ThreadWrapper::GetThreadId() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000093 return rtc::CurrentThreadId();
niklase@google.com470e71d2011-07-07 08:21:25 +000094}
95
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000096ThreadPosix::~ThreadPosix() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000097 DCHECK(thread_checker_.CalledOnValidThread());
niklase@google.com470e71d2011-07-07 08:21:25 +000098}
99
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000100bool ThreadPosix::Start(unsigned int& thread_id) {
101 DCHECK(thread_checker_.CalledOnValidThread());
102 DCHECK(!thread_id_) << "Thread already started?";
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000103
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000104 ThreadAttributes attr;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000105 // Set the stack stack size to 1M.
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000106 pthread_attr_setstacksize(&attr, 1024 * 1024);
107
108 InitParams params(this);
109 int result = pthread_create(&thread_, &attr, &StartThread, &params);
110 if (result != 0)
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000111 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000112
tommi@webrtc.orgccd7e992015-02-06 19:26:42 +0000113 // TODO(tommi): Change the timeout back to WEBRTC_EVENT_INFINITE when we've
114 // figured out where we're seeing tests hang.
115 auto state = params.started->Wait(30 * 1000);
116 CHECK_EQ(kEventSignaled, state);
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000117 DCHECK_NE(thread_id_, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000118
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000119 thread_id = thread_id_;
120
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000121 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000122}
123
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000124bool ThreadPosix::Stop() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000125 DCHECK(thread_checker_.CalledOnValidThread());
126 if (!thread_id_)
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000127 return true;
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000128
129 stop_event_->Set();
130 CHECK_EQ(0, pthread_join(thread_, nullptr));
131 thread_id_ = 0;
132 stop_event_->Reset();
133
134 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135}
136
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000137void ThreadPosix::Run(ThreadPosix::InitParams* params) {
138 thread_id_ = rtc::CurrentThreadId();
139 params->started->Set();
niklase@google.com470e71d2011-07-07 08:21:25 +0000140
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000141 if (!name_.empty()) {
142 // Setting the thread name may fail (harmlessly) if running inside a
143 // sandbox. Ignore failures if they happen.
144#if defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
145 prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name_.c_str()));
146#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
147 pthread_setname_np(name_.substr(0, 63).c_str());
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000148#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000149 }
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000150
151#ifdef WEBRTC_THREAD_RR
152 const int policy = SCHED_RR;
153#else
154 const int policy = SCHED_FIFO;
155#endif
156 const int min_prio = sched_get_priority_min(policy);
157 const int max_prio = sched_get_priority_max(policy);
158 if ((min_prio == -1) || (max_prio == -1)) {
159 WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
160 "unable to retreive min or max priority for threads");
161 }
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000162
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000163 if (max_prio - min_prio > 2) {
164 sched_param param;
165 param.sched_priority = ConvertToSystemPriority(prio_, min_prio, max_prio);
166 if (pthread_setschedparam(pthread_self(), policy, &param) != 0) {
167 WEBRTC_TRACE(
168 kTraceError, kTraceUtility, -1, "unable to set thread priority");
169 }
170 }
171
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000172 // It's a requirement that for successful thread creation that the run
173 // function be called at least once (see RunFunctionIsCalled unit test),
174 // so to fullfill that requirement, we use a |do| loop and not |while|.
175 do {
176 if (!run_function_(obj_))
177 break;
178 } while (stop_event_->Wait(0) == kEventTimeout);
niklase@google.com470e71d2011-07-07 08:21:25 +0000179}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000180
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000181} // namespace webrtc