blob: af90672a81a7b0c9e9a31f918542d252798a8621 [file] [log] [blame]
Tommibebc6902015-05-18 09:51:42 +02001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
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
11#include "webrtc/base/platform_thread.h"
12
13#include "webrtc/base/checks.h"
14
15#if defined(WEBRTC_LINUX)
Tommiea14f0a2015-05-18 13:51:06 +020016#include <sys/prctl.h>
Tommibebc6902015-05-18 09:51:42 +020017#include <sys/syscall.h>
18#endif
19
20namespace rtc {
21
22PlatformThreadId CurrentThreadId() {
23 PlatformThreadId ret;
24#if defined(WEBRTC_WIN)
25 ret = GetCurrentThreadId();
26#elif defined(WEBRTC_POSIX)
27#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
28 ret = pthread_mach_thread_np(pthread_self());
29#elif defined(WEBRTC_LINUX)
30 ret = syscall(__NR_gettid);
31#elif defined(WEBRTC_ANDROID)
32 ret = gettid();
33#else
34 // Default implementation for nacl and solaris.
35 ret = reinterpret_cast<pid_t>(pthread_self());
36#endif
37#endif // defined(WEBRTC_POSIX)
henrikg91d6ede2015-09-17 00:24:34 -070038 RTC_DCHECK(ret);
Tommibebc6902015-05-18 09:51:42 +020039 return ret;
40}
41
42PlatformThreadRef CurrentThreadRef() {
43#if defined(WEBRTC_WIN)
44 return GetCurrentThreadId();
45#elif defined(WEBRTC_POSIX)
46 return pthread_self();
47#endif
48}
49
50bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
51#if defined(WEBRTC_WIN)
52 return a == b;
53#elif defined(WEBRTC_POSIX)
54 return pthread_equal(a, b);
55#endif
56}
57
Tommiea14f0a2015-05-18 13:51:06 +020058void SetCurrentThreadName(const char* name) {
Tommiea14f0a2015-05-18 13:51:06 +020059#if defined(WEBRTC_WIN)
60 struct {
61 DWORD dwType;
62 LPCSTR szName;
63 DWORD dwThreadID;
64 DWORD dwFlags;
65 } threadname_info = {0x1000, name, static_cast<DWORD>(-1), 0};
66
67 __try {
68 ::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(DWORD),
69 reinterpret_cast<ULONG_PTR*>(&threadname_info));
70 } __except (EXCEPTION_EXECUTE_HANDLER) {
71 }
72#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
73 prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name));
74#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
75 pthread_setname_np(name);
76#endif
77}
78
Tommibebc6902015-05-18 09:51:42 +020079} // namespace rtc
pbos12411ef2015-11-23 14:47:56 -080080
81namespace webrtc {
82
83rtc::scoped_ptr<PlatformThread> PlatformThread::CreateThread(
84 ThreadRunFunction func,
85 void* obj,
86 const char* thread_name) {
87 return rtc::scoped_ptr<PlatformThread>(
88 new PlatformThread(func, obj, thread_name));
89}
90
91namespace {
92#if defined(WEBRTC_WIN)
93void CALLBACK RaiseFlag(ULONG_PTR param) {
94 *reinterpret_cast<bool*>(param) = true;
95}
96#else
97struct ThreadAttributes {
98 ThreadAttributes() { pthread_attr_init(&attr); }
99 ~ThreadAttributes() { pthread_attr_destroy(&attr); }
100 pthread_attr_t* operator&() { return &attr; }
101 pthread_attr_t attr;
102};
pbos12411ef2015-11-23 14:47:56 -0800103#endif // defined(WEBRTC_WIN)
104}
105
106PlatformThread::PlatformThread(ThreadRunFunction func,
107 void* obj,
108 const char* thread_name)
109 : run_function_(func),
110 obj_(obj),
111 name_(thread_name ? thread_name : "webrtc"),
112#if defined(WEBRTC_WIN)
113 stop_(false),
114 thread_(NULL) {
115#else
116 stop_event_(false, false),
117 thread_(0) {
118#endif // defined(WEBRTC_WIN)
119 RTC_DCHECK(func);
120 RTC_DCHECK(name_.length() < 64);
121}
122
123PlatformThread::~PlatformThread() {
124 RTC_DCHECK(thread_checker_.CalledOnValidThread());
125#if defined(WEBRTC_WIN)
126 RTC_DCHECK(!thread_);
127#endif // defined(WEBRTC_WIN)
128}
129
130#if defined(WEBRTC_WIN)
131DWORD WINAPI PlatformThread::StartThread(void* param) {
132 static_cast<PlatformThread*>(param)->Run();
133 return 0;
134}
135#else
136void* PlatformThread::StartThread(void* param) {
137 static_cast<PlatformThread*>(param)->Run();
138 return 0;
139}
140#endif // defined(WEBRTC_WIN)
141
142bool PlatformThread::Start() {
143 RTC_DCHECK(thread_checker_.CalledOnValidThread());
144 RTC_DCHECK(!thread_) << "Thread already started?";
145#if defined(WEBRTC_WIN)
146 stop_ = false;
147
148 // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
149 // Set the reserved stack stack size to 1M, which is the default on Windows
150 // and Linux.
151 DWORD thread_id;
152 thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this,
153 STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id);
154 RTC_CHECK(thread_) << "CreateThread failed";
155#else
156 ThreadAttributes attr;
157 // Set the stack stack size to 1M.
158 pthread_attr_setstacksize(&attr, 1024 * 1024);
159 RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
160#endif // defined(WEBRTC_WIN)
161 return true;
162}
163
164bool PlatformThread::Stop() {
165 RTC_DCHECK(thread_checker_.CalledOnValidThread());
166#if defined(WEBRTC_WIN)
167 if (thread_) {
168 // Set stop_ to |true| on the worker thread.
169 QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_));
170 WaitForSingleObject(thread_, INFINITE);
171 CloseHandle(thread_);
172 thread_ = nullptr;
173 }
174#else
175 if (!thread_)
176 return true;
177
178 stop_event_.Set();
179 RTC_CHECK_EQ(0, pthread_join(thread_, nullptr));
180 thread_ = 0;
181#endif // defined(WEBRTC_WIN)
182 return true;
183}
184
185void PlatformThread::Run() {
186 if (!name_.empty())
187 rtc::SetCurrentThreadName(name_.c_str());
188 do {
189 // The interface contract of Start/Stop is that for a successfull call to
190 // Start, there should be at least one call to the run function. So we
191 // call the function before checking |stop_|.
192 if (!run_function_(obj_))
193 break;
194#if defined(WEBRTC_WIN)
195 // Alertable sleep to permit RaiseFlag to run and update |stop_|.
196 SleepEx(0, true);
197 } while (!stop_);
198#else
199 } while (!stop_event_.Wait(0));
200#endif // defined(WEBRTC_WIN)
201}
202
203bool PlatformThread::SetPriority(ThreadPriority priority) {
204 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Peter Boströmc6612132015-11-24 18:10:24 +0100205#if defined(WEBRTC_WIN)
Peter Boström7d842d62015-11-24 18:23:24 +0100206 return thread_ && SetThreadPriority(thread_, priority);
Peter Boströmc6612132015-11-24 18:10:24 +0100207#elif defined(__native_client__)
208 // Setting thread priorities is not supported in NaCl.
209 return true;
210#elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
211 // TODO(tommi): Switch to the same mechanism as Chromium uses for changing
212 // thread priorities.
pbos12411ef2015-11-23 14:47:56 -0800213 return true;
214#else
Peter Boström7d842d62015-11-24 18:23:24 +0100215 if (!thread_)
216 return false;
pbos12411ef2015-11-23 14:47:56 -0800217#ifdef WEBRTC_THREAD_RR
218 const int policy = SCHED_RR;
219#else
220 const int policy = SCHED_FIFO;
221#endif
222 const int min_prio = sched_get_priority_min(policy);
223 const int max_prio = sched_get_priority_max(policy);
224 if (min_prio == -1 || max_prio == -1) {
225 return false;
226 }
227
228 if (max_prio - min_prio <= 2)
229 return false;
230
Peter Boström97c821d2015-11-24 13:48:13 +0100231 // Convert webrtc priority to system priorities:
pbos12411ef2015-11-23 14:47:56 -0800232 sched_param param;
Peter Boström97c821d2015-11-24 13:48:13 +0100233 const int top_prio = max_prio - 1;
234 const int low_prio = min_prio + 1;
235 switch (priority) {
236 case kLowPriority:
237 param.sched_priority = low_prio;
238 break;
239 case kNormalPriority:
240 // The -1 ensures that the kHighPriority is always greater or equal to
241 // kNormalPriority.
242 param.sched_priority = (low_prio + top_prio - 1) / 2;
243 break;
244 case kHighPriority:
245 param.sched_priority = std::max(top_prio - 2, low_prio);
246 break;
247 case kHighestPriority:
248 param.sched_priority = std::max(top_prio - 1, low_prio);
249 break;
250 case kRealtimePriority:
251 param.sched_priority = top_prio;
252 break;
pbos12411ef2015-11-23 14:47:56 -0800253 }
Peter Boström97c821d2015-11-24 13:48:13 +0100254 return pthread_setschedparam(thread_, policy, &param) == 0;
pbos12411ef2015-11-23 14:47:56 -0800255#endif // defined(WEBRTC_WIN)
256}
257
258} // namespace webrtc