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 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, &param);
    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