blob: fe928ef50f2563a7e5a86c00385ab9cd353dfbcb [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.orgd0165c62015-02-09 11:47:57 +000085 stop_event_(true, false),
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000086 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.org11c5db02015-02-09 16:31:31 +0000113 CHECK_EQ(kEventSignaled, params.started->Wait(WEBRTC_EVENT_INFINITE));
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000114 DCHECK_NE(thread_id_, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000116 thread_id = thread_id_;
117
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000118 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000119}
120
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000121bool ThreadPosix::Stop() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000122 DCHECK(thread_checker_.CalledOnValidThread());
123 if (!thread_id_)
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000124 return true;
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000125
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000126 stop_event_.Set();
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000127 CHECK_EQ(0, pthread_join(thread_, nullptr));
128 thread_id_ = 0;
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000129 stop_event_.Reset();
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000130
131 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000132}
133
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000134void ThreadPosix::Run(ThreadPosix::InitParams* params) {
135 thread_id_ = rtc::CurrentThreadId();
136 params->started->Set();
niklase@google.com470e71d2011-07-07 08:21:25 +0000137
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000138 if (!name_.empty()) {
139 // Setting the thread name may fail (harmlessly) if running inside a
140 // sandbox. Ignore failures if they happen.
141#if defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
142 prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name_.c_str()));
143#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
144 pthread_setname_np(name_.substr(0, 63).c_str());
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000145#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000146 }
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000147
148#ifdef WEBRTC_THREAD_RR
149 const int policy = SCHED_RR;
150#else
151 const int policy = SCHED_FIFO;
152#endif
153 const int min_prio = sched_get_priority_min(policy);
154 const int max_prio = sched_get_priority_max(policy);
155 if ((min_prio == -1) || (max_prio == -1)) {
156 WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
157 "unable to retreive min or max priority for threads");
158 }
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000159
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000160 if (max_prio - min_prio > 2) {
161 sched_param param;
162 param.sched_priority = ConvertToSystemPriority(prio_, min_prio, max_prio);
163 if (pthread_setschedparam(pthread_self(), policy, &param) != 0) {
164 WEBRTC_TRACE(
165 kTraceError, kTraceUtility, -1, "unable to set thread priority");
166 }
167 }
168
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000169 // It's a requirement that for successful thread creation that the run
170 // function be called at least once (see RunFunctionIsCalled unit test),
171 // so to fullfill that requirement, we use a |do| loop and not |while|.
172 do {
173 if (!run_function_(obj_))
174 break;
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000175 } while (!stop_event_.Wait(0));
niklase@google.com470e71d2011-07-07 08:21:25 +0000176}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000177
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000178} // namespace webrtc