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