|
MythTV
0.26-pre
|
00001 /* -*- Mode: c++ -*- 00002 * 00003 * Class MThread 00004 * 00005 * Copyright (C) Daniel Kristjansson 2011 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 */ 00021 00022 #include <iostream> 00023 using namespace std; 00024 00025 // Qt headers 00026 #include <QStringList> 00027 #include <QTimerEvent> 00028 #include <QRunnable> 00029 #include <QtGlobal> 00030 #include <QSet> 00031 00032 // MythTV headers 00033 #include "mythlogging.h" 00034 #include "mythdbcon.h" 00035 #include "mthread.h" 00036 #include "mythtimer.h" 00037 #include "logging.h" 00038 #include "mythdb.h" 00039 00040 bool is_current_thread(MThread *thread) 00041 { 00042 if (!thread) 00043 return false; 00044 return QThread::currentThread() == thread->qthread(); 00045 } 00046 00047 bool is_current_thread(QThread *thread) 00048 { 00049 if (!thread) 00050 return false; 00051 return QThread::currentThread() == thread; 00052 } 00053 00054 bool is_current_thread(MThread &thread) 00055 { 00056 return QThread::currentThread() == thread.qthread(); 00057 } 00058 00059 class DBPurgeHandler : public QObject 00060 { 00061 public: 00062 DBPurgeHandler() 00063 { 00064 purgeTimer = startTimer(5 * 60000); 00065 } 00066 void timerEvent(QTimerEvent *event) 00067 { 00068 if (event->timerId() == purgeTimer) 00069 GetMythDB()->GetDBManager()->PurgeIdleConnections(false); 00070 } 00071 int purgeTimer; 00072 }; 00073 00074 class MThreadInternal : public QThread 00075 { 00076 public: 00077 MThreadInternal(MThread &parent) : m_parent(parent) {} 00078 virtual void run(void) { m_parent.run(); } 00079 00080 void QThreadRun(void) { QThread::run(); } 00081 int exec(void) 00082 { 00083 DBPurgeHandler ph(); 00084 return QThread::exec(); 00085 } 00086 00087 static void SetTerminationEnabled(bool enabled = true) 00088 { QThread::setTerminationEnabled(enabled); } 00089 00090 static void Sleep(unsigned long time) { QThread::sleep(time); } 00091 static void MSleep(unsigned long time) { QThread::msleep(time); } 00092 static void USleep(unsigned long time) { QThread::usleep(time); } 00093 00094 private: 00095 MThread &m_parent; 00096 }; 00097 00098 static QMutex s_all_threads_lock; 00099 static QSet<MThread*> s_all_threads; 00100 00101 MThread::MThread(const QString &objectName) : 00102 m_thread(new MThreadInternal(*this)), m_runnable(NULL), 00103 m_prolog_executed(true), m_epilog_executed(true) 00104 { 00105 m_thread->setObjectName(objectName); 00106 QMutexLocker locker(&s_all_threads_lock); 00107 s_all_threads.insert(this); 00108 } 00109 00110 MThread::MThread(const QString &objectName, QRunnable *runnable) : 00111 m_thread(new MThreadInternal(*this)), m_runnable(runnable), 00112 m_prolog_executed(false), m_epilog_executed(false) 00113 { 00114 m_thread->setObjectName(objectName); 00115 QMutexLocker locker(&s_all_threads_lock); 00116 s_all_threads.insert(this); 00117 } 00118 00119 MThread::~MThread() 00120 { 00121 if (!m_prolog_executed) 00122 { 00123 LOG(VB_GENERAL, LOG_CRIT, "MThread prolog was never run!"); 00124 } 00125 if (!m_epilog_executed) 00126 { 00127 LOG(VB_GENERAL, LOG_CRIT, "MThread epilog was never run!"); 00128 } 00129 if (m_thread->isRunning()) 00130 { 00131 LOG(VB_GENERAL, LOG_CRIT, 00132 "MThread destructor called while thread still running!"); 00133 m_thread->wait(); 00134 } 00135 00136 { 00137 QMutexLocker locker(&s_all_threads_lock); 00138 s_all_threads.remove(this); 00139 } 00140 00141 delete m_thread; 00142 m_thread = NULL; 00143 } 00144 00145 void MThread::Cleanup(void) 00146 { 00147 QMutexLocker locker(&s_all_threads_lock); 00148 QSet<MThread*> badGuys; 00149 QSet<MThread*>::const_iterator it; 00150 for (it = s_all_threads.begin(); it != s_all_threads.end(); ++it) 00151 { 00152 if ((*it)->isRunning()) 00153 { 00154 badGuys.insert(*it); 00155 (*it)->exit(1); 00156 } 00157 } 00158 00159 if (badGuys.empty()) 00160 return; 00161 00162 // logging has been stopped so we need to use iostream... 00163 cerr<<"Error: Not all threads were shut down properly: "<<endl; 00164 for (it = badGuys.begin(); it != badGuys.end(); ++it) 00165 { 00166 cerr<<"Thread "<<qPrintable((*it)->objectName()) 00167 <<" is still running"<<endl; 00168 } 00169 cerr<<endl; 00170 00171 static const int kTimeout = 5000; 00172 MythTimer t; 00173 t.start(); 00174 for (it = badGuys.begin(); 00175 it != badGuys.end() && t.elapsed() < kTimeout; ++it) 00176 { 00177 int left = kTimeout - t.elapsed(); 00178 if (left > 0) 00179 (*it)->wait(left); 00180 } 00181 } 00182 00183 void MThread::GetAllThreadNames(QStringList &list) 00184 { 00185 QMutexLocker locker(&s_all_threads_lock); 00186 QSet<MThread*>::const_iterator it; 00187 for (it = s_all_threads.begin(); it != s_all_threads.end(); ++it) 00188 list.push_back((*it)->objectName()); 00189 } 00190 00191 void MThread::GetAllRunningThreadNames(QStringList &list) 00192 { 00193 QMutexLocker locker(&s_all_threads_lock); 00194 QSet<MThread*>::const_iterator it; 00195 for (it = s_all_threads.begin(); it != s_all_threads.end(); ++it) 00196 { 00197 if ((*it)->isRunning()) 00198 list.push_back((*it)->objectName()); 00199 } 00200 } 00201 00202 void MThread::RunProlog(void) 00203 { 00204 if (QThread::currentThread() != m_thread) 00205 { 00206 LOG(VB_GENERAL, LOG_CRIT, 00207 "RunProlog can only be executed in the run() method of a thread."); 00208 return; 00209 } 00210 setTerminationEnabled(false); 00211 ThreadSetup(m_thread->objectName()); 00212 m_prolog_executed = true; 00213 } 00214 00215 void MThread::RunEpilog(void) 00216 { 00217 if (QThread::currentThread() != m_thread) 00218 { 00219 LOG(VB_GENERAL, LOG_CRIT, 00220 "RunEpilog can only be executed in the run() method of a thread."); 00221 return; 00222 } 00223 ThreadCleanup(); 00224 m_epilog_executed = true; 00225 } 00226 00227 void MThread::ThreadSetup(const QString &name) 00228 { 00229 loggingRegisterThread(name); 00230 qsrand(QDateTime::currentDateTime().toTime_t() ^ 00231 QTime::currentTime().msec()); 00232 } 00233 00234 void MThread::ThreadCleanup(void) 00235 { 00236 if (GetMythDB() && GetMythDB()->GetDBManager()) 00237 GetMythDB()->GetDBManager()->CloseDatabases(); 00238 loggingDeregisterThread(); 00239 } 00240 00241 QThread *MThread::qthread(void) 00242 { 00243 return m_thread; 00244 } 00245 00246 void MThread::setObjectName(const QString &name) 00247 { 00248 m_thread->setObjectName(name); 00249 } 00250 00251 QString MThread::objectName(void) const 00252 { 00253 return m_thread->objectName(); 00254 } 00255 00256 void MThread::setPriority(QThread::Priority priority) 00257 { 00258 m_thread->setPriority(priority); 00259 } 00260 00261 QThread::Priority MThread::priority(void) const 00262 { 00263 return m_thread->priority(); 00264 } 00265 00266 bool MThread::isFinished(void) const 00267 { 00268 return m_thread->isFinished(); 00269 } 00270 00271 bool MThread::isRunning(void) const 00272 { 00273 return m_thread->isRunning(); 00274 } 00275 00276 void MThread::setStackSize(uint stackSize) 00277 { 00278 m_thread->setStackSize(stackSize); 00279 } 00280 00281 uint MThread::stackSize(void) const 00282 { 00283 return m_thread->stackSize(); 00284 } 00285 00286 void MThread::exit(int retcode) 00287 { 00288 m_thread->exit(retcode); 00289 } 00290 00291 void MThread::start(QThread::Priority p) 00292 { 00293 m_prolog_executed = false; 00294 m_epilog_executed = false; 00295 m_thread->start(p); 00296 } 00297 00298 void MThread::terminate(void) 00299 { 00300 m_thread->terminate(); 00301 } 00302 00303 void MThread::quit(void) 00304 { 00305 m_thread->quit(); 00306 } 00307 00308 bool MThread::wait(unsigned long time) 00309 { 00310 if (m_thread->isRunning()) 00311 return m_thread->wait(time); 00312 return true; 00313 } 00314 00315 void MThread::run(void) 00316 { 00317 RunProlog(); 00318 if (m_runnable) 00319 m_runnable->run(); 00320 else 00321 m_thread->QThreadRun(); 00322 RunEpilog(); 00323 } 00324 00325 int MThread::exec(void) 00326 { 00327 return m_thread->exec(); 00328 } 00329 00330 void MThread::setTerminationEnabled(bool enabled) 00331 { 00332 MThreadInternal::SetTerminationEnabled(enabled); 00333 } 00334 00335 void MThread::sleep(unsigned long time) 00336 { 00337 MThreadInternal::Sleep(time); 00338 } 00339 00340 void MThread::msleep(unsigned long time) 00341 { 00342 MThreadInternal::MSleep(time); 00343 } 00344 00345 void MThread::usleep(unsigned long time) 00346 { 00347 MThreadInternal::USleep(time); 00348 } 00349 00350 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1