2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
22 #if defined(TARGET_ANDROID)
25 #include <sys/syscall.h>
27 #include <sys/resource.h>
30 #include <sys/param.h>
31 #if __FreeBSD_version < 900031
34 #include <pthread_np.h>
40 void CThread::SpawnThread(unsigned stacksize)
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);
48 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
49 if (pthread_create(&m_ThreadId, &attr, (void*(*)(void*))staticThread, this) != 0)
51 if (logger) logger->Log(LOGNOTICE, "%s - fatal error creating thread",__FUNCTION__);
53 pthread_attr_destroy(&attr);
56 void CThread::TermHandler() { }
58 void CThread::SetThreadInfo()
61 #if __FreeBSD_version < 900031
64 m_ThreadOpaque.LwpId = lwpid;
66 m_ThreadOpaque.LwpId = pthread_getthreadid_np();
68 #elif defined(TARGET_ANDROID)
69 m_ThreadOpaque.LwpId = gettid();
71 m_ThreadOpaque.LwpId = syscall(SYS_gettid);
75 #if(__MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 30200)
76 pthread_setname_np(m_ThreadName.c_str());
84 if (getrlimit(RLIMIT_NICE, &limit) == 0)
86 userMaxPrio = limit.rlim_cur - 20;
93 // if the user does not have an entry in limits.conf the following
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));
105 ThreadIdentifier CThread::GetCurrentThreadId()
107 return pthread_self();
110 bool CThread::IsCurrentThread(const ThreadIdentifier tid)
112 return pthread_equal(pthread_self(), tid);
115 int CThread::GetMinPriority(void)
117 // one level lower than application
121 int CThread::GetMaxPriority(void)
123 // one level higher than application
127 int CThread::GetNormalPriority(void)
129 // same level as application
133 bool CThread::SetPriority(const int iPriority)
135 bool bReturn = false;
137 // wait until thread is running, it needs to get its lwp id
140 CSingleLock lock(m_CriticalSection);
142 // get min prio for SCHED_RR
143 int minRR = GetMaxPriority() + 1;
147 else if (iPriority >= minRR)
148 bReturn = SetPrioritySched_RR(iPriority);
155 if (getrlimit(RLIMIT_NICE, &limit) == 0)
157 userMaxPrio = limit.rlim_cur - 20;
158 // is a user has no entry in limits.conf rlim_cur is zero
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();
172 // nice level of application
173 int appNice = getpriority(PRIO_PROCESS, getpid());
175 prio = prio > 0 ? appNice-1 : appNice+1;
177 if (setpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId, prio) == 0)
180 if (logger) logger->Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno));
187 int CThread::GetPriority()
191 // lwp id is valid after start signel has fired
194 CSingleLock lock(m_CriticalSection);
196 int appNice = getpriority(PRIO_PROCESS, getpid());
197 int prio = getpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId);
198 iReturn = appNice - prio;
203 bool CThread::WaitForThreadExit(unsigned int milliseconds)
205 bool bReturn = m_TermEvent.WaitMSec(milliseconds);
210 int64_t CThread::GetAbsoluteUsage()
212 CSingleLock lock(m_CriticalSection);
219 thread_basic_info threadInfo;
220 mach_msg_type_number_t threadInfoCount = THREAD_BASIC_INFO_COUNT;
222 kern_return_t ret = thread_info(pthread_mach_thread_np(m_ThreadId),
223 THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &threadInfoCount);
225 if (ret == KERN_SUCCESS)
228 time = ((int64_t)threadInfo.user_time.seconds * 10000000L) + threadInfo.user_time.microseconds*10L;
231 time += (((int64_t)threadInfo.system_time.seconds * 10000000L) + threadInfo.system_time.microseconds*10L);
236 if (pthread_getcpuclockid(m_ThreadId, &clock) == 0)
239 clock_gettime(clock, &tp);
240 time = (int64_t)tp.tv_sec * 10000000 + tp.tv_nsec/100;
247 float CThread::GetRelativeUsage()
249 unsigned int iTime = XbmcThreads::SystemClockMillis();
250 iTime *= 10000; // convert into 100ns tics
252 // only update every 1 second
253 if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage;
255 int64_t iUsage = GetAbsoluteUsage();
257 if (m_iLastUsage > 0 && m_iLastTime > 0)
258 m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime );
260 m_iLastUsage = iUsage;
266 void term_handler (int signum)
268 XbmcCommons::ILogger* logger = CThread::GetLogger();
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();
274 curThread->StopThread(false);
275 curThread->OnException();
276 if( curThread->IsAutoDelete() )
282 void CThread::SetSignalHandlers()
284 struct sigaction action;
285 action.sa_handler = term_handler;
286 sigemptyset (&action.sa_mask);
288 //sigaction (SIGABRT, &action, NULL);
289 //sigaction (SIGSEGV, &action, NULL);