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, ¶m);
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