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 runFunction 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 "thread_posix.h" 46 47 #include <errno.h> 48 #include <string.h> // strncpy 49 #include <time.h> // nanosleep 50 #include <unistd.h> 51 #ifdef WEBRTC_LINUX 52 #include <sys/types.h> 53 #include <sched.h> 54 #include <sys/syscall.h> 55 #include <linux/unistd.h> 56 #include <sys/prctl.h> 57 #endif 58 59 #if defined(WEBRTC_MAC) 60 #include <mach/mach.h> 61 #endif 62 63 #include "system_wrappers/interface/critical_section_wrapper.h" 64 #include "system_wrappers/interface/event_wrapper.h" 65 #include "system_wrappers/interface/trace.h" 66 67 namespace webrtc { 68 extern "C" 69 { 70 static void* StartThread(void* lpParameter) 71 { 72 static_cast<ThreadPosix*>(lpParameter)->Run(); 73 return 0; 74 } 75 } 76 77 ThreadWrapper* ThreadPosix::Create(ThreadRunFunction func, ThreadObj obj, 78 ThreadPriority prio, const char* threadName) 79 { 80 ThreadPosix* ptr = new ThreadPosix(func, obj, prio, threadName); 81 if (!ptr) 82 { 83 return NULL; 84 } 85 const int error = ptr->Construct(); 86 if (error) 87 { 88 delete ptr; 89 return NULL; 90 } 91 return ptr; 92 } 93 94 ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj, 95 ThreadPriority prio, const char* threadName) 96 : _runFunction(func), 97 _obj(obj), 98 _crit_state(CriticalSectionWrapper::CreateCriticalSection()), 99 _alive(false), 100 _dead(true), 101 _prio(prio), 102 _event(EventWrapper::Create()), 103 _name(), 104 _setThreadName(false), 105 #if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) 106 _pid(-1), 107 #endif 108 _attr(), 109 _thread(0) 110 { 111 if (threadName != NULL) 112 { 113 _setThreadName = true; 114 strncpy(_name, threadName, kThreadMaxNameLength); 115 _name[kThreadMaxNameLength - 1] = '\0'; 116 } 117 } 118 119 uint32_t ThreadWrapper::GetThreadId() { 120 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_LINUX) 121 return static_cast<uint32_t>(syscall(__NR_gettid)); 122 #elif defined(WEBRTC_MAC) 123 return static_cast<uint32_t>(mach_thread_self()); 124 #else 125 return reinterpret_cast<uint32_t>(pthread_self()); 126 #endif 127 } 128 129 int ThreadPosix::Construct() 130 { 131 int result = 0; 132 #if !defined(WEBRTC_ANDROID) 133 // Enable immediate cancellation if requested, see Shutdown() 134 result = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 135 if (result != 0) 136 { 137 return -1; 138 } 139 result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 140 if (result != 0) 141 { 142 return -1; 143 } 144 #endif 145 result = pthread_attr_init(&_attr); 146 if (result != 0) 147 { 148 return -1; 149 } 150 return 0; 151 } 152 153 ThreadPosix::~ThreadPosix() 154 { 155 pthread_attr_destroy(&_attr); 156 delete _event; 157 delete _crit_state; 158 } 159 160 #define HAS_THREAD_ID !defined(MAC_IPHONE) && !defined(MAC_IPHONE_SIM) && \ 161 !defined(WEBRTC_MAC) && !defined(WEBRTC_MAC_INTEL) && \ 162 !defined(MAC_DYLIB) && !defined(MAC_INTEL_DYLIB) 163 #if HAS_THREAD_ID 164 bool ThreadPosix::Start(unsigned int& threadID) 165 #else 166 bool ThreadPosix::Start(unsigned int& /*threadID*/) 167 #endif 168 { 169 if (!_runFunction) 170 { 171 return false; 172 } 173 int result = pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_DETACHED); 174 // Set the stack stack size to 1M. 175 result |= pthread_attr_setstacksize(&_attr, 1024*1024); 176 #ifdef WEBRTC_THREAD_RR 177 const int policy = SCHED_RR; 178 #else 179 const int policy = SCHED_FIFO; 180 #endif 181 _event->Reset(); 182 result |= pthread_create(&_thread, &_attr, &StartThread, this); 183 if (result != 0) 184 { 185 return false; 186 } 187 188 // Wait up to 10 seconds for the OS to call the callback function. Prevents 189 // race condition if Stop() is called too quickly after start. 190 if (kEventSignaled != _event->Wait(WEBRTC_EVENT_10_SEC)) 191 { 192 // Timed out. Something went wrong. 193 _runFunction = NULL; 194 return false; 195 } 196 197 #if HAS_THREAD_ID 198 threadID = static_cast<unsigned int>(_thread); 199 #endif 200 sched_param param; 201 202 const int minPrio = sched_get_priority_min(policy); 203 const int maxPrio = sched_get_priority_max(policy); 204 if ((minPrio == EINVAL) || (maxPrio == EINVAL)) 205 { 206 return false; 207 } 208 209 switch (_prio) 210 { 211 case kLowPriority: 212 param.sched_priority = minPrio + 1; 213 break; 214 case kNormalPriority: 215 param.sched_priority = (minPrio + maxPrio) / 2; 216 break; 217 case kHighPriority: 218 param.sched_priority = maxPrio - 3; 219 break; 220 case kHighestPriority: 221 param.sched_priority = maxPrio - 2; 222 break; 223 case kRealtimePriority: 224 param.sched_priority = maxPrio - 1; 225 break; 226 } 227 result = pthread_setschedparam(_thread, policy, ¶m); 228 if (result == EINVAL) 229 { 230 return false; 231 } 232 return true; 233 } 234 235 // CPU_ZERO and CPU_SET are not available in NDK r7, so disable 236 // SetAffinity on Android for now. 237 #if (defined(WEBRTC_LINUX) && (!defined(WEBRTC_ANDROID))) 238 bool ThreadPosix::SetAffinity(const int* processorNumbers, 239 const unsigned int amountOfProcessors) { 240 if (!processorNumbers || (amountOfProcessors == 0)) { 241 return false; 242 } 243 cpu_set_t mask; 244 CPU_ZERO(&mask); 245 246 for (unsigned int processor = 0; 247 processor < amountOfProcessors; 248 processor++) { 249 CPU_SET(processorNumbers[processor], &mask); 250 } 251 #if defined(WEBRTC_ANDROID) 252 // Android. 253 const int result = syscall(__NR_sched_setaffinity, 254 _pid, 255 sizeof(mask), 256 &mask); 257 #else 258 // "Normal" Linux. 259 const int result = sched_setaffinity(_pid, 260 sizeof(mask), 261 &mask); 262 #endif 263 if (result != 0) { 264 return false; 265 } 266 return true; 267 } 268 269 #else 270 // NOTE: On Mac OS X, use the Thread affinity API in 271 // /usr/include/mach/thread_policy.h: thread_policy_set and mach_thread_self() 272 // instead of Linux gettid() syscall. 273 bool ThreadPosix::SetAffinity(const int* , const unsigned int) 274 { 275 return false; 276 } 277 #endif 278 279 void ThreadPosix::SetNotAlive() 280 { 281 CriticalSectionScoped cs(_crit_state); 282 _alive = false; 283 } 284 285 bool ThreadPosix::Shutdown() 286 { 287 #if !defined(WEBRTC_ANDROID) 288 if (_thread && (0 != pthread_cancel(_thread))) 289 { 290 return false; 291 } 292 293 return true; 294 #else 295 return false; 296 #endif 297 } 298 299 bool ThreadPosix::Stop() 300 { 301 bool dead = false; 302 { 303 CriticalSectionScoped cs(_crit_state); 304 _alive = false; 305 dead = _dead; 306 } 307 308 // TODO (hellner) why not use an event here? 309 // Wait up to 10 seconds for the thread to terminate 310 for (int i = 0; i < 1000 && !dead; i++) 311 { 312 timespec t; 313 t.tv_sec = 0; 314 t.tv_nsec = 10*1000*1000; 315 nanosleep(&t, NULL); 316 { 317 CriticalSectionScoped cs(_crit_state); 318 dead = _dead; 319 } 320 } 321 if (dead) 322 { 323 return true; 324 } 325 else 326 { 327 return false; 328 } 329 } 330 331 void ThreadPosix::Run() 332 { 333 { 334 CriticalSectionScoped cs(_crit_state); 335 _alive = true; 336 _dead = false; 337 } 338 #if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) 339 _pid = GetThreadId(); 340 #endif 341 // The event the Start() is waiting for. 342 _event->Set(); 343 344 if (_setThreadName) 345 { 346 #ifdef WEBRTC_LINUX 347 prctl(PR_SET_NAME, (unsigned long)_name, 0, 0, 0); 348 #endif 349 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, 350 "Thread with name:%s started ", _name); 351 } else 352 { 353 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, 354 "Thread without name started"); 355 } 356 bool alive = true; 357 do 358 { 359 if (_runFunction) 360 { 361 if (!_runFunction(_obj)) 362 { 363 alive = false; 364 } 365 } 366 else 367 { 368 alive = false; 369 } 370 { 371 CriticalSectionScoped cs(_crit_state); 372 if (!alive) { 373 _alive = false; 374 } 375 alive = _alive; 376 } 377 } 378 while (alive); 379 380 if (_setThreadName) 381 { 382 // Don't set the name for the trace thread because it may cause a 383 // deadlock. TODO (hellner) there should be a better solution than 384 // coupling the thread and the trace class like this. 385 if (strcmp(_name, "Trace")) 386 { 387 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, 388 "Thread with name:%s stopped", _name); 389 } 390 } 391 else 392 { 393 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, 394 "Thread without name stopped"); 395 } 396 { 397 CriticalSectionScoped cs(_crit_state); 398 _dead = true; 399 } 400 } 401 } // namespace webrtc 402