blob: 84ed52d168f94763ee1ab23af0c99cc5133407f7 [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 +000065void* ThreadPosix::StartThread(void* param) {
pbos@webrtc.org86639732015-03-13 00:06:21 +000066 static_cast<ThreadPosix*>(param)->Run();
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000067 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000068}
69
ajm@google.comb5c49ff2011-08-01 17:04:04 +000070ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj,
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000071 ThreadPriority prio, const char* thread_name)
72 : run_function_(func),
73 obj_(obj),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000074 prio_(prio),
pbos@webrtc.org86639732015-03-13 00:06:21 +000075 started_(false),
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +000076 stop_event_(true, false),
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000077 name_(thread_name ? thread_name : "webrtc"),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000078 thread_(0) {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000079 DCHECK(name_.length() < kThreadMaxNameLength);
niklase@google.com470e71d2011-07-07 08:21:25 +000080}
81
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +000082uint32_t ThreadWrapper::GetThreadId() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000083 return rtc::CurrentThreadId();
niklase@google.com470e71d2011-07-07 08:21:25 +000084}
85
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000086ThreadPosix::~ThreadPosix() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000087 DCHECK(thread_checker_.CalledOnValidThread());
niklase@google.com470e71d2011-07-07 08:21:25 +000088}
89
pbos@webrtc.org86639732015-03-13 00:06:21 +000090// TODO(pbos): Make Start void, calling code really doesn't support failures
91// here.
92bool ThreadPosix::Start() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000093 DCHECK(thread_checker_.CalledOnValidThread());
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000094
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000095 ThreadAttributes attr;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000096 // Set the stack stack size to 1M.
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000097 pthread_attr_setstacksize(&attr, 1024 * 1024);
98
pbos@webrtc.org86639732015-03-13 00:06:21 +000099 CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
100 started_ = true;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000101 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000102}
103
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000104bool ThreadPosix::Stop() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000105 DCHECK(thread_checker_.CalledOnValidThread());
pbos@webrtc.org86639732015-03-13 00:06:21 +0000106 if (!started_)
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000107 return true;
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000108
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000109 stop_event_.Set();
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000110 CHECK_EQ(0, pthread_join(thread_, nullptr));
pbos@webrtc.org86639732015-03-13 00:06:21 +0000111 started_ = false;
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000112 stop_event_.Reset();
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000113
114 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000115}
116
pbos@webrtc.org86639732015-03-13 00:06:21 +0000117void ThreadPosix::Run() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000118 if (!name_.empty()) {
119 // Setting the thread name may fail (harmlessly) if running inside a
120 // sandbox. Ignore failures if they happen.
121#if defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
122 prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name_.c_str()));
123#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
124 pthread_setname_np(name_.substr(0, 63).c_str());
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000125#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000126 }
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000127
128#ifdef WEBRTC_THREAD_RR
129 const int policy = SCHED_RR;
130#else
131 const int policy = SCHED_FIFO;
132#endif
133 const int min_prio = sched_get_priority_min(policy);
134 const int max_prio = sched_get_priority_max(policy);
135 if ((min_prio == -1) || (max_prio == -1)) {
136 WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
137 "unable to retreive min or max priority for threads");
138 }
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000139
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000140 if (max_prio - min_prio > 2) {
141 sched_param param;
142 param.sched_priority = ConvertToSystemPriority(prio_, min_prio, max_prio);
143 if (pthread_setschedparam(pthread_self(), policy, &param) != 0) {
144 WEBRTC_TRACE(
145 kTraceError, kTraceUtility, -1, "unable to set thread priority");
146 }
147 }
148
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000149 // It's a requirement that for successful thread creation that the run
150 // function be called at least once (see RunFunctionIsCalled unit test),
151 // so to fullfill that requirement, we use a |do| loop and not |while|.
152 do {
153 if (!run_function_(obj_))
154 break;
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000155 } while (!stop_event_.Wait(0));
niklase@google.com470e71d2011-07-07 08:21:25 +0000156}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000157
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000158} // namespace webrtc