1/* 2 * Copyright (c) 2012 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// The state of a thread is controlled by the two member variables 12// alive_ and dead_. 13// alive_ represents the state the thread has been ordered to achieve. 14// It is set to true by the thread at startup, and is set to false by 15// other threads, using SetNotAlive() and Stop(). 16// dead_ represents the state the thread has achieved. 17// It is written by the thread encapsulated by this class only 18// (except at init). It is read only by the Stop() method. 19// The Run() method fires event_ when it's started; this ensures that the 20// Start() method does not continue until after dead_ is false. 21// This protects against premature Stop() calls from the creator thread, but 22// not from other threads. 23 24// Their transitions and states: 25// alive_ dead_ Set by 26// false true Constructor 27// true false Run() method entry 28// false any Run() method run_function failure 29// any false Run() method exit (happens only with alive_ false) 30// false any SetNotAlive 31// false any Stop Stop waits for dead_ to become true. 32// 33// Summarized a different way: 34// Variable Writer Reader 35// alive_ Constructor(false) Run.loop 36// Run.start(true) 37// Run.fail(false) 38// SetNotAlive(false) 39// Stop(false) 40// 41// dead_ Constructor(true) Stop.loop 42// Run.start(false) 43// Run.exit(true) 44 45#include "webrtc/system_wrappers/source/thread_posix.h" 46 47#include <algorithm> 48 49#include <assert.h> 50#include <errno.h> 51#include <string.h> // strncpy 52#include <unistd.h> 53#ifdef WEBRTC_LINUX 54#include <linux/unistd.h> 55#include <sched.h> 56#include <sys/prctl.h> 57#include <sys/syscall.h> 58#include <sys/types.h> 59#endif 60 61#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 62#include "webrtc/system_wrappers/interface/event_wrapper.h" 63#include "webrtc/system_wrappers/interface/sleep.h" 64#include "webrtc/system_wrappers/interface/trace.h" 65 66namespace webrtc { 67 68int 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; 73 74 switch (priority) { 75 case kLowPriority: 76 return low_prio; 77 case kNormalPriority: 78 // The -1 ensures that the kHighPriority is always greater or equal to 79 // kNormalPriority. 80 return (low_prio + top_prio - 1) / 2; 81 case kHighPriority: 82 return std::max(top_prio - 2, low_prio); 83 case kHighestPriority: 84 return std::max(top_prio - 1, low_prio); 85 case kRealtimePriority: 86 return top_prio; 87 } 88 assert(false); 89 return low_prio; 90} 91 92extern "C" 93{ 94 static void* StartThread(void* lp_parameter) { 95 static_cast<ThreadPosix*>(lp_parameter)->Run(); 96 return 0; 97 } 98} 99 100ThreadWrapper* ThreadPosix::Create(ThreadRunFunction func, ThreadObj obj, 101 ThreadPriority prio, 102 const char* thread_name) { 103 ThreadPosix* ptr = new ThreadPosix(func, obj, prio, thread_name); 104 if (!ptr) { 105 return NULL; 106 } 107 const int error = ptr->Construct(); 108 if (error) { 109 delete ptr; 110 return NULL; 111 } 112 return ptr; 113} 114 115ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj, 116 ThreadPriority prio, const char* thread_name) 117 : run_function_(func), 118 obj_(obj), 119 crit_state_(CriticalSectionWrapper::CreateCriticalSection()), 120 alive_(false), 121 dead_(true), 122 prio_(prio), 123 event_(EventWrapper::Create()), 124 name_(), 125 set_thread_name_(false), 126#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) 127 pid_(-1), 128#endif 129 attr_(), 130 thread_(0) { 131 if (thread_name != NULL) { 132 set_thread_name_ = true; 133 strncpy(name_, thread_name, kThreadMaxNameLength); 134 name_[kThreadMaxNameLength - 1] = '\0'; 135 } 136} 137 138uint32_t ThreadWrapper::GetThreadId() { 139#if defined(WEBRTC_ANDROID) || defined(WEBRTC_LINUX) 140 return static_cast<uint32_t>(syscall(__NR_gettid)); 141#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS) 142 return pthread_mach_thread_np(pthread_self()); 143#else 144 return reinterpret_cast<uint32_t>(pthread_self()); 145#endif 146} 147 148int ThreadPosix::Construct() { 149 int result = 0; 150#if !defined(WEBRTC_ANDROID) 151 // Enable immediate cancellation if requested, see Shutdown(). 152 result = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 153 if (result != 0) { 154 return -1; 155 } 156 result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 157 if (result != 0) { 158 return -1; 159 } 160#endif 161 result = pthread_attr_init(&attr_); 162 if (result != 0) { 163 return -1; 164 } 165 return 0; 166} 167 168ThreadPosix::~ThreadPosix() { 169 pthread_attr_destroy(&attr_); 170 delete event_; 171 delete crit_state_; 172} 173 174#define HAS_THREAD_ID !defined(WEBRTC_IOS) && !defined(WEBRTC_MAC) 175 176bool ThreadPosix::Start(unsigned int& thread_id) 177{ 178 int result = pthread_attr_setdetachstate(&attr_, PTHREAD_CREATE_DETACHED); 179 // Set the stack stack size to 1M. 180 result |= pthread_attr_setstacksize(&attr_, 1024 * 1024); 181#ifdef WEBRTC_THREAD_RR 182 const int policy = SCHED_RR; 183#else 184 const int policy = SCHED_FIFO; 185#endif 186 event_->Reset(); 187 // If pthread_create was successful, a thread was created and is running. 188 // Don't return false if it was successful since if there are any other 189 // failures the state will be: thread was started but not configured as 190 // asked for. However, the caller of this API will assume that a false 191 // return value means that the thread never started. 192 result |= pthread_create(&thread_, &attr_, &StartThread, this); 193 if (result != 0) { 194 return false; 195 } 196 { 197 CriticalSectionScoped cs(crit_state_); 198 dead_ = false; 199 } 200 201 // Wait up to 10 seconds for the OS to call the callback function. Prevents 202 // race condition if Stop() is called too quickly after start. 203 if (kEventSignaled != event_->Wait(WEBRTC_EVENT_10_SEC)) { 204 WEBRTC_TRACE(kTraceError, kTraceUtility, -1, 205 "posix thread event never triggered"); 206 // Timed out. Something went wrong. 207 return true; 208 } 209 210#if HAS_THREAD_ID 211 thread_id = static_cast<unsigned int>(thread_); 212#endif 213 sched_param param; 214 215 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"); 221 return true; 222 } 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, ¶m); 229 if (result == EINVAL) { 230 WEBRTC_TRACE(kTraceError, kTraceUtility, -1, 231 "unable to set thread priority"); 232 } 233 return true; 234} 235 236// 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))) 239bool ThreadPosix::SetAffinity(const int* processor_numbers, 240 const unsigned int amount_of_processors) { 241 if (!processor_numbers || (amount_of_processors == 0)) { 242 return false; 243 } 244 cpu_set_t mask; 245 CPU_ZERO(&mask); 246 247 for (unsigned int processor = 0; 248 processor < amount_of_processors; 249 ++processor) { 250 CPU_SET(processor_numbers[processor], &mask); 251 } 252#if defined(WEBRTC_ANDROID) 253 // Android. 254 const int result = syscall(__NR_sched_setaffinity, 255 pid_, 256 sizeof(mask), 257 &mask); 258#else 259 // "Normal" Linux. 260 const int result = sched_setaffinity(pid_, 261 sizeof(mask), 262 &mask); 263#endif 264 if (result != 0) { 265 return false; 266 } 267 return true; 268} 269 270#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. 274bool 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 SleepMs(10); 296 { 297 CriticalSectionScoped cs(crit_state_); 298 dead = dead_; 299 } 300 } 301 if (dead) { 302 return true; 303 } else { 304 return false; 305 } 306} 307 308void ThreadPosix::Run() { 309 { 310 CriticalSectionScoped cs(crit_state_); 311 alive_ = true; 312 } 313#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) 314 pid_ = GetThreadId(); 315#endif 316 // The event the Start() is waiting for. 317 event_->Set(); 318 319 if (set_thread_name_) { 320#ifdef WEBRTC_LINUX 321 prctl(PR_SET_NAME, (unsigned long)name_, 0, 0, 0); 322#endif 323 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, 324 "Thread with name:%s started ", name_); 325 } else { 326 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, 327 "Thread without name started"); 328 } 329 bool alive = true; 330 bool run = true; 331 while (alive) { 332 run = run_function_(obj_); 333 CriticalSectionScoped cs(crit_state_); 334 if (!run) { 335 alive_ = false; 336 } 337 alive = alive_; 338 } 339 340 if (set_thread_name_) { 341 // Don't set the name for the trace thread because it may cause a 342 // deadlock. TODO(hellner) there should be a better solution than 343 // coupling the thread and the trace class like this. 344 if (strcmp(name_, "Trace")) { 345 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, 346 "Thread with name:%s stopped", name_); 347 } 348 } else { 349 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, 350 "Thread without name stopped"); 351 } 352 { 353 CriticalSectionScoped cs(crit_state_); 354 dead_ = true; 355 } 356} 357 358} // namespace webrtc 359