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