00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <iostream>
00023 using namespace std;
00024
00025
00026 #include <QStringList>
00027 #include <QTimerEvent>
00028 #include <QRunnable>
00029 #include <QtGlobal>
00030 #include <QSet>
00031
00032
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
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