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 {
StartThread(void * lpParameter)70     static void* StartThread(void* lpParameter)
71     {
72         static_cast<ThreadPosix*>(lpParameter)->Run();
73         return 0;
74     }
75 }
76 
Create(ThreadRunFunction func,ThreadObj obj,ThreadPriority prio,const char * threadName)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 
ThreadPosix(ThreadRunFunction func,ThreadObj obj,ThreadPriority prio,const char * threadName)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 
GetThreadId()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 
Construct()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 
~ThreadPosix()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
Start(unsigned int & threadID)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)))
SetAffinity(const int * processorNumbers,const unsigned int amountOfProcessors)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.
SetAffinity(const int *,const unsigned int)273 bool ThreadPosix::SetAffinity(const int* , const unsigned int)
274 {
275     return false;
276 }
277 #endif
278 
SetNotAlive()279 void ThreadPosix::SetNotAlive()
280 {
281     CriticalSectionScoped cs(_crit_state);
282     _alive = false;
283 }
284 
Shutdown()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 
Stop()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 
Run()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