blob: 7245b0b976b04c14920ae9d21a9df1b948b4a17a [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
hta@webrtc.orge1919f42012-05-22 15:57:34 +000011// The state of a thread is controlled by the two member variables
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000012// alive_ and dead_.
13// alive_ represents the state the thread has been ordered to achieve.
hta@webrtc.orge1919f42012-05-22 15:57:34 +000014// It is set to true by the thread at startup, and is set to false by
15// other threads, using SetNotAlive() and Stop().
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000016// dead_ represents the state the thread has achieved.
hta@webrtc.orge1919f42012-05-22 15:57:34 +000017// It is written by the thread encapsulated by this class only
18// (except at init). It is read only by the Stop() method.
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000019// The Run() method fires event_ when it's started; this ensures that the
20// Start() method does not continue until after dead_ is false.
hta@webrtc.orge1919f42012-05-22 15:57:34 +000021// This protects against premature Stop() calls from the creator thread, but
22// not from other threads.
23
24// Their transitions and states:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000025// alive_ dead_ Set by
hta@webrtc.orge1919f42012-05-22 15:57:34 +000026// false true Constructor
27// true false Run() method entry
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000028// false any Run() method run_function failure
29// any false Run() method exit (happens only with alive_ false)
hta@webrtc.orge1919f42012-05-22 15:57:34 +000030// false any SetNotAlive
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000031// false any Stop Stop waits for dead_ to become true.
hta@webrtc.orge1919f42012-05-22 15:57:34 +000032//
33// Summarized a different way:
34// Variable Writer Reader
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000035// alive_ Constructor(false) Run.loop
hta@webrtc.orge1919f42012-05-22 15:57:34 +000036// Run.start(true)
37// Run.fail(false)
38// SetNotAlive(false)
39// Stop(false)
40//
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000041// dead_ Constructor(true) Stop.loop
hta@webrtc.orge1919f42012-05-22 15:57:34 +000042// Run.start(false)
43// Run.exit(true)
44
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000045#include "webrtc/system_wrappers/source/thread_posix.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000046
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000047#include <algorithm>
48
49#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000050#include <errno.h>
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000051#include <string.h> // strncpy
52#include <time.h> // nanosleep
niklase@google.com470e71d2011-07-07 08:21:25 +000053#include <unistd.h>
54#ifdef WEBRTC_LINUX
55#include <sys/types.h>
56#include <sched.h>
57#include <sys/syscall.h>
58#include <linux/unistd.h>
59#include <sys/prctl.h>
60#endif
61
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000062#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
63#include "webrtc/system_wrappers/interface/event_wrapper.h"
64#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000065
66namespace webrtc {
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000067
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000068int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
69 int max_prio) {
70 assert(max_prio - min_prio > 2);
71 const int top_prio = max_prio - 1;
72 const int low_prio = min_prio + 1;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000073
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000074 switch (priority) {
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000075 case kLowPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000076 return low_prio;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000077 case kNormalPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000078 // The -1 ensures that the kHighPriority is always greater or equal to
79 // kNormalPriority.
80 return (low_prio + top_prio - 1) / 2;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000081 case kHighPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000082 return std::max(top_prio - 2, low_prio);
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000083 case kHighestPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000084 return std::max(top_prio - 1, low_prio);
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000085 case kRealtimePriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000086 return top_prio;
87 }
88 assert(false);
89 return low_prio;
henrike@webrtc.org5ba44112012-10-05 14:36:54 +000090}
91
niklase@google.com470e71d2011-07-07 08:21:25 +000092extern "C"
93{
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000094 static void* StartThread(void* lp_parameter) {
95 static_cast<ThreadPosix*>(lp_parameter)->Run();
96 return 0;
97 }
niklase@google.com470e71d2011-07-07 08:21:25 +000098}
99
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000100ThreadWrapper* ThreadPosix::Create(ThreadRunFunction func,
101 ThreadObj obj,
102 ThreadPriority prio,
103 const char* thread_name) {
104 ThreadPosix* ptr = new ThreadPosix(func, obj, prio, thread_name);
105 if (!ptr) {
106 return NULL;
107 }
108 const int error = ptr->Construct();
109 if (error) {
110 delete ptr;
111 return NULL;
112 }
113 return ptr;
niklase@google.com470e71d2011-07-07 08:21:25 +0000114}
115
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000116ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj,
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000117 ThreadPriority prio, const char* thread_name)
118 : run_function_(func),
119 obj_(obj),
120 crit_state_(CriticalSectionWrapper::CreateCriticalSection()),
121 alive_(false),
122 dead_(true),
123 prio_(prio),
124 event_(EventWrapper::Create()),
125 name_(),
126 set_thread_name_(false),
pwestin@webrtc.orgdf9866f2012-01-11 08:57:47 +0000127#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID))
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000128 pid_(-1),
pwestin@webrtc.orgdf9866f2012-01-11 08:57:47 +0000129#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000130 attr_(),
131 thread_(0) {
132 if (thread_name != NULL) {
133 set_thread_name_ = true;
134 strncpy(name_, thread_name, kThreadMaxNameLength);
135 name_[kThreadMaxNameLength - 1] = '\0';
136 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000137}
138
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000139uint32_t ThreadWrapper::GetThreadId() {
140#if defined(WEBRTC_ANDROID) || defined(WEBRTC_LINUX)
141 return static_cast<uint32_t>(syscall(__NR_gettid));
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000142#else
143 return reinterpret_cast<uint32_t>(pthread_self());
144#endif
145}
146
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000147int ThreadPosix::Construct() {
148 int result = 0;
leozwang@google.comb3527002011-07-26 17:29:38 +0000149#if !defined(WEBRTC_ANDROID)
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000150 // Enable immediate cancellation if requested, see Shutdown().
151 result = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
152 if (result != 0) {
153 return -1;
154 }
155 result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
156 if (result != 0) {
157 return -1;
158 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000159#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000160 result = pthread_attr_init(&attr_);
161 if (result != 0) {
162 return -1;
163 }
164 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000165}
166
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000167ThreadPosix::~ThreadPosix() {
168 pthread_attr_destroy(&attr_);
169 delete event_;
170 delete crit_state_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000171}
172
sjlee@webrtc.org414fa7f2012-09-11 17:25:46 +0000173#define HAS_THREAD_ID !defined(WEBRTC_IOS) && !defined(WEBRTC_MAC)
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000174
175bool ThreadPosix::Start(unsigned int& thread_id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000176{
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000177 if (!run_function_) {
178 return false;
179 }
180 int result = pthread_attr_setdetachstate(&attr_, PTHREAD_CREATE_DETACHED);
181 // Set the stack stack size to 1M.
182 result |= pthread_attr_setstacksize(&attr_, 1024 * 1024);
niklase@google.com470e71d2011-07-07 08:21:25 +0000183#ifdef WEBRTC_THREAD_RR
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000184 const int policy = SCHED_RR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000185#else
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000186 const int policy = SCHED_FIFO;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000188 event_->Reset();
189 // If pthread_create was successful, a thread was created and is running.
190 // Don't return false if it was successful since if there are any other
191 // failures the state will be: thread was started but not configured as
192 // asked for. However, the caller of this API will assume that a false
193 // return value means that the thread never started.
194 result |= pthread_create(&thread_, &attr_, &StartThread, this);
195 if (result != 0) {
196 return false;
197 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000199 // Wait up to 10 seconds for the OS to call the callback function. Prevents
200 // race condition if Stop() is called too quickly after start.
201 if (kEventSignaled != event_->Wait(WEBRTC_EVENT_10_SEC)) {
202 WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
203 "posix thread event never triggered");
204
205 // Timed out. Something went wrong.
206 run_function_ = NULL;
207 return true;
208 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000209
210#if HAS_THREAD_ID
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000211 thread_id = static_cast<unsigned int>(thread_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000212#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000213 sched_param param;
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000215 const int min_prio = sched_get_priority_min(policy);
216 const int max_prio = sched_get_priority_max(policy);
217
218 if ((min_prio == EINVAL) || (max_prio == EINVAL)) {
219 WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
220 "unable to retreive min or max priority for threads");
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 return true;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000222 }
223 if (max_prio - min_prio <= 2) {
224 // There is no room for setting priorities with any granularity.
225 return true;
226 }
227 param.sched_priority = ConvertToSystemPriority(prio_, min_prio, max_prio);
228 result = pthread_setschedparam(thread_, policy, &param);
229 if (result == EINVAL) {
230 WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
231 "unable to set thread priority");
232 }
233 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000234}
235
leozwang@webrtc.org0a272eb2012-02-15 22:35:29 +0000236// CPU_ZERO and CPU_SET are not available in NDK r7, so disable
237// SetAffinity on Android for now.
238#if (defined(WEBRTC_LINUX) && (!defined(WEBRTC_ANDROID)))
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000239bool ThreadPosix::SetAffinity(const int* processor_numbers,
240 const unsigned int amount_of_processors) {
241 if (!processor_numbers || (amount_of_processors == 0)) {
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000242 return false;
243 }
244 cpu_set_t mask;
245 CPU_ZERO(&mask);
niklase@google.com470e71d2011-07-07 08:21:25 +0000246
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000247 for (unsigned int processor = 0;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000248 processor < amount_of_processors;
249 ++processor) {
250 CPU_SET(processor_numbers[processor], &mask);
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000251 }
252#if defined(WEBRTC_ANDROID)
253 // Android.
254 const int result = syscall(__NR_sched_setaffinity,
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000255 pid_,
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000256 sizeof(mask),
257 &mask);
258#else
259 // "Normal" Linux.
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000260 const int result = sched_setaffinity(pid_,
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000261 sizeof(mask),
262 &mask);
263#endif
264 if (result != 0) {
265 return false;
266 }
267 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000268}
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000269
niklase@google.com470e71d2011-07-07 08:21:25 +0000270#else
271// NOTE: On Mac OS X, use the Thread affinity API in
272// /usr/include/mach/thread_policy.h: thread_policy_set and mach_thread_self()
273// instead of Linux gettid() syscall.
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000274bool ThreadPosix::SetAffinity(const int* , const unsigned int) {
275 return false;
276}
277#endif
278
279void ThreadPosix::SetNotAlive() {
280 CriticalSectionScoped cs(crit_state_);
281 alive_ = false;
282}
283
284bool ThreadPosix::Stop() {
285 bool dead = false;
286 {
287 CriticalSectionScoped cs(crit_state_);
288 alive_ = false;
289 dead = dead_;
290 }
291
292 // TODO(hellner) why not use an event here?
293 // Wait up to 10 seconds for the thread to terminate
294 for (int i = 0; i < 1000 && !dead; i++) {
295 timespec t;
296 t.tv_sec = 0;
297 t.tv_nsec = 10 * 1000 * 1000;
298 nanosleep(&t, NULL);
299 {
300 CriticalSectionScoped cs(crit_state_);
301 dead = dead_;
302 }
303 }
304 if (dead) {
305 return true;
306 } else {
niklase@google.com470e71d2011-07-07 08:21:25 +0000307 return false;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000308 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000309}
310
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000311void ThreadPosix::Run() {
312 {
313 CriticalSectionScoped cs(crit_state_);
314 alive_ = true;
315 dead_ = false;
316 }
pwestin@webrtc.orgdf9866f2012-01-11 08:57:47 +0000317#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID))
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000318 pid_ = GetThreadId();
pwestin@webrtc.orgdf9866f2012-01-11 08:57:47 +0000319#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000320 // The event the Start() is waiting for.
321 event_->Set();
niklase@google.com470e71d2011-07-07 08:21:25 +0000322
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000323 if (set_thread_name_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000324#ifdef WEBRTC_LINUX
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000325 prctl(PR_SET_NAME, (unsigned long)name_, 0, 0, 0);
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +0000326#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000327 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
328 "Thread with name:%s started ", name_);
329 } else {
330 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
331 "Thread without name started");
332 }
333 bool alive = true;
334 do {
335 if (run_function_) {
336 if (!run_function_(obj_)) {
337 alive = false;
338 }
339 } else {
340 alive = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000342 {
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000343 CriticalSectionScoped cs(crit_state_);
344 if (!alive) {
345 alive_ = false;
346 }
347 alive = alive_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000348 }
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000349 } while (alive);
niklase@google.com470e71d2011-07-07 08:21:25 +0000350
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000351 if (set_thread_name_) {
352 // Don't set the name for the trace thread because it may cause a
353 // deadlock. TODO(hellner) there should be a better solution than
354 // coupling the thread and the trace class like this.
355 if (strcmp(name_, "Trace")) {
356 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
357 "Thread with name:%s stopped", name_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 }
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000359 } else {
360 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
361 "Thread without name stopped");
362 }
363 {
364 CriticalSectionScoped cs(crit_state_);
365 dead_ = true;
366 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000367}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000368
niklase@google.com470e71d2011-07-07 08:21:25 +0000369} // namespace webrtc