Merge pull request #4857 from t-nelson/Gotham_13.2_backports
[vuplus_xbmc] / xbmc / threads / Thread.cpp
1 /*
2  *      Copyright (c) 2002 Frodo
3  *      Portions Copyright (c) by the authors of ffmpeg and xvid
4  *      Copyright (C) 2002-2013 Team XBMC
5  *      http://xbmc.org
6  *
7  *  This Program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2, or (at your option)
10  *  any later version.
11  *
12  *  This Program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with XBMC; see the file COPYING.  If not, see
19  *  <http://www.gnu.org/licenses/>.
20  *
21  */
22
23 #include "threads/SystemClock.h"
24 #include "Thread.h"
25 #include "threads/ThreadLocal.h"
26 #include "threads/SingleLock.h"
27 #include "commons/Exception.h"
28
29 #define __STDC_FORMAT_MACROS
30 #include <inttypes.h>
31
32 static XbmcThreads::ThreadLocal<CThread> currentThread;
33
34 XbmcCommons::ILogger* CThread::logger = NULL;
35
36 #include "threads/platform/ThreadImpl.cpp"
37
38 //////////////////////////////////////////////////////////////////////
39 // Construction/Destruction
40 //////////////////////////////////////////////////////////////////////
41
42 #define LOG if(logger) logger->Log
43
44 CThread::CThread(const char* ThreadName)
45 : m_StopEvent(true,true), m_TermEvent(true), m_StartEvent(true)
46 {
47   m_bStop = false;
48
49   m_bAutoDelete = false;
50   m_ThreadId = 0;
51   m_iLastTime = 0;
52   m_iLastUsage = 0;
53   m_fLastUsage = 0.0f;
54
55   m_pRunnable=NULL;
56
57   if (ThreadName)
58     m_ThreadName = ThreadName;
59 }
60
61 CThread::CThread(IRunnable* pRunnable, const char* ThreadName)
62 : m_StopEvent(true,true), m_TermEvent(true), m_StartEvent(true)
63 {
64   m_bStop = false;
65
66   m_bAutoDelete = false;
67   m_ThreadId = 0;
68   m_iLastTime = 0;
69   m_iLastUsage = 0;
70   m_fLastUsage = 0.0f;
71
72   m_pRunnable=pRunnable;
73
74   if (ThreadName)
75     m_ThreadName = ThreadName;
76 }
77
78 CThread::~CThread()
79 {
80   StopThread();
81 }
82
83 void CThread::Create(bool bAutoDelete, unsigned stacksize)
84 {
85   if (m_ThreadId != 0)
86   {
87     LOG(LOGERROR, "%s - fatal error creating thread- old thread id not null", __FUNCTION__);
88     exit(1);
89   }
90   m_iLastTime = XbmcThreads::SystemClockMillis() * 10000;
91   m_iLastUsage = 0;
92   m_fLastUsage = 0.0f;
93   m_bAutoDelete = bAutoDelete;
94   m_bStop = false;
95   m_StopEvent.Reset();
96   m_TermEvent.Reset();
97   m_StartEvent.Reset();
98
99   SpawnThread(stacksize);
100 }
101
102 bool CThread::IsRunning() const
103 {
104   return m_ThreadId ? true : false;
105 }
106
107 THREADFUNC CThread::staticThread(void* data)
108 {
109   CThread* pThread = (CThread*)(data);
110   std::string name;
111   ThreadIdentifier id;
112   bool autodelete;
113
114   if (!pThread) {
115     LOG(LOGERROR,"%s, sanity failed. thread is NULL.",__FUNCTION__);
116     return 1;
117   }
118
119   name = pThread->m_ThreadName;
120   id = pThread->m_ThreadId;
121   autodelete = pThread->m_bAutoDelete;
122
123   pThread->SetThreadInfo();
124
125   LOG(LOGNOTICE,"Thread %s start, auto delete: %s", name.c_str(), (autodelete ? "true" : "false"));
126
127   currentThread.set(pThread);
128   pThread->m_StartEvent.Set();
129
130   pThread->Action();
131
132   // lock during termination
133   CSingleLock lock(pThread->m_CriticalSection);
134
135   pThread->m_ThreadId = 0;
136   pThread->m_TermEvent.Set();
137   pThread->TermHandler();
138
139   lock.Leave();
140
141   if (autodelete)
142   {
143     LOG(LOGDEBUG,"Thread %s %"PRIu64" terminating (autodelete)", name.c_str(), (uint64_t)id);
144     delete pThread;
145     pThread = NULL;
146   }
147   else
148     LOG(LOGDEBUG,"Thread %s %"PRIu64" terminating", name.c_str(), (uint64_t)id);
149
150   return 0;
151 }
152
153 bool CThread::IsAutoDelete() const
154 {
155   return m_bAutoDelete;
156 }
157
158 void CThread::StopThread(bool bWait /*= true*/)
159 {
160   m_bStop = true;
161   m_StopEvent.Set();
162   CSingleLock lock(m_CriticalSection);
163   if (m_ThreadId && bWait)
164   {
165     lock.Leave();
166     WaitForThreadExit(0xFFFFFFFF);
167   }
168 }
169
170 ThreadIdentifier CThread::ThreadId() const
171 {
172   return m_ThreadId;
173 }
174
175 void CThread::Process()
176 {
177   if(m_pRunnable)
178     m_pRunnable->Run();
179 }
180
181 bool CThread::IsCurrentThread() const
182 {
183   return IsCurrentThread(ThreadId());
184 }
185
186 CThread* CThread::GetCurrentThread()
187 {
188   return currentThread.get();
189 }
190
191 void CThread::Sleep(unsigned int milliseconds)
192 {
193   if(milliseconds > 10 && IsCurrentThread())
194     m_StopEvent.WaitMSec(milliseconds);
195   else
196     XbmcThreads::ThreadSleep(milliseconds);
197 }
198
199 void CThread::Action()
200 {
201   try
202   {
203     OnStartup();
204   }
205   catch (const XbmcCommons::UncheckedException &e)
206   {
207     e.LogThrowMessage("OnStartup");
208     if (IsAutoDelete())
209       return;
210   }
211   catch (...)
212   {
213     LOG(LOGERROR, "%s - thread %s, Unhandled exception caught in thread startup, aborting. auto delete: %d", __FUNCTION__, m_ThreadName.c_str(), IsAutoDelete());
214     if (IsAutoDelete())
215       return;
216   }
217
218   try
219   {
220     Process();
221   }
222   catch (const XbmcCommons::UncheckedException &e)
223   {
224     e.LogThrowMessage("Process");
225   }
226   catch (...)
227   {
228     LOG(LOGERROR, "%s - thread %s, Unhandled exception caught in thread process, aborting. auto delete: %d", __FUNCTION__, m_ThreadName.c_str(), IsAutoDelete());
229   }
230
231   try
232   {
233     OnExit();
234   }
235   catch (const XbmcCommons::UncheckedException &e)
236   {
237     e.LogThrowMessage("OnExit");
238   }
239   catch (...)
240   {
241     LOG(LOGERROR, "%s - thread %s, Unhandled exception caught in thread OnExit, aborting. auto delete: %d", __FUNCTION__, m_ThreadName.c_str(), IsAutoDelete());
242   }
243 }
244