blob: c60541175fb09ca52f4bb28060a7e66a10a676a4 [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.orgaba92192015-03-16 16:05:50 +000065// static
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000066void* ThreadPosix::StartThread(void* param) {
pbos@webrtc.org86639732015-03-13 00:06:21 +000067 static_cast<ThreadPosix*>(param)->Run();
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000068 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000069}
70
tommi@webrtc.org27c0be92015-03-19 14:35:58 +000071ThreadPosix::ThreadPosix(ThreadRunFunction func, void* obj,
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000072 ThreadPriority prio, const char* thread_name)
73 : run_function_(func),
74 obj_(obj),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000075 prio_(prio),
tommi@webrtc.orgaba92192015-03-16 16:05:50 +000076 stop_event_(false, 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.org27c0be92015-03-19 14:35:58 +000079 DCHECK(name_.length() < 64);
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());
tommi@webrtc.orgaba92192015-03-16 16:05:50 +000094 DCHECK(!thread_) << "Thread already started?";
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000095
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000096 ThreadAttributes attr;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000097 // Set the stack stack size to 1M.
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +000098 pthread_attr_setstacksize(&attr, 1024 * 1024);
pbos@webrtc.org86639732015-03-13 00:06:21 +000099 CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000100 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000101}
102
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000103bool ThreadPosix::Stop() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000104 DCHECK(thread_checker_.CalledOnValidThread());
tommi@webrtc.orgaba92192015-03-16 16:05:50 +0000105 if (!thread_)
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000106 return true;
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000107
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000108 stop_event_.Set();
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000109 CHECK_EQ(0, pthread_join(thread_, nullptr));
tommi@webrtc.orgaba92192015-03-16 16:05:50 +0000110 thread_ = 0;
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000111
112 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113}
114
pbos@webrtc.org86639732015-03-13 00:06:21 +0000115void ThreadPosix::Run() {
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000116 if (!name_.empty()) {
117 // Setting the thread name may fail (harmlessly) if running inside a
118 // sandbox. Ignore failures if they happen.
119#if defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
120 prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name_.c_str()));
121#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
122 pthread_setname_np(name_.substr(0, 63).c_str());
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000123#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000124 }
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000125
126#ifdef WEBRTC_THREAD_RR
127 const int policy = SCHED_RR;
128#else
129 const int policy = SCHED_FIFO;
130#endif
131 const int min_prio = sched_get_priority_min(policy);
132 const int max_prio = sched_get_priority_max(policy);
133 if ((min_prio == -1) || (max_prio == -1)) {
134 WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
135 "unable to retreive min or max priority for threads");
136 }
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000137
henrike@webrtc.orgea6c12e2014-09-29 18:25:27 +0000138 if (max_prio - min_prio > 2) {
139 sched_param param;
140 param.sched_priority = ConvertToSystemPriority(prio_, min_prio, max_prio);
141 if (pthread_setschedparam(pthread_self(), policy, &param) != 0) {
142 WEBRTC_TRACE(
143 kTraceError, kTraceUtility, -1, "unable to set thread priority");
144 }
145 }
146
tommi@webrtc.orgd43bdf52015-02-03 16:29:57 +0000147 // It's a requirement that for successful thread creation that the run
148 // function be called at least once (see RunFunctionIsCalled unit test),
149 // so to fullfill that requirement, we use a |do| loop and not |while|.
150 do {
151 if (!run_function_(obj_))
152 break;
tommi@webrtc.orgd0165c62015-02-09 11:47:57 +0000153 } while (!stop_event_.Wait(0));
niklase@google.com470e71d2011-07-07 08:21:25 +0000154}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000155
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000156} // namespace webrtc