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 66 namespace webrtc { 67 68 int 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 92 extern "C" 93 { 94 static void* StartThread(void* lp_parameter) { 95 static_cast<ThreadPosix*>(lp_parameter)->Run(); 96 return 0; 97 } 98 } 99 100 ThreadWrapper* 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 115 ThreadPosix::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 138 uint32_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 148 int 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 168 ThreadPosix::~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 176 bool 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))) 239 bool 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. 274 bool ThreadPosix::SetAffinity(const int* , const unsigned int) { 275 return false; 276 } 277 #endif 278 279 void ThreadPosix::SetNotAlive() { 280 CriticalSectionScoped cs(crit_state_); 281 alive_ = false; 282 } 283 284 bool 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 308 void 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