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
67namespace webrtc {
68extern "C"
69{
70    static void* StartThread(void* lpParameter)
71    {
72        static_cast<ThreadPosix*>(lpParameter)->Run();
73        return 0;
74    }
75}
76
77ThreadWrapper* 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
94ThreadPosix::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
119uint32_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
129int 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
153ThreadPosix::~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
164bool ThreadPosix::Start(unsigned int& threadID)
165#else
166bool 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)))
238bool 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.
273bool ThreadPosix::SetAffinity(const int* , const unsigned int)
274{
275    return false;
276}
277#endif
278
279void ThreadPosix::SetNotAlive()
280{
281    CriticalSectionScoped cs(_crit_state);
282    _alive = false;
283}
284
285bool 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
299bool 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
331void 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