Home | History | Annotate | Download | only in source
      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, &param);
    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