[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / threads / platform / pthreads / ThreadImpl.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <limits.h>
22 #if defined(TARGET_ANDROID)
23 #include <unistd.h>
24 #else
25 #include <sys/syscall.h>
26 #endif
27 #include <sys/resource.h>
28 #include <string.h>
29 #ifdef __FreeBSD__
30 #include <sys/param.h>
31 #if __FreeBSD_version < 900031
32 #include <sys/thr.h>
33 #else
34 #include <pthread_np.h>
35 #endif
36 #endif
37
38 #include <signal.h>
39
40 void CThread::SpawnThread(unsigned stacksize)
41 {
42   pthread_attr_t attr;
43   pthread_attr_init(&attr);
44 #if !defined(TARGET_ANDROID) // http://code.google.com/p/android/issues/detail?id=7808
45   if (stacksize > PTHREAD_STACK_MIN)
46     pthread_attr_setstacksize(&attr, stacksize);
47 #endif
48   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
49   if (pthread_create(&m_ThreadId, &attr, (void*(*)(void*))staticThread, this) != 0)
50   {
51     if (logger) logger->Log(LOGNOTICE, "%s - fatal error creating thread",__FUNCTION__);
52   }
53   pthread_attr_destroy(&attr);
54 }
55
56 void CThread::TermHandler() { }
57
58 void CThread::SetThreadInfo()
59 {
60 #ifdef __FreeBSD__
61 #if __FreeBSD_version < 900031
62   long lwpid;
63   thr_self(&lwpid);
64   m_ThreadOpaque.LwpId = lwpid;
65 #else
66   m_ThreadOpaque.LwpId = pthread_getthreadid_np();
67 #endif
68 #elif defined(TARGET_ANDROID)
69   m_ThreadOpaque.LwpId = gettid();
70 #else
71   m_ThreadOpaque.LwpId = syscall(SYS_gettid);
72 #endif
73
74 #ifdef TARGET_DARWIN
75 #if(__MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 30200)
76   pthread_setname_np(m_ThreadName.c_str());
77 #endif
78 #endif
79     
80 #ifdef RLIMIT_NICE
81   // get user max prio
82   struct rlimit limit;
83   int userMaxPrio;
84   if (getrlimit(RLIMIT_NICE, &limit) == 0)
85   {
86     userMaxPrio = limit.rlim_cur - 20;
87     if (userMaxPrio < 0)
88       userMaxPrio = 0;
89   }
90   else
91     userMaxPrio = 0;
92
93   // if the user does not have an entry in limits.conf the following
94   // call will fail
95   if (userMaxPrio > 0)
96   {
97     // start thread with nice level of appication
98     int appNice = getpriority(PRIO_PROCESS, getpid());
99     if (setpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId, appNice) != 0)
100       if (logger) logger->Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno));
101   }
102 #endif
103 }
104
105 ThreadIdentifier CThread::GetCurrentThreadId()
106 {
107   return pthread_self();
108 }
109
110 bool CThread::IsCurrentThread(const ThreadIdentifier tid)
111 {
112   return pthread_equal(pthread_self(), tid);
113 }
114
115 int CThread::GetMinPriority(void)
116 {
117   // one level lower than application
118   return -1;
119 }
120
121 int CThread::GetMaxPriority(void)
122 {
123   // one level higher than application
124   return 1;
125 }
126
127 int CThread::GetNormalPriority(void)
128 {
129   // same level as application
130   return 0;
131 }
132
133 bool CThread::SetPriority(const int iPriority)
134 {
135   bool bReturn = false;
136
137   // wait until thread is running, it needs to get its lwp id
138   m_StartEvent.Wait();
139   
140   CSingleLock lock(m_CriticalSection);
141
142   // get min prio for SCHED_RR
143   int minRR = GetMaxPriority() + 1;
144
145   if (!m_ThreadId)
146     bReturn = false;
147   else if (iPriority >= minRR)
148     bReturn = SetPrioritySched_RR(iPriority);
149 #ifdef RLIMIT_NICE
150   else
151   {
152     // get user max prio
153     struct rlimit limit;
154     int userMaxPrio;
155     if (getrlimit(RLIMIT_NICE, &limit) == 0)
156     {
157       userMaxPrio = limit.rlim_cur - 20;
158       // is a user has no entry in limits.conf rlim_cur is zero
159       if (userMaxPrio < 0)
160         userMaxPrio = 0;
161     }
162     else
163       userMaxPrio = 0;
164
165     // keep priority in bounds
166     int prio = iPriority;
167     if (prio >= GetMaxPriority())
168       prio = std::min(GetMaxPriority(), userMaxPrio);
169     if (prio < GetMinPriority())
170       prio = GetMinPriority();
171
172     // nice level of application
173     int appNice = getpriority(PRIO_PROCESS, getpid());
174     if (prio)
175       prio = prio > 0 ? appNice-1 : appNice+1;
176
177     if (setpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId, prio) == 0)
178       bReturn = true;
179     else
180       if (logger) logger->Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno));
181   }
182 #endif
183
184   return bReturn;
185 }
186
187 int CThread::GetPriority()
188 {
189   int iReturn;
190
191   // lwp id is valid after start signel has fired
192   m_StartEvent.Wait();
193
194   CSingleLock lock(m_CriticalSection);
195   
196   int appNice = getpriority(PRIO_PROCESS, getpid());
197   int prio = getpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId);
198   iReturn = appNice - prio;
199
200   return iReturn;
201 }
202
203 bool CThread::WaitForThreadExit(unsigned int milliseconds)
204 {
205   bool bReturn = m_TermEvent.WaitMSec(milliseconds);
206
207   return bReturn;
208 }
209
210 int64_t CThread::GetAbsoluteUsage()
211 {
212   CSingleLock lock(m_CriticalSection);
213   
214   if (!m_ThreadId)
215   return 0;
216   
217   int64_t time = 0;
218 #ifdef TARGET_DARWIN
219   thread_basic_info threadInfo;
220   mach_msg_type_number_t threadInfoCount = THREAD_BASIC_INFO_COUNT;
221
222   kern_return_t ret = thread_info(pthread_mach_thread_np(m_ThreadId),
223     THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &threadInfoCount);
224
225   if (ret == KERN_SUCCESS)
226   {
227     // User time.
228     time = ((int64_t)threadInfo.user_time.seconds * 10000000L) + threadInfo.user_time.microseconds*10L;
229
230     // System time.
231     time += (((int64_t)threadInfo.system_time.seconds * 10000000L) + threadInfo.system_time.microseconds*10L);
232   }
233
234 #else
235   clockid_t clock;
236   if (pthread_getcpuclockid(m_ThreadId, &clock) == 0)
237   {
238     struct timespec tp;
239     clock_gettime(clock, &tp);
240     time = (int64_t)tp.tv_sec * 10000000 + tp.tv_nsec/100;
241   }
242 #endif
243
244   return time;
245 }
246
247 float CThread::GetRelativeUsage()
248 {
249   unsigned int iTime = XbmcThreads::SystemClockMillis();
250   iTime *= 10000; // convert into 100ns tics
251
252   // only update every 1 second
253   if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage;
254
255   int64_t iUsage = GetAbsoluteUsage();
256
257   if (m_iLastUsage > 0 && m_iLastTime > 0)
258     m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime );
259
260   m_iLastUsage = iUsage;
261   m_iLastTime = iTime;
262
263   return m_fLastUsage;
264 }
265
266 void term_handler (int signum)
267 {
268   XbmcCommons::ILogger* logger = CThread::GetLogger();
269   if (logger)
270     logger->Log(LOGERROR,"thread 0x%lx (%lu) got signal %d. calling OnException and terminating thread abnormally.", (long unsigned int)pthread_self(), (long unsigned int)pthread_self(), signum);
271   CThread* curThread = CThread::GetCurrentThread();
272   if (curThread)
273   {
274     curThread->StopThread(false);
275     curThread->OnException();
276     if( curThread->IsAutoDelete() )
277       delete curThread;
278   }
279   pthread_exit(NULL);
280 }
281
282 void CThread::SetSignalHandlers()
283 {
284   struct sigaction action;
285   action.sa_handler = term_handler;
286   sigemptyset (&action.sa_mask);
287   action.sa_flags = 0;
288   //sigaction (SIGABRT, &action, NULL);
289   //sigaction (SIGSEGV, &action, NULL);
290 }
291