From c1d6a3d0de79ad588165200cdec3fd4f68cc72a9 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 2 Aug 2011 18:38:10 +0100 Subject: [PATCH 01/49] Fix a couple of dos line endings in MNV html. --- .../internetcontent/nv_python_libs/configs/HTML/cinemarv.html | 3 ++- .../internetcontent/nv_python_libs/configs/HTML/thewb.html | 3 ++- .../internetcontent/nv_python_libs/configs/HTML/tributeca.html | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mythtv/programs/scripts/internetcontent/nv_python_libs/configs/HTML/cinemarv.html b/mythtv/programs/scripts/internetcontent/nv_python_libs/configs/HTML/cinemarv.html index 15d6416957f..acfe7d0fbec 100644 --- a/mythtv/programs/scripts/internetcontent/nv_python_libs/configs/HTML/cinemarv.html +++ b/mythtv/programs/scripts/internetcontent/nv_python_libs/configs/HTML/cinemarv.html @@ -1,7 +1,8 @@ - + + + + + + + + + + + + 200,100 + + + + 200,154 + + + + + + 200,312 + + + + + + + diff --git a/mythplugins/mythgallery/theme/default/gallery-ui.xml b/mythplugins/mythgallery/theme/default/gallery-ui.xml index e515e773054..7ab939af3f5 100644 --- a/mythplugins/mythgallery/theme/default/gallery-ui.xml +++ b/mythplugins/mythgallery/theme/default/gallery-ui.xml @@ -112,4 +112,67 @@ + + + + + + + + + + + + + + + + + 200,100 + + + + 200,154 + + + + + + 200,312 + + + + + + + From 3f5f6b9a775499b2b2024362b716029235eb97d9 Mon Sep 17 00:00:00 2001 From: Gavin Hurlbut Date: Wed, 27 Jul 2011 00:40:16 -0700 Subject: [PATCH 14/49] Rework the gallery filter/sort patch So this would actually compile, and meet our coding style and standards, I needed to rework parts of the code. This should all essentially be cosmetic and not affect the actual functionality beneath. Fixes #9880 --- .../mythgallery/mythgallery/galleryfilter.cpp | 74 +++++----- .../mythgallery/mythgallery/galleryfilter.h | 42 +++--- .../mythgallery/galleryfilterdlg.cpp | 134 ++++++++---------- .../mythgallery/galleryfilterdlg.h | 25 ++-- .../mythgallery/gallerysettings.cpp | 31 ++-- .../mythgallery/mythgallery/galleryutil.cpp | 24 ++-- .../mythgallery/mythgallery/glsingleview.cpp | 1 - .../mythgallery/mythgallery/iconview.cpp | 11 +- .../mythgallery/mythgallery/singleview.cpp | 1 - 9 files changed, 167 insertions(+), 176 deletions(-) diff --git a/mythplugins/mythgallery/mythgallery/galleryfilter.cpp b/mythplugins/mythgallery/mythgallery/galleryfilter.cpp index 8413914917c..26bbea99cbc 100644 --- a/mythplugins/mythgallery/mythgallery/galleryfilter.cpp +++ b/mythplugins/mythgallery/mythgallery/galleryfilter.cpp @@ -1,23 +1,17 @@ - #include -#include - -#include "galleryfilter.h" +#include -#include - -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "config.h" #include "galleryfilter.h" #include "galleryutil.h" -#define LOC QString("GalleryFilter:") -#define LOC_ERR QString("GalleryFilter, Error:") - GalleryFilter::GalleryFilter(bool loaddefaultsettings) : m_dirFilter(""), m_typeFilter(kTypeFilterAll), m_sort(kSortOrderUnsorted), @@ -27,8 +21,10 @@ GalleryFilter::GalleryFilter(bool loaddefaultsettings) : if (loaddefaultsettings) { m_dirFilter = gCoreContext->GetSetting("GalleryFilterDirectory", ""); - m_typeFilter = gCoreContext->GetNumSetting("GalleryFilterType", kTypeFilterAll); - m_sort = gCoreContext->GetNumSetting("GallerySortOrder", kSortOrderUnsorted); + m_typeFilter = gCoreContext->GetNumSetting("GalleryFilterType", + kTypeFilterAll); + m_sort = gCoreContext->GetNumSetting("GallerySortOrder", + kSortOrderUnsorted); } } @@ -38,8 +34,7 @@ GalleryFilter::GalleryFilter(const GalleryFilter &gfs) : *this = gfs; } -GalleryFilter & -GalleryFilter::operator=(const GalleryFilter &gfs) +GalleryFilter & GalleryFilter::operator=(const GalleryFilter &gfs) { if (m_dirFilter != gfs.m_dirFilter) { @@ -85,50 +80,59 @@ bool GalleryFilter::TestFilter(const QString& dir, const GalleryFilter& flt, return false; if (!flt.getDirFilter().isEmpty()) - { splitFD = flt.getDirFilter().split(":"); - } - - for (QFileInfoList::const_iterator it = list.begin(); it != list.end(); it++) + for (QFileInfoList::const_iterator it = list.begin(); + it != list.end(); it++) { fi = &(*it); - if (fi->fileName() == "." - || fi->fileName() == "..") - { + if (fi->fileName() == "." || fi->fileName() == "..") continue; - } // remove these already-resized pictures. if ((fi->fileName().indexOf(".thumb.") > 0) || (fi->fileName().indexOf(".sized.") > 0) || (fi->fileName().indexOf(".highlight.") > 0)) - { continue; - } // skip filtered directory if (fi->isDir()) { if (!splitFD.filter(fi->fileName(), Qt::CaseInsensitive).isEmpty()) - { continue; - } + // add directory (*dirCount)++; - GalleryFilter::TestFilter(QDir::cleanPath(fi->absoluteFilePath()), flt, - dirCount, imageCount, movieCount); + GalleryFilter::TestFilter(QDir::cleanPath(fi->absoluteFilePath()), + flt, dirCount, imageCount, movieCount); } else { - if (GalleryUtil::IsImage(fi->absoluteFilePath()) - && flt.getTypeFilter() != kTypeFilterMoviesOnly) + if (GalleryUtil::IsImage(fi->absoluteFilePath()) && + flt.getTypeFilter() != kTypeFilterMoviesOnly) (*imageCount)++; - else if (GalleryUtil::IsMovie(fi->absoluteFilePath()) - && flt.getTypeFilter() != kTypeFilterImagesOnly) + else if (GalleryUtil::IsMovie(fi->absoluteFilePath()) && + flt.getTypeFilter() != kTypeFilterImagesOnly) (*movieCount)++; } } return true; } + + +void GalleryFilter::dumpFilter(QString src) +{ + LOG(VB_GENERAL, LOG_DEBUG, QString("Dumping GalleryFilter from: %1") + .arg(src)); + LOG(VB_GENERAL, LOG_DEBUG, QString("directory fiter: %1") + .arg(m_dirFilter)); + LOG(VB_GENERAL, LOG_DEBUG, QString("type filter: %1") + .arg(m_typeFilter)); + LOG(VB_GENERAL, LOG_DEBUG, QString("sort options: %1") + .arg(m_sort)); +} + +/* + * vim:ts=4:sw=4:ai:et:si:sts=4 + */ diff --git a/mythplugins/mythgallery/mythgallery/galleryfilter.h b/mythplugins/mythgallery/mythgallery/galleryfilter.h index fb71a5128e8..09ef563bb36 100644 --- a/mythplugins/mythgallery/mythgallery/galleryfilter.h +++ b/mythplugins/mythgallery/mythgallery/galleryfilter.h @@ -4,19 +4,22 @@ // qt #include -#include -#include +#include enum SortOrder { - kSortOrderUnsorted = QDir::Unsorted, - kSortOrderNameAsc = QDir::Name + QDir::DirsFirst + QDir::IgnoreCase, - kSortOrderNameDesc = QDir::Name + QDir::Reversed + QDir::DirsFirst + QDir::IgnoreCase, - kSortOrderModTimeAsc = QDir::Time + QDir::DirsFirst + QDir::IgnoreCase, - kSortOrderModTimeDesc = QDir::Time + QDir::Reversed + QDir::DirsFirst + QDir::IgnoreCase, - kSortOrderExtAsc = QDir::Size + QDir::DirsFirst + QDir::IgnoreCase, - kSortOrderExtDesc = QDir::Size + QDir::Reversed + QDir::DirsFirst + QDir::IgnoreCase, - kSortOrderSizeAsc = QDir::Type + QDir::DirsFirst + QDir::IgnoreCase, - kSortOrderSizeDesc = QDir::Type + QDir::Reversed + QDir::DirsFirst + QDir::IgnoreCase + kSortOrderUnsorted = QDir::Unsorted, + kSortOrderNameAsc = QDir::Name + QDir::DirsFirst + QDir::IgnoreCase, + kSortOrderNameDesc = QDir::Name + QDir::DirsFirst + QDir::IgnoreCase + + QDir::Reversed, + kSortOrderModTimeAsc = QDir::Time + QDir::DirsFirst + QDir::IgnoreCase, + kSortOrderModTimeDesc = QDir::Time + QDir::DirsFirst + QDir::IgnoreCase + + QDir::Reversed, + kSortOrderExtAsc = QDir::Size + QDir::DirsFirst + QDir::IgnoreCase, + kSortOrderExtDesc = QDir::Size + QDir::DirsFirst + QDir::IgnoreCase + + QDir::Reversed, + kSortOrderSizeAsc = QDir::Type + QDir::DirsFirst + QDir::IgnoreCase, + kSortOrderSizeDesc = QDir::Type + QDir::DirsFirst + QDir::IgnoreCase + + QDir::Reversed }; Q_DECLARE_METATYPE(SortOrder) @@ -66,18 +69,7 @@ class GalleryFilter m_changed_state = 0; return ret; } - void dumpFilter(QString src) - { - VERBOSE(VB_EXTRA, QString("Dumping GalleryFilter from: %1") - .arg(src)); - VERBOSE(VB_EXTRA, QString("directory fiter: %1") - .arg(m_dirFilter)); - VERBOSE(VB_EXTRA, QString("type filter: %1") - .arg(m_typeFilter)); - VERBOSE(VB_EXTRA, QString("sort options: %1") - .arg(m_sort)); - } - + void dumpFilter(QString src); private: QString m_dirFilter; @@ -88,3 +80,7 @@ class GalleryFilter }; #endif /* GALLERYFILTER_H */ + +/* + * vim:ts=4:sw=4:ai:et:si:sts=4 + */ diff --git a/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp b/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp index e51c4b36637..4d66cf7a103 100644 --- a/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp +++ b/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp @@ -15,41 +15,25 @@ * * ============================================================ */ -#include "galleryfilter.h" - using namespace std; // Qt headers #include #include -//#include -//#include #include -//#include // MythTV headers -#include -#include -#include -//#include -#include -#include -//#include -//#include -//#include +#include +#include +#include +#include +#include // MythGallery headers -//#include "galleryutil.h" -//#include "gallerysettings.h" #include "galleryfilterdlg.h" #include "galleryfilter.h" -//#include "thumbgenerator.h" -//#include "iconview.h" -//#include "singleview.h" -//#include "glsingleview.h" #define LOC QString("GalleryFilterDlg:") -#define LOC_ERR QString("GalleryFilterDlg, Error:") class FilterScanThread : public QThread { @@ -67,7 +51,8 @@ class FilterScanThread : public QThread }; FilterScanThread::FilterScanThread(const QString& dir, const GalleryFilter& flt, - int *dirCount, int *imageCount, int *movieCount) + int *dirCount, int *imageCount, + int *movieCount) { m_dir = dir; m_filter = flt; @@ -78,10 +63,14 @@ FilterScanThread::FilterScanThread(const QString& dir, const GalleryFilter& flt, void FilterScanThread::run() { - GalleryFilter::TestFilter(m_dir, m_filter, m_dirCount, m_imgCount, m_movCount); + threadRegister("FilterScan"); + GalleryFilter::TestFilter(m_dir, m_filter, m_dirCount, m_imgCount, + m_movCount); + threadDeregister(); } -GalleryFilterDialog::GalleryFilterDialog(MythScreenStack *parent, QString name, GalleryFilter *filter) +GalleryFilterDialog::GalleryFilterDialog(MythScreenStack *parent, QString name, + GalleryFilter *filter) : MythScreenType(parent, name) { m_settingsOriginal = filter; @@ -115,7 +104,7 @@ bool GalleryFilterDialog::Create() if (err) { - VERBOSE(VB_IMPORTANT, "Cannot load screen 'filter'"); + LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'filter'"); return false; } @@ -157,19 +146,24 @@ void GalleryFilterDialog::fillWidgets() kSortOrderUnsorted); new MythUIButtonListItem(m_sortList, QObject::tr("Name (A-Z alpha)"), kSortOrderNameAsc); - new MythUIButtonListItem(m_sortList, QObject::tr("Reverse Name (Z-A alpha)"), + new MythUIButtonListItem(m_sortList, + QObject::tr("Reverse Name (Z-A alpha)"), kSortOrderNameDesc); new MythUIButtonListItem(m_sortList, QObject::tr("Mod Time (oldest first)"), kSortOrderModTimeAsc); - new MythUIButtonListItem(m_sortList, QObject::tr("Reverse Mod Time (most recent first)"), + new MythUIButtonListItem(m_sortList, + QObject::tr("Reverse Mod Time (newest first)"), kSortOrderModTimeDesc); new MythUIButtonListItem(m_sortList, QObject::tr("Extension (A-Z alpha)"), kSortOrderExtAsc); - new MythUIButtonListItem(m_sortList, QObject::tr("Reverse Extension (Z-A alpha)"), + new MythUIButtonListItem(m_sortList, + QObject::tr("Reverse Extension (Z-A alpha)"), kSortOrderExtDesc); - new MythUIButtonListItem(m_sortList, QObject::tr("Filesize (smallest first)"), + new MythUIButtonListItem(m_sortList, + QObject::tr("Filesize (smallest first)"), kSortOrderSizeAsc); - new MythUIButtonListItem(m_sortList, QObject::tr("Reverse Filesize (largest first)"), + new MythUIButtonListItem(m_sortList, + QObject::tr("Reverse Filesize (largest first)"), kSortOrderSizeDesc); m_sortList->SetValueByData(m_settingsTemp->getSort()); } @@ -192,59 +186,49 @@ void GalleryFilterDialog::updateFilter() m_numImagesText->SetText("-- scanning current filter --"); - FilterScanThread *fltScan = new FilterScanThread(m_photoDir, *m_settingsTemp, &dir_count, &img_count, &mov_count); - fltScan->start(); + FilterScanThread fltScan(m_photoDir, *m_settingsTemp, &dir_count, + &img_count, &mov_count); + fltScan.start(); - while (!fltScan->isFinished()) + while (!fltScan.isFinished()) { usleep(500); qApp->processEvents(); } + m_scanning = false; + if (dir_count + img_count + mov_count == 0) - { m_numImagesText->SetText(QString(tr("No files / directories found"))); - } - else + else if (dir_count > 0) { - if (dir_count > 0) - { - if (img_count + mov_count == 0) - m_numImagesText->SetText(QString(tr("Filter result : %1 directories found but no files")) - .arg(dir_count)); - else { - if (img_count == 0) - m_numImagesText->SetText(QString(tr("Filter result : %1 directories, %2 movie(s) found")) - .arg(dir_count) - .arg(mov_count)); - else if (mov_count == 0) - m_numImagesText->SetText(QString(tr("Filter result : %1 directories, %2 image(s) found")) - .arg(dir_count) - .arg(img_count)); - else - m_numImagesText->SetText(QString(tr("Filter result : %1 directories, %2 image(s) and %3 movie(s) found")) - .arg(dir_count) - .arg(img_count) - .arg(mov_count)); - } - - } + if (img_count + mov_count == 0) + m_numImagesText->SetText(QString(tr( + "Filter result : %1 directories found but no files")) + .arg(dir_count)); + else if (img_count == 0) + m_numImagesText->SetText(QString(tr( + "Filter result : %1 directories, %2 movie(s) found")) + .arg(dir_count) .arg(mov_count)); + else if (mov_count == 0) + m_numImagesText->SetText(QString(tr( + "Filter result : %1 directories, %2 image(s) found")) + .arg(dir_count) .arg(img_count)); else - { - if (img_count > 0 && mov_count > 0) - m_numImagesText->SetText(QString(tr("Filter result : %1 image(s) and %2 movie(s) found")) - .arg(img_count) - .arg(mov_count)); - else if (mov_count == 0) - m_numImagesText->SetText(QString(tr("Filter result : %1 image(s) found")) - .arg(img_count)); - else - m_numImagesText->SetText(QString(tr("Filter result : %1 movie(s) found")) - .arg(mov_count)); - } + m_numImagesText->SetText(QString(tr( + "Filter result : %1 directories, %2 image(s) and %3 movie(s) " + "found")) .arg(dir_count) .arg(img_count) .arg(mov_count)); } - - m_scanning = false; + else if (img_count > 0 && mov_count > 0) + m_numImagesText->SetText(QString(tr( + "Filter result : %1 image(s) and %2 movie(s) found")) + .arg(img_count) .arg(mov_count)); + else if (mov_count == 0) + m_numImagesText->SetText(QString(tr( + "Filter result : %1 image(s) found")) .arg(img_count)); + else + m_numImagesText->SetText(QString(tr( + "Filter result : %1 movie(s) found")) .arg(mov_count)); } void GalleryFilterDialog::setDirFilter(void) @@ -276,9 +260,11 @@ void GalleryFilterDialog::saveAndExit() m_settingsOriginal->dumpFilter("GalleryFilterDialog::saveAndExit()"); if (m_settingsOriginal->getChangedState() > 0) - { emit filterChanged(); - } Close(); } + +/* + * vim:ts=4:sw=4:ai:et:si:sts=4 + */ diff --git a/mythplugins/mythgallery/mythgallery/galleryfilterdlg.h b/mythplugins/mythgallery/mythgallery/galleryfilterdlg.h index 9e91f700c19..a0d3d69a463 100644 --- a/mythplugins/mythgallery/mythgallery/galleryfilterdlg.h +++ b/mythplugins/mythgallery/mythgallery/galleryfilterdlg.h @@ -19,17 +19,14 @@ #ifndef GALLERYFILTERDLG_H #define GALLERYFILTERDLG_H -// Qt headers -#include - // MythTV headers -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include "galleryfilter.h" @@ -38,11 +35,11 @@ using namespace std; class GalleryFilter; class GalleryFilterDialog : public MythScreenType { - Q_OBJECT public: - GalleryFilterDialog(MythScreenStack *parent, QString name, GalleryFilter *filter); + GalleryFilterDialog(MythScreenStack *parent, QString name, + GalleryFilter *filter); ~GalleryFilterDialog(); bool Create(); @@ -76,3 +73,7 @@ class GalleryFilterDialog : public MythScreenType }; #endif /* GALLERYFILTERDLG_H */ + +/* + * vim:ts=4:sw=4:ai:et:si:sts=4 + */ diff --git a/mythplugins/mythgallery/mythgallery/gallerysettings.cpp b/mythplugins/mythgallery/mythgallery/gallerysettings.cpp index ada8652d653..bad8c278ba8 100644 --- a/mythplugins/mythgallery/mythgallery/gallerysettings.cpp +++ b/mythplugins/mythgallery/mythgallery/gallerysettings.cpp @@ -17,8 +17,9 @@ static HostLineEdit *MythGalleryFilter() HostLineEdit *gc = new HostLineEdit("GalleryFilterDirectory"); gc->setLabel(QObject::tr("Directory filter")); gc->setValue(""); - gc->setHelpText(QObject::tr("Enter direcory names to be excluded in browser. " - "(multiple entries delimited with ':')")); + gc->setHelpText(QObject::tr("Enter direcory names to be excluded in " + "browser. (multiple entries delimited with " + "':')")); return gc; }; @@ -33,6 +34,7 @@ static HostComboBox *MythGalleryFilterType() "thumbnails.")); return gc; }; + static HostLineEdit *MythGalleryDir() { HostLineEdit *gc = new HostLineEdit("GalleryDir"); @@ -60,15 +62,22 @@ static HostComboBox *MythGallerySortOrder() { HostComboBox *gc = new HostComboBox("GallerySortOrder"); gc->setLabel(QObject::tr("Sort order when browsing")); - gc->addSelection("Unsorted", QString::number(QDir::Unsorted)); - gc->addSelection("Name (A-Z alpha)", QString::number(QDir::Name | QDir::DirsFirst | QDir::IgnoreCase)); - gc->addSelection("Reverse Name (Z-A alpha)", QString::number(QDir::Name | QDir::DirsFirst | QDir::IgnoreCase | QDir::Reversed)); - gc->addSelection("Mod Time (earliest first)", QString::number(QDir::Time | QDir::DirsFirst | QDir::IgnoreCase | QDir::Reversed)); - gc->addSelection("Reverse Mod Time (most recent first)", QString::number(QDir::Time | QDir::DirsFirst | QDir::IgnoreCase)); - gc->addSelection("Extension (A-Z alpha)", QString::number(QDir::Size | QDir::DirsFirst | QDir::IgnoreCase)); - gc->addSelection("Reverse Extension (Z-A alpha", QString::number(QDir::Size | QDir::Reversed | QDir::DirsFirst | QDir::IgnoreCase)); - gc->addSelection("Filesize (smallest first)", QString::number(QDir::Type | QDir::DirsFirst | QDir::IgnoreCase)); - gc->addSelection("Reverse Filesize (largest first)", QString::number(QDir::Type | QDir::Reversed | QDir::DirsFirst | QDir::IgnoreCase)); + gc->addSelection("Unsorted", QString::number(kSortOrderUnsorted)); + gc->addSelection("Name (A-Z alpha)", QString::number(kSortOrderNameAsc)); + gc->addSelection("Reverse Name (Z-A alpha)", + QString::number(kSortOrderNameDesc)); + gc->addSelection("Mod Time (oldest first)", + QString::number(kSortOrderModTimeAsc)); + gc->addSelection("Reverse Mod Time (newest first)", + QString::number(kSortOrderModTimeDesc)); + gc->addSelection("Extension (A-Z alpha)", + QString::number(kSortOrderExtAsc)); + gc->addSelection("Reverse Extension (Z-A alpha)", + QString::number(kSortOrderExtDesc)); + gc->addSelection("Filesize (smallest first)", + QString::number(kSortOrderSizeAsc)); + gc->addSelection("Reverse Filesize (largest first)", + QString::number(kSortOrderSizeDesc)); gc->setHelpText(QObject::tr("This is the sort order for the displayed " "picture thumbnails.")); return gc; diff --git a/mythplugins/mythgallery/mythgallery/galleryutil.cpp b/mythplugins/mythgallery/mythgallery/galleryutil.cpp index cd0e5bfa11e..1d57d6f3799 100644 --- a/mythplugins/mythgallery/mythgallery/galleryutil.cpp +++ b/mythplugins/mythgallery/mythgallery/galleryutil.cpp @@ -43,7 +43,6 @@ #endif // EXIF_SUPPORT #define LOC QString("GalleryUtil:") -#define LOC_ERR QString("GalleryUtil, Error:") static QFileInfo MakeUnique(const QFileInfo &dest); static QFileInfo MakeUniqueDirectory(const QFileInfo &dest); @@ -263,28 +262,25 @@ bool GalleryUtil::LoadDirectory(ThumbList& itemList, const QString& dir, continue; // skip filtered directory - if (fi->isDir() && !splitFD.filter(fi->fileName(), Qt::CaseInsensitive).isEmpty()) - { + if (fi->isDir() && + !splitFD.filter(fi->fileName(), Qt::CaseInsensitive).isEmpty()) continue; - } if (fi->isDir() && recurse) { - LoadDirectory( - itemList, QDir::cleanPath(fi->absoluteFilePath()), - flt, true, itemHash, thumbGen); + LoadDirectory(itemList, QDir::cleanPath(fi->absoluteFilePath()), + flt, true, itemHash, thumbGen); } else { - if ((GalleryUtil::IsImage(fi->absoluteFilePath()) - && flt.getTypeFilter() == kTypeFilterMoviesOnly) - || (GalleryUtil::IsMovie(fi->absoluteFilePath()) - && flt.getTypeFilter() == kTypeFilterImagesOnly)) + if ((GalleryUtil::IsImage(fi->absoluteFilePath()) && + flt.getTypeFilter() == kTypeFilterMoviesOnly) || + (GalleryUtil::IsMovie(fi->absoluteFilePath()) && + flt.getTypeFilter() == kTypeFilterImagesOnly)) continue; - ThumbItem *item = new ThumbItem( - fi->fileName(), - QDir::cleanPath(fi->absoluteFilePath()), fi->isDir()); + ThumbItem *item = new ThumbItem(fi->fileName(), + QDir::cleanPath(fi->absoluteFilePath()), fi->isDir()); itemList.append(item); diff --git a/mythplugins/mythgallery/mythgallery/glsingleview.cpp b/mythplugins/mythgallery/mythgallery/glsingleview.cpp index 3146d2c5760..eeb8a86b984 100644 --- a/mythplugins/mythgallery/mythgallery/glsingleview.cpp +++ b/mythplugins/mythgallery/mythgallery/glsingleview.cpp @@ -45,7 +45,6 @@ using namespace std; #include "galleryutil.h" #define LOC QString("GLView: ") -#define LOC_ERR QString("GLView, Error: ") GLSDialog::GLSDialog(const ThumbList& itemList, int *pos, int slideShow, int sortOrder, diff --git a/mythplugins/mythgallery/mythgallery/iconview.cpp b/mythplugins/mythgallery/mythgallery/iconview.cpp index 9eca9e13c57..a991e5ca741 100644 --- a/mythplugins/mythgallery/mythgallery/iconview.cpp +++ b/mythplugins/mythgallery/mythgallery/iconview.cpp @@ -54,7 +54,6 @@ using namespace std; #include "glsingleview.h" #define LOC QString("IconView: ") -#define LOC_ERR QString("IconView, Error: ") QEvent::Type ChildCountEvent::kEventType = (QEvent::Type) QEvent::registerEventType(); @@ -939,7 +938,8 @@ void IconView::HandleSubMenuMark(void) { QString label = tr("Marking Options"); - m_menuPopup = new MythDialogBox(label, m_popupStack, "mythgallerymenupopup"); + m_menuPopup = new MythDialogBox(label, m_popupStack, + "mythgallerymenupopup"); if (m_menuPopup->Create()) m_popupStack->AddScreen(m_menuPopup); @@ -956,8 +956,8 @@ void IconView::HandleSubMenuFilter(void) { MythScreenStack *mainStack = GetScreenStack(); - GalleryFilterDialog *filterdialog = new GalleryFilterDialog(mainStack, - "galleryfilter", m_galleryFilter); + GalleryFilterDialog *filterdialog = + new GalleryFilterDialog(mainStack, "galleryfilter", m_galleryFilter); if (filterdialog->Create()) mainStack->AddScreen(filterdialog); @@ -969,7 +969,8 @@ void IconView::HandleSubMenuFile(void) { QString label = tr("File Options"); - m_menuPopup = new MythDialogBox(label, m_popupStack, "mythgallerymenupopup"); + m_menuPopup = new MythDialogBox(label, m_popupStack, + "mythgallerymenupopup"); if (m_menuPopup->Create()) m_popupStack->AddScreen(m_menuPopup); diff --git a/mythplugins/mythgallery/mythgallery/singleview.cpp b/mythplugins/mythgallery/mythgallery/singleview.cpp index 186bd2701ab..083b8535822 100644 --- a/mythplugins/mythgallery/mythgallery/singleview.cpp +++ b/mythplugins/mythgallery/mythgallery/singleview.cpp @@ -43,7 +43,6 @@ using namespace std; #include "galleryutil.h" #define LOC QString("QtView: ") -#define LOC_ERR QString("QtView, Error: ") template T sq(T val) { return val * val; } From c4f071d6857957d1240d6389a4bd16abbad9618b Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Thu, 4 Aug 2011 11:59:22 -0400 Subject: [PATCH 15/49] Fixes a null settings data Save.. that column doesn't allow null values so use an empty string instead. --- mythtv/programs/mythfrontend/themechooser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythtv/programs/mythfrontend/themechooser.cpp b/mythtv/programs/mythfrontend/themechooser.cpp index 3d863018e37..540c03f8b0a 100644 --- a/mythtv/programs/mythfrontend/themechooser.cpp +++ b/mythtv/programs/mythfrontend/themechooser.cpp @@ -890,7 +890,7 @@ ThemeUpdateChecker::ThemeUpdateChecker() : "remotethemes/themes.zip", "Temp"); - gCoreContext->SaveSetting("ThemeUpdateStatus", QString()); + gCoreContext->SaveSetting("ThemeUpdateStatus", ""); connect(m_updateTimer, SIGNAL(timeout()), SLOT(checkForUpdate())); m_updateTimer->start(60 * 60 * 1000); // Run once an hour From 4dfcdb8dd0c80d096ed95d5eccd489c692efa90d Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Thu, 4 Aug 2011 15:34:56 -0400 Subject: [PATCH 16/49] Fix SQL reconnection logic. Refs #9704. Refs #9773. Refs #9792. What this does is get rid of the old KickDatabase() logic and replaces it with a simple reconnect if the DB socket is disconnected, and also gets rid of a recent re-enablement of the automatic reconnects in [dd2d7a14d1] and importantly it extends the reconnection logic in [528324d8ba] so that it resends the prepare() and rebinds the bindings when a reconnect happens in an exec(). This also makes the QSqlQuery parent of MSqlQuery private and adds some wrappers so we can prevent MSqlQuery users from accessing methods that may invalidate some assumption in MSqlQuery + it adds debugging wrappers for first(), last(), previous(), and seek() like we already had for next(). A little bit of history is in order. In Qt3 the SQL driver automatically reconnected whenever a connection was lost. But the first query after this auto-reconnect always failed. So in 2003 mdz added KickDatabase() which would recover disconnect and reconnect an automatically all was good with the world. In Qt4 the QSqlQuery::prepare() started to actually do prepared statements instead of emulating them. This caused a small problem in now it was possible that a disconnect happened between the call to prepare() and exec() and then the exec() would fail. But odds of this were still pretty low for most uses of the database in MythTV. But at some point trolltech also got rid of the automatic reconnections which caused us trouble in Qt3. To fix this we added reconnection logic in [528324d8ba] and this is where the real trouble began. While this reconnection logic really does exactly the same thing that the auto-reconnection logic did in Qt3, the fact that prepare() doesn't just emulate prepared statements in Qt4 means that it's now that when we reconnect to the database in exec() the prepared statement has not been sent to the database. Note: This should be back-ported to 0.24-fixes after a reasonable burn-in time in master. --- mythtv/libs/libmyth/programinfo.cpp | 24 +-- mythtv/libs/libmythbase/mythdb.cpp | 2 +- mythtv/libs/libmythbase/mythdb.h | 5 +- mythtv/libs/libmythbase/mythdbcon.cpp | 197 +++++++++++-------- mythtv/libs/libmythbase/mythdbcon.h | 53 ++++- mythtv/libs/libmythbase/mythversion.h | 2 +- mythtv/libs/libmythtv/datadirect.cpp | 3 +- mythtv/libs/libmythtv/dbcheck.cpp | 8 +- mythtv/programs/mythbackend/httpstatus.cpp | 9 +- mythtv/programs/mythbackend/main_helpers.cpp | 12 +- mythtv/programs/mythbackend/mainserver.cpp | 8 +- mythtv/programs/mythbackend/scheduler.cpp | 4 +- mythtv/programs/mythfrontend/progfind.cpp | 2 +- 13 files changed, 193 insertions(+), 136 deletions(-) diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp index 9a189fc6242..73b4c9ea639 100644 --- a/mythtv/libs/libmyth/programinfo.cpp +++ b/mythtv/libs/libmyth/programinfo.cpp @@ -2372,8 +2372,8 @@ QStringList ProgramInfo::QueryDVDBookmark( { query.prepare(" SELECT title, framenum, audionum, subtitlenum " " FROM dvdbookmark " - " WHERE serialid = ? "); - query.addBindValue(serialid); + " WHERE serialid = :SERIALID "); + query.bindValue(":SERIALID", serialid); if (query.exec() && query.next()) { @@ -2407,17 +2407,17 @@ void ProgramInfo::SaveDVDBookmark(const QStringList &fields) const MythDB::DBError("SetDVDBookmark inserting", query); query.prepare(" UPDATE dvdbookmark " - " SET title = ? , " - " audionum = ? , " - " subtitlenum = ? , " - " framenum = ? , " + " SET title = :TITLE , " + " audionum = :AUDIONUM , " + " subtitlenum = :SUBTITLENUM , " + " framenum = :FRAMENUM , " " timestamp = NOW() " - " WHERE serialid = ? ;"); - query.addBindValue(title); - query.addBindValue(audionum); - query.addBindValue(subtitlenum); - query.addBindValue(frame); - query.addBindValue(serialid); + " WHERE serialid = :SERIALID"); + query.bindValue(":TITLE",title); + query.bindValue(":AUDIONUM",audionum); + query.bindValue(":SUBTITLENUM",subtitlenum); + query.bindValue(":FRAMENUM",frame); + query.bindValue(":SERIALID",serialid); if (!query.exec()) MythDB::DBError("SetDVDBookmark updating", query); diff --git a/mythtv/libs/libmythbase/mythdb.cpp b/mythtv/libs/libmythbase/mythdb.cpp index befc6f8c929..7af8157af28 100644 --- a/mythtv/libs/libmythbase/mythdb.cpp +++ b/mythtv/libs/libmythbase/mythdb.cpp @@ -162,7 +162,7 @@ QString MythDB::toCommaList(const QMap &bindings, return str; } -void MythDB::DBError(const QString &where, const QSqlQuery& query) +void MythDB::DBError(const QString &where, const MSqlQuery& query) { QString str = QString("DB Error (%1):\n").arg(where); diff --git a/mythtv/libs/libmythbase/mythdb.h b/mythtv/libs/libmythbase/mythdb.h index e2ce5566a2e..8f43979990a 100644 --- a/mythtv/libs/libmythbase/mythdb.h +++ b/mythtv/libs/libmythbase/mythdb.h @@ -14,12 +14,13 @@ class MDBManager; class MBASE_PUBLIC MythDB { + friend class MSqlQuery; public: MDBManager *GetDBManager(void); Settings *GetOldSettings(void); - static void DBError(const QString &where, const QSqlQuery &query); - static QString DBErrorMessage(const QSqlError& err); + static void DBError(const QString &where, const MSqlQuery &query); + static QString DBErrorMessage(const QSqlError &err); DatabaseParams GetDatabaseParams(void) const; void SetDatabaseParams(const DatabaseParams ¶ms); diff --git a/mythtv/libs/libmythbase/mythdbcon.cpp b/mythtv/libs/libmythbase/mythdbcon.cpp index f7c78523173..16dad09c6c1 100644 --- a/mythtv/libs/libmythbase/mythdbcon.cpp +++ b/mythtv/libs/libmythbase/mythdbcon.cpp @@ -18,6 +18,11 @@ #include "exitcodes.h" #include +#define DEBUG_RECONNECT 0 +#if DEBUG_RECONNECT +#include +#endif + static const uint kPurgeTimeout = 60 * 60; bool TestDatabase(QString dbHostName, @@ -71,10 +76,6 @@ MSqlDatabase::MSqlDatabase(const QString &name) LOG(VB_GENERAL, LOG_ERR, "Unable to init db connection."); return; } - QString connectOptions("MYSQL_OPT_RECONNECT=1"); - LOG(VB_GENERAL, LOG_DEBUG, QString("Setting connect options: %1") - .arg(connectOptions)); - m_db.setConnectOptions(connectOptions); m_lastDBKick = QDateTime::currentDateTime().addSecs(-60); } @@ -213,51 +214,14 @@ bool MSqlDatabase::OpenDatabase(bool skipdb) return connected; } -bool MSqlDatabase::KickDatabase() +bool MSqlDatabase::KickDatabase(void) { - // Some explanation is called for. This exists because the mysql - // driver does not gracefully handle the situation where a TCP - // socketconnection is dropped (for example due to a timeout). If - // a Unix domain socket connection is lost, the driver - // transparently reestablishes the connection and we don't even - // notice. However, when this happens with a TCP connection, the - // driver returns an error for the next query to be executed, and - // THEN reestablishes the connection (so the second query succeeds - // with no intervention). - // mdz, 2003/08/11 - - - if (m_lastDBKick.secsTo(QDateTime::currentDateTime()) < 30 && - m_db.isOpen()) - { - return true; - } - - QString query("SELECT NULL;"); - for (unsigned int i = 0 ; i < 2 ; ++i, usleep(50000)) - { - if (m_db.isOpen()) - { - QSqlQuery result = m_db.exec(query); // don't convert to MSqlQuery - if (result.isActive()) - { - m_lastDBKick = QDateTime::currentDateTime(); - return true; - } - } - - if (i == 0) - { - m_db.close(); - m_db.open(); - } - else - LOG(VB_GENERAL, LOG_ERR, MythDB::DBErrorMessage(m_db.lastError())); - } - m_lastDBKick = QDateTime::currentDateTime().addSecs(-60); - return false; + if (!m_db.isOpen()) + m_db.open(); + + return m_db.isOpen(); } bool MSqlDatabase::Reconnect() @@ -624,15 +588,31 @@ void MSqlQuery::CloseLogCon() bool MSqlQuery::exec() { - // Database connection down. Try to restart it, give up if it's still - // down if (!m_db) { // Database structure's been deleted return false; } - if (!m_db->isOpen() && !m_db->Reconnect()) + if (m_last_prepared_query.isEmpty()) + { + LOG(VB_GENERAL, LOG_ERR, + "MSqlQuery::exec(void) called without a prepared query."); + return false; + } + +#if DEBUG_RECONNECT + if (random() < RAND_MAX / 50) + { + LOG(VB_GENERAL, LOG_INFO, + "MSqlQuery disconnecting DB to test reconnection logic"); + m_db->m_db.close(); + } +#endif + + // Database connection down. Try to restart it, give up if it's still + // down + if (!m_db->isOpen() && !Reconnect()) { LOG(VB_GENERAL, LOG_INFO, "MySQL server disconnected"); return false; @@ -643,7 +623,7 @@ bool MSqlQuery::exec() // if the query failed with "MySQL server has gone away" // Close and reopen the database connection and retry the query if it // connects again - if (!result && QSqlQuery::lastError().number() == 2006 && m_db->Reconnect()) + if (!result && QSqlQuery::lastError().number() == 2006 && Reconnect()) result = QSqlQuery::exec(); if (VERBOSE_LEVEL_CHECK(VB_DATABASE, LOG_DEBUG)) @@ -678,9 +658,15 @@ bool MSqlQuery::exec() bool MSqlQuery::exec(const QString &query) { + if (!m_db) + { + // Database structure's been deleted + return false; + } + // Database connection down. Try to restart it, give up if it's still // down - if (!m_db->isOpen() && !m_db->Reconnect()) + if (!m_db->isOpen() && !Reconnect()) { LOG(VB_GENERAL, LOG_INFO, "MySQL server disconnected"); return false; @@ -691,7 +677,7 @@ bool MSqlQuery::exec(const QString &query) // if the query failed with "MySQL server has gone away" // Close and reopen the database connection and retry the query if it // connects again - if (!result && QSqlQuery::lastError().number() == 2006 && m_db->Reconnect()) + if (!result && QSqlQuery::lastError().number() == 2006 && Reconnect()) result = QSqlQuery::exec(query); LOG(VB_DATABASE, LOG_DEBUG, @@ -703,35 +689,77 @@ bool MSqlQuery::exec(const QString &query) return result; } -bool MSqlQuery::next() +bool MSqlQuery::seekDebug(const char *type, bool result, + int where, bool relative) const { - bool result = QSqlQuery::next(); - if (result && VERBOSE_LEVEL_CHECK(VB_DATABASE, LOG_DEBUG)) { QString str; - QSqlRecord record=QSqlQuery::record(); + QSqlRecord rec = record(); - for ( long int i = 0; iMSqlDatabase::GetConnectionName()) - .arg(str)); + if (QString("seek")==type) + { + LOG(VB_DATABASE, LOG_DEBUG, + QString("MSqlQuery::seek(%1,%2,%3) Result: \"%4\"") + .arg(m_db->MSqlDatabase::GetConnectionName()) + .arg(where).arg(relative) + .arg(str)); + } + else + { + LOG(VB_DATABASE, LOG_DEBUG, + QString("MSqlQuery::%1(%2) Result: \"%3\"") + .arg(type).arg(m_db->MSqlDatabase::GetConnectionName()) + .arg(str)); + } } - return result; } +bool MSqlQuery::next(void) +{ + return seekDebug("next", QSqlQuery::next(), 0, false); +} + +bool MSqlQuery::previous(void) +{ + return seekDebug("previous", QSqlQuery::previous(), 0, false); +} + +bool MSqlQuery::first(void) +{ + return seekDebug("first", QSqlQuery::first(), 0, false); +} + +bool MSqlQuery::last(void) +{ + return seekDebug("last", QSqlQuery::last(), 0, false); +} + +bool MSqlQuery::seek(int where, bool relative) +{ + return seekDebug("seek", QSqlQuery::seek(where, relative), where, relative); +} + bool MSqlQuery::prepare(const QString& query) { + if (!m_db) + { + // Database structure's been deleted + return false; + } + m_last_prepared_query = query; + #ifdef DEBUG_QT4_PORT if (query.contains(m_testbindings)) { @@ -752,7 +780,7 @@ bool MSqlQuery::prepare(const QString& query) return false; } - if (!m_db->isOpen() && !m_db->Reconnect()) + if (!m_db->isOpen() && !Reconnect()) { LOG(VB_GENERAL, LOG_INFO, "MySQL server disconnected"); return false; @@ -763,7 +791,7 @@ bool MSqlQuery::prepare(const QString& query) // if the prepare failed with "MySQL server has gone away" // Close and reopen the database connection and retry the query if it // connects again - if (!ok && QSqlQuery::lastError().number() == 2006 && m_db->Reconnect()) + if (!ok && QSqlQuery::lastError().number() == 2006 && Reconnect()) ok = QSqlQuery::prepare(query); if (!ok && !(GetMythDB()->SuppressDBMessages())) @@ -789,8 +817,7 @@ bool MSqlQuery::testDBConnection() return isOpen; } -void MSqlQuery::bindValue (const QString & placeholder, - const QVariant & val, QSql::ParamType paramType) +void MSqlQuery::bindValue(const QString &placeholder, const QVariant &val) { #ifdef DEBUG_QT4_PORT // XXX - HACK BEGIN @@ -805,28 +832,12 @@ void MSqlQuery::bindValue (const QString & placeholder, // XXX - HACK END #endif - if (val.type() == QVariant::String && val.isNull()) - { - QSqlQuery::bindValue(placeholder, QString(""), paramType); - return; - } - QSqlQuery::bindValue(placeholder, val, paramType); -} - -void MSqlQuery::bindValue(int pos, const QVariant & val, - QSql::ParamType paramType) -{ - if (val.type() == QVariant::String && val.isNull()) - { - QSqlQuery::bindValue(pos, QString(""), paramType); - return; - } - QSqlQuery::bindValue(pos, val, paramType); + QSqlQuery::bindValue(placeholder, val, QSql::In); } -void MSqlQuery::bindValues(MSqlBindings &bindings) +void MSqlQuery::bindValues(const MSqlBindings &bindings) { - MSqlBindings::Iterator it; + MSqlBindings::const_iterator it; for (it = bindings.begin(); it != bindings.end(); ++it) { bindValue(it.key(), it.value()); @@ -838,6 +849,20 @@ QVariant MSqlQuery::lastInsertId() return QSqlQuery::lastInsertId(); } +bool MSqlQuery::Reconnect(void) +{ + if (!m_db->Reconnect()) + return false; + if (!m_last_prepared_query.isEmpty()) + { + MSqlBindings tmp = QSqlQuery::boundValues(); + if (!prepare(m_last_prepared_query)) + return false; + bindValues(tmp); + } + return true; +} + void MSqlAddMoreBindings(MSqlBindings &output, MSqlBindings &addfrom) { MSqlBindings::Iterator it; diff --git a/mythtv/libs/libmythbase/mythdbcon.h b/mythtv/libs/libmythbase/mythdbcon.h index f607574ddd0..601ac52b43f 100644 --- a/mythtv/libs/libmythbase/mythdbcon.h +++ b/mythtv/libs/libmythbase/mythdbcon.h @@ -2,6 +2,8 @@ #define MYTHDBCON_H_ #include +#include +#include #include #include #include @@ -21,7 +23,7 @@ MBASE_PUBLIC bool TestDatabase(QString dbHostName, int dbPort = 3306); /// \brief QSqlDatabase wrapper, used by MSqlQuery. Do not use directly. -class MBASE_PUBLIC MSqlDatabase +class MSqlDatabase { friend class MDBManager; friend class MSqlQuery; @@ -119,8 +121,9 @@ typedef QMap MSqlBindings; * will crash if closed and reopend - so we never close them and keep them in * a pool. */ -class MBASE_PUBLIC MSqlQuery : public QSqlQuery +class MBASE_PUBLIC MSqlQuery : private QSqlQuery { + friend void MSqlEscapeAsAQuery(QString&, MSqlBindings&); public: /// \brief Get DB connection from pool MSqlQuery(const MSqlQueryInfo &qi); @@ -136,19 +139,29 @@ class MBASE_PUBLIC MSqlQuery : public QSqlQuery /// \brief Wrap QSqlQuery::next() so we can display the query results bool next(void); + /// \brief Wrap QSqlQuery::previous() so we can display the query results + bool previous(void); + + /// \brief Wrap QSqlQuery::first() so we can display the query results + bool first(void); + + /// \brief Wrap QSqlQuery::last() so we can display the query results + bool last(void); + + /// \brief Wrap QSqlQuery::seek(int,bool) + // so we can display the query results + bool seek(int, bool relative = false); + /// \brief Wrap QSqlQuery::exec(const QString &query) so we can display SQL bool exec(const QString &query); /// \brief QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2 bool prepare(const QString &query); - /// \brief Wrap QSqlQuery::bindValue so we can convert null QStrings to empty QStrings - void bindValue ( const QString & placeholder, const QVariant & val, QSql::ParamType paramType = QSql::In ); - /// \brief Wrap QSqlQuery::bindValue so we can convert null QStrings to empty QStrings - void bindValue ( int pos, const QVariant & val, QSql::ParamType paramType = QSql::In ); + void bindValue(const QString &placeholder, const QVariant &val); /// \brief Add all the bindings in the passed in bindings - void bindValues(MSqlBindings &bindings); + void bindValues(const MSqlBindings &bindings); /** \brief Return the id of the last inserted row * @@ -160,6 +173,24 @@ class MBASE_PUBLIC MSqlQuery : public QSqlQuery */ QVariant lastInsertId(); + /// Reconnects server and re-prepares and re-binds the last prepared + /// query. + bool Reconnect(void); + + // Thunks that allow us to make QSqlQuery private + QVariant value(int i) const { return QSqlQuery::value(i); } + QString executedQuery(void) const { return QSqlQuery::executedQuery(); } + QMap boundValues(void) const + { return QSqlQuery::boundValues(); } + QSqlError lastError(void) const { return QSqlQuery::lastError(); } + int size(void) const { return QSqlQuery::size();} + bool isActive(void) const { return QSqlQuery::isActive(); } + QSqlRecord record(void) const { return QSqlQuery::record(); } + int numRowsAffected() const { return QSqlQuery::numRowsAffected(); } + void setForwardOnly(bool f) { QSqlQuery::setForwardOnly(f); } + bool isNull(int field) const { return QSqlQuery::isNull(field); } + + /// \brief Checks DB connection + login (login info via Mythcontext) static bool testDBConnection(); @@ -180,6 +211,14 @@ class MBASE_PUBLIC MSqlQuery : public QSqlQuery static void CloseLogCon(); private: + // Only QSql::In is supported as a param type and only named params... + void bindValue(const QString&, const QVariant&, QSql::ParamType); + void bindValue(int, const QVariant&, QSql::ParamType); + void addBindValue(const QVariant&, QSql::ParamType = QSql::In); + + bool seekDebug(const char *type, bool result, + int where, bool relative) const; + MSqlDatabase *m_db; bool m_isConnected; bool m_returnConnection; diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h index 24883260d5d..ab870ed009b 100644 --- a/mythtv/libs/libmythbase/mythversion.h +++ b/mythtv/libs/libmythbase/mythversion.h @@ -12,7 +12,7 @@ /// Update this whenever the plug-in API changes. /// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and /// libmythui class methods used by plug-ins. -#define MYTH_BINARY_VERSION "0.25.20110802-1" +#define MYTH_BINARY_VERSION "0.25.20110804-1" /** \brief Increment this whenever the MythTV network protocol changes. * diff --git a/mythtv/libs/libmythtv/datadirect.cpp b/mythtv/libs/libmythtv/datadirect.cpp index 17509bc3fac..b388b8fb4c9 100644 --- a/mythtv/libs/libmythtv/datadirect.cpp +++ b/mythtv/libs/libmythtv/datadirect.cpp @@ -822,8 +822,7 @@ bool DataDirectProcessor::UpdateChannelsUnsafe( if (!chan_update_q.exec()) { - MythDB::DBError("Updating channel table", - chan_update_q.lastQuery()); + MythDB::DBError("Updating channel table", chan_update_q); } } diff --git a/mythtv/libs/libmythtv/dbcheck.cpp b/mythtv/libs/libmythtv/dbcheck.cpp index 37bbb99b8e2..9bde63958a4 100644 --- a/mythtv/libs/libmythtv/dbcheck.cpp +++ b/mythtv/libs/libmythtv/dbcheck.cpp @@ -3666,7 +3666,7 @@ NULL { MythDB::DBError(QString("Unable to perform test for database " "corruption before character set conversion."), - thequery); + query); return false; } // If the conversion to utf8 resulted in warnings, the data in the @@ -3696,7 +3696,7 @@ NULL { MythDB::DBError(QString("Error getting database warnings for " "database corruption test."), - thequery); + query); return false; } // Test creating an index to see if we had partial corruption that @@ -3710,7 +3710,7 @@ NULL if (!ok) { MythDB::DBError(QString("Index creation failed."), - thequery); + query); LOG(VB_GENERAL, LOG_ERR, "DB charset pre-conversion test " "failed! Your database seems to be partially " "corrupted. Please move the backup to a safe " @@ -3724,7 +3724,7 @@ NULL thequery = QString("DROP TEMPORARY TABLE temp_%1;").arg(table); if (!query.exec(thequery)) MythDB::DBError(QString("Error dropping temporary table %1.") - .arg(table), thequery); + .arg(table), query); tableIndex++; } diff --git a/mythtv/programs/mythbackend/httpstatus.cpp b/mythtv/programs/mythbackend/httpstatus.cpp index 103fed64e9f..6328bbb9ba9 100644 --- a/mythtv/programs/mythbackend/httpstatus.cpp +++ b/mythtv/programs/mythbackend/httpstatus.cpp @@ -526,13 +526,10 @@ void HttpStatus::FillStatusXML( QDomDocument *pDoc ) MSqlQuery query(MSqlQuery::InitCon()); query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;"); - if (query.exec() && query.isActive() && query.size()) + if (query.exec() && query.next()) { - query.next(); - - if (query.isValid()) - GuideDataThrough = QDateTime::fromString(query.value(0).toString(), - Qt::ISODate); + GuideDataThrough = QDateTime::fromString( + query.value(0).toString(), Qt::ISODate); } guide.setAttribute("start", diff --git a/mythtv/programs/mythbackend/main_helpers.cpp b/mythtv/programs/mythbackend/main_helpers.cpp index 7536223874f..4cfe1c81bc3 100644 --- a/mythtv/programs/mythbackend/main_helpers.cpp +++ b/mythtv/programs/mythbackend/main_helpers.cpp @@ -75,15 +75,14 @@ bool setupTVs(bool ismaster, bool &error) "DATE_FORMAT(starttime, '%Y%m%d%H%i00'), '_', " "DATE_FORMAT(endtime, '%Y%m%d%H%i00'), '.nuv') " "WHERE basename = '';")) - MythDB::DBError("Updating record basename", - query.lastQuery()); + MythDB::DBError("Updating record basename", query); // Hack to make sure record.station gets set if the user // downgrades to a prior version and creates new entries // without it. if (!query.exec("UPDATE channel SET callsign=chanid " "WHERE callsign IS NULL OR callsign='';")) - MythDB::DBError("Updating channel callsign", query.lastQuery()); + MythDB::DBError("Updating channel callsign", query); if (query.exec("SELECT MIN(chanid) FROM channel;")) { @@ -91,10 +90,10 @@ bool setupTVs(bool ismaster, bool &error) int min_chanid = query.value(0).toInt(); if (!query.exec(QString("UPDATE record SET chanid = %1 " "WHERE chanid IS NULL;").arg(min_chanid))) - MythDB::DBError("Updating record chanid", query.lastQuery()); + MythDB::DBError("Updating record chanid", query); } else - MythDB::DBError("Querying minimum chanid", query.lastQuery()); + MythDB::DBError("Querying minimum chanid", query); MSqlQuery records_without_station(MSqlQuery::InitCon()); records_without_station.prepare("SELECT record.chanid," @@ -113,8 +112,7 @@ bool setupTVs(bool ismaster, bool &error) records_without_station.value(0)); if (!update_record.exec()) { - MythDB::DBError("Updating record station", - update_record.lastQuery()); + MythDB::DBError("Updating record station", update_record); } } while (records_without_station.next()); } diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp index 3c121282ac3..7e3193b342b 100644 --- a/mythtv/programs/mythbackend/mainserver.cpp +++ b/mythtv/programs/mythbackend/mainserver.cpp @@ -3072,12 +3072,10 @@ void MainServer::getGuideDataThrough(QDateTime &GuideDataThrough) MSqlQuery query(MSqlQuery::InitCon()); query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;"); - if (query.exec() && query.isActive() && query.size()) + if (query.exec() && query.next()) { - query.next(); - if (query.isValid()) - GuideDataThrough = QDateTime::fromString(query.value(0).toString(), - Qt::ISODate); + GuideDataThrough = QDateTime::fromString( + query.value(0).toString(), Qt::ISODate); } } diff --git a/mythtv/programs/mythbackend/scheduler.cpp b/mythtv/programs/mythbackend/scheduler.cpp index 3a5fce07e14..a7494d6f327 100644 --- a/mythtv/programs/mythbackend/scheduler.cpp +++ b/mythtv/programs/mythbackend/scheduler.cpp @@ -3978,12 +3978,12 @@ void Scheduler::AddNewRecords(void) { result.prepare("DROP TABLE IF EXISTS sched_temp_record;"); if (!result.exec()) - MythDB::DBError("AddNewRecords sched_temp_record", query); + MythDB::DBError("AddNewRecords sched_temp_record", result); } result.prepare("DROP TABLE IF EXISTS sched_temp_recorded;"); if (!result.exec()) - MythDB::DBError("AddNewRecords drop table", query); + MythDB::DBError("AddNewRecords drop table", result); } void Scheduler::AddNotListed(void) { diff --git a/mythtv/programs/mythfrontend/progfind.cpp b/mythtv/programs/mythfrontend/progfind.cpp index fae9161802c..439f728c904 100644 --- a/mythtv/programs/mythfrontend/progfind.cpp +++ b/mythtv/programs/mythfrontend/progfind.cpp @@ -532,7 +532,7 @@ void ProgFinder::getShowNames() query.bindValues(bindings); if (!query.exec()) { - MythDB::DBError("getShowNames", thequery); + MythDB::DBError("getShowNames", query); return; } From 1fb0a77fc17089b5cd2bf36ef07998bf68461261 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Thu, 4 Aug 2011 17:15:52 -0400 Subject: [PATCH 17/49] Few bits missing in [4dfcdb8dd]. Refs #9704. Refs #9773. Refs #9792. --- mythplugins/mythmusic/mythmusic/smartplaylist.cpp | 2 +- mythplugins/mythweather/mythweather/weatherSource.cpp | 6 +++--- mythtv/libs/libmythbase/mythdbcon.h | 3 ++- mythtv/libs/libmythbase/mythversion.h | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mythplugins/mythmusic/mythmusic/smartplaylist.cpp b/mythplugins/mythmusic/mythmusic/smartplaylist.cpp index 1e7254d73f0..303f763f66f 100644 --- a/mythplugins/mythmusic/mythmusic/smartplaylist.cpp +++ b/mythplugins/mythmusic/mythmusic/smartplaylist.cpp @@ -1741,7 +1741,7 @@ void SmartPLResultViewer::setSQL(QString sql) query.value(4).toString(), query.value(5).toString(), query.value(6).toString()); - } while (query.prev()); + } while (query.previous()); } // set selection to first item diff --git a/mythplugins/mythweather/mythweather/weatherSource.cpp b/mythplugins/mythweather/mythweather/weatherSource.cpp index 152bc38f544..f55ccc96964 100644 --- a/mythplugins/mythweather/mythweather/weatherSource.cpp +++ b/mythplugins/mythweather/mythweather/weatherSource.cpp @@ -256,7 +256,7 @@ ScriptInfo *WeatherSource::ProbeScript(const QFileInfo &fi) db.bindValue(":EMAIL", info.email); if (!db.exec()) { - MythDB::DBError("Updating weather source settings.", query); + MythDB::DBError("Updating weather source settings.", db); return NULL; } } @@ -290,7 +290,7 @@ ScriptInfo *WeatherSource::ProbeScript(const QFileInfo &fi) db.bindValue(":TYPES", info.types.join(",")); if (!db.exec()) { - MythDB::DBError("Inserting weather source", query); + MythDB::DBError("Inserting weather source", db); return NULL; } query = "SELECT sourceid FROM weathersourcesettings " @@ -302,7 +302,7 @@ ScriptInfo *WeatherSource::ProbeScript(const QFileInfo &fi) db.bindValue(":NAME", info.name); if (!db.exec()) { - MythDB::DBError("Getting weather sourceid", query); + MythDB::DBError("Getting weather sourceid", db); return NULL; } else if (!db.next()) diff --git a/mythtv/libs/libmythbase/mythdbcon.h b/mythtv/libs/libmythbase/mythdbcon.h index 601ac52b43f..f69c045522d 100644 --- a/mythtv/libs/libmythbase/mythdbcon.h +++ b/mythtv/libs/libmythbase/mythdbcon.h @@ -189,7 +189,8 @@ class MBASE_PUBLIC MSqlQuery : private QSqlQuery int numRowsAffected() const { return QSqlQuery::numRowsAffected(); } void setForwardOnly(bool f) { QSqlQuery::setForwardOnly(f); } bool isNull(int field) const { return QSqlQuery::isNull(field); } - + const QSqlDriver *driver(void) const { return QSqlQuery::driver(); } + int at(void) const { return QSqlQuery::at(); } /// \brief Checks DB connection + login (login info via Mythcontext) static bool testDBConnection(); diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h index ab870ed009b..34cceaa5d63 100644 --- a/mythtv/libs/libmythbase/mythversion.h +++ b/mythtv/libs/libmythbase/mythversion.h @@ -12,7 +12,7 @@ /// Update this whenever the plug-in API changes. /// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and /// libmythui class methods used by plug-ins. -#define MYTH_BINARY_VERSION "0.25.20110804-1" +#define MYTH_BINARY_VERSION "0.25.20110804-2" /** \brief Increment this whenever the MythTV network protocol changes. * From bac1097c35dcc6845ca1760dfb07f89ff72db918 Mon Sep 17 00:00:00 2001 From: Lawrence Rust Date: Thu, 4 Aug 2011 16:42:04 -0700 Subject: [PATCH 18/49] Fix MythGallery's use of removable devices MythGallery has a menu option 'Show Devices' to show pictures on removable media. However, there are some bugs in the current code that stop this from working and also prevent the display of pictures on media inserted if MediaMonitor 'Jump to Plugin' is enabled. This also effectively enables the media monitor for Windows builds. Closes #9522 Signed-off-by: Gavin Hurlbut --- .../mythgallery/mythgallery/iconview.cpp | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/mythplugins/mythgallery/mythgallery/iconview.cpp b/mythplugins/mythgallery/mythgallery/iconview.cpp index a991e5ca741..44ccbe828dd 100644 --- a/mythplugins/mythgallery/mythgallery/iconview.cpp +++ b/mythplugins/mythgallery/mythgallery/iconview.cpp @@ -212,7 +212,8 @@ bool IconView::Create(void) m_thumbGen->setSize(thumbWidth, thumbHeight); SetupMediaMonitor(); - LoadDirectory(m_galleryDir); + if (!m_currDevice) + LoadDirectory(m_galleryDir); return true; } @@ -347,7 +348,10 @@ void IconView::LoadThumbnail(ThumbItem *item) void IconView::SetupMediaMonitor(void) { -#ifndef _WIN32 +#ifdef _WIN32 + if (m_currDevice) + LoadDirectory(m_currDevice->getDevicePath()); +#else MediaMonitor *mon = MediaMonitor::GetMediaMonitor(); if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice)) { @@ -378,7 +382,6 @@ void IconView::SetupMediaMonitor(void) mon->Unlock(m_currDevice); } } - m_currDevice = NULL; #endif // _WIN32 } @@ -538,6 +541,9 @@ bool IconView::HandleMediaDeviceSelect(ThumbItem *item) { m_currDevice = item->GetMediaDevice(); +#ifdef _WIN32 + LoadDirectory(m_currDevice->getDevicePath()); +#else if (!m_currDevice->isMounted(false)) m_currDevice->mount(); @@ -550,6 +556,7 @@ bool IconView::HandleMediaDeviceSelect(ThumbItem *item) MythMediaDevice*))); LoadDirectory(m_currDevice->getMountPath()); +#endif mon->Unlock(m_currDevice); } @@ -1076,7 +1083,11 @@ void IconView::HandleSettings(void) MediaMonitor *mon = MediaMonitor::GetMediaMonitor(); if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice)) { +#ifdef _WIN32 + LoadDirectory(m_currDevice->getDevicePath()); +#else LoadDirectory(m_currDevice->getMountPath()); +#endif mon->Unlock(m_currDevice); } else @@ -1161,8 +1172,8 @@ void IconView::HandleImport(void) void IconView::HandleShowDevices(void) { -#ifndef _WIN32 MediaMonitor *mon = MediaMonitor::GetMediaMonitor(); +#ifndef _WIN32 if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice)) { m_currDevice->disconnect(this); @@ -1190,10 +1201,10 @@ void IconView::HandleShowDevices(void) m_itemList.append(item); m_itemHash.insert(item->GetName(), item); -#ifndef _WIN32 if (mon) { - QList removables = mon->GetMedias(MEDIATYPE_DATA); + MythMediaType type = MythMediaType(MEDIATYPE_DATA | MEDIATYPE_MGALLERY); + QList removables = mon->GetMedias(type); QList::Iterator it = removables.begin(); for (; it != removables.end(); it++) { @@ -1211,7 +1222,6 @@ void IconView::HandleShowDevices(void) } } } -#endif ThumbItem *thumbitem; for (int x = 0; x < m_itemList.size(); x++) From 89ad944f273a1f49fdc15982008ebc5566d88eba Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Thu, 4 Aug 2011 20:24:53 -0400 Subject: [PATCH 19/49] Make sure ProgramInfo::DiscoverRecordingDirectory() doesn't return a null string which will throw off inuse insert. --- mythtv/libs/libmyth/programinfo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp index 73b4c9ea639..3010351a49a 100644 --- a/mythtv/libs/libmyth/programinfo.cpp +++ b/mythtv/libs/libmyth/programinfo.cpp @@ -3812,7 +3812,7 @@ QString ProgramInfo::DiscoverRecordingDirectory(void) const if (!IsLocal()) { if (!gCoreContext->IsBackend()) - return QString(); + return ""; QString path = GetPlaybackURL(false, true); if (path.left(1) == "/") @@ -3821,7 +3821,7 @@ QString ProgramInfo::DiscoverRecordingDirectory(void) const return testFile.path(); } - return QString(); + return ""; } QFileInfo testFile(pathname); @@ -3853,7 +3853,7 @@ QString ProgramInfo::DiscoverRecordingDirectory(void) const } } - return QString(); + return ""; } #include From 1c2b33e696dbf96ceb2eca6151e43dcb895b2c4b Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Thu, 4 Aug 2011 20:29:37 -0400 Subject: [PATCH 20/49] Cleanup DeviceReadBuffer start()/stop() handling. --- mythtv/libs/libmythtv/DeviceReadBuffer.cpp | 47 ++++++++++------------ mythtv/libs/libmythtv/DeviceReadBuffer.h | 3 +- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/mythtv/libs/libmythtv/DeviceReadBuffer.cpp b/mythtv/libs/libmythtv/DeviceReadBuffer.cpp index 95ce4490c82..68de6e0e1a3 100644 --- a/mythtv/libs/libmythtv/DeviceReadBuffer.cpp +++ b/mythtv/libs/libmythtv/DeviceReadBuffer.cpp @@ -23,7 +23,7 @@ DeviceReadBuffer::DeviceReadBuffer(DeviceReaderCB *cb, bool use_poll) readerCB(cb), // Data for managing the device ringbuffer - dorun(false), running(false), + dorun(false), eof(false), error(false), request_pause(false), paused(false), using_poll(use_poll), max_poll_wait(2500 /*ms*/), @@ -58,10 +58,12 @@ DeviceReadBuffer::DeviceReadBuffer(DeviceReaderCB *cb, bool use_poll) DeviceReadBuffer::~DeviceReadBuffer() { + Stop(); if (buffer) + { delete[] buffer; - if (isRunning() || dorun) - Stop(); + buffer = NULL; + } } bool DeviceReadBuffer::Setup(const QString &streamName, int streamfd, @@ -125,28 +127,25 @@ void DeviceReadBuffer::Start(void) { LOG(VB_RECORD, LOG_INFO, LOC + "Start() -- begin"); + QMutexLocker locker(&lock); if (isRunning() || dorun) { - { - QMutexLocker locker(&lock); - dorun = false; - } + dorun = false; + locker.unlock(); WakePoll(); wait(); + locker.relock(); } - { - QMutexLocker locker(&lock); - error = false; - eof = false; - } + dorun = true; + error = false; + eof = false; start(); LOG(VB_RECORD, LOG_INFO, LOC + "Start() -- middle"); - QMutexLocker locker(&lock); - while (dorun && !running) + while (dorun && !isRunning()) runWait.wait(locker.mutex(), 100); LOG(VB_RECORD, LOG_INFO, LOC + "Start() -- end"); @@ -170,15 +169,14 @@ void DeviceReadBuffer::Reset(const QString &streamName, int streamfd) void DeviceReadBuffer::Stop(void) { LOG(VB_RECORD, LOG_INFO, LOC + "Stop() -- begin"); + QMutexLocker locker(&lock); + if (isRunning() || dorun) { - QMutexLocker locker(&lock); dorun = false; + locker.unlock(); + WakePoll(); + wait(); } - - WakePoll(); - LOG(VB_RECORD, LOG_INFO, LOC + "Stop() -- middle"); - - wait(); LOG(VB_RECORD, LOG_INFO, LOC + "Stop() -- end"); } @@ -205,7 +203,7 @@ void DeviceReadBuffer::WakePoll(void) const char buf[1]; buf[0] = '0'; ssize_t wret = 0; - while (running && (wret <= 0) && (wake_pipe[1] >= 0)) + while (isRunning() && (wret <= 0) && (wake_pipe[1] >= 0)) { wret = ::write(wake_pipe[1], &buf, 1); if ((wret < 0) && (EAGAIN != errno) && (EINTR != errno)) @@ -277,7 +275,7 @@ bool DeviceReadBuffer::IsEOF(void) const bool DeviceReadBuffer::IsRunning(void) const { QMutexLocker locker(&lock); - return running; + return isRunning(); } uint DeviceReadBuffer::GetUnused(void) const @@ -325,8 +323,6 @@ void DeviceReadBuffer::run(void) threadRegister("DeviceReadBuffer"); lock.lock(); - dorun = true; - running = true; runWait.wakeAll(); lock.unlock(); @@ -382,7 +378,6 @@ void DeviceReadBuffer::run(void) ClosePipes(); lock.lock(); - running = false; eof = true; runWait.wakeAll(); dataWait.wakeAll(); @@ -675,7 +670,7 @@ uint DeviceReadBuffer::WaitForUsed(uint needed, uint max_wait) const QMutexLocker locker(&lock); size_t avail = used; - while ((needed > avail) && running && + while ((needed > avail) && isRunning() && !request_pause && !error && !eof && (timer.elapsed() < (int)max_wait)) { diff --git a/mythtv/libs/libmythtv/DeviceReadBuffer.h b/mythtv/libs/libmythtv/DeviceReadBuffer.h index 0a3fab172d0..3779d54ab69 100644 --- a/mythtv/libs/libmythtv/DeviceReadBuffer.h +++ b/mythtv/libs/libmythtv/DeviceReadBuffer.h @@ -89,8 +89,7 @@ class DeviceReadBuffer : protected QThread // Data for managing the device ringbuffer mutable QMutex lock; - bool dorun; - bool running; + volatile bool dorun; bool eof; mutable bool error; bool request_pause; From 9189f5c441b22b500ca243ea43e2401f4a4dd748 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Fri, 5 Aug 2011 11:00:31 -0400 Subject: [PATCH 21/49] Make DVBChannel dtor thread-safe. --- mythtv/libs/libmythtv/dtvchannel.cpp | 71 +++++----- mythtv/libs/libmythtv/dtvchannel.h | 15 ++- mythtv/libs/libmythtv/dvbchannel.cpp | 187 +++++++++++++++++++++----- mythtv/libs/libmythtv/dvbchannel.h | 11 +- mythtv/libs/libmythtv/hdhrchannel.cpp | 14 +- mythtv/libs/libmythtv/hdhrchannel.h | 4 +- 6 files changed, 223 insertions(+), 79 deletions(-) diff --git a/mythtv/libs/libmythtv/dtvchannel.cpp b/mythtv/libs/libmythtv/dtvchannel.cpp index 3d30f854531..41ed1b52cdf 100644 --- a/mythtv/libs/libmythtv/dtvchannel.cpp +++ b/mythtv/libs/libmythtv/dtvchannel.cpp @@ -12,8 +12,9 @@ using namespace std; #define LOC QString("DTVChan(%1): ").arg(GetDevice()) -QMutex DTVChannel::master_map_lock; -QMap DTVChannel::master_map; +QReadWriteLock DTVChannel::master_map_lock(QReadWriteLock::Recursive); +typedef QMap > MasterMap; +MasterMap DTVChannel::master_map; DTVChannel::DTVChannel(TVRec *parent) : ChannelBase(parent), @@ -39,17 +40,6 @@ DTVChannel::~DTVChannel() delete genPMT; genPMT = NULL; } - - QMutexLocker locker(&master_map_lock); - QMap::iterator it = master_map.begin(); - for (; it != master_map.end(); ++it) - { - if (*it == this) - { - master_map.erase(it); - break; - } - } } void DTVChannel::SetDTVInfo(uint atsc_major, uint atsc_minor, @@ -142,32 +132,47 @@ void DTVChannel::SaveCachedPids(const pid_cache_t &pid_cache) const ChannelUtil::SaveCachedPids(chanid, pid_cache); } -DTVChannel *DTVChannel::GetMaster(const QString &videodevice) +void DTVChannel::RegisterForMaster(const QString &key) { - QMutexLocker locker(&master_map_lock); - - QMap::iterator it = master_map.find(videodevice); - if (it != master_map.end()) - return *it; - - QString tmp = videodevice; tmp.detach(); - master_map[tmp] = this; - - return this; + master_map_lock.lockForWrite(); + master_map[key].push_back(this); + master_map_lock.unlock(); } -const DTVChannel *DTVChannel::GetMaster(const QString &videodevice) const +void DTVChannel::DeregisterForMaster(const QString &key) { - QMutexLocker locker(&master_map_lock); - - QMap::iterator it = master_map.find(videodevice); - if (it != master_map.end()) - return *it; + master_map_lock.lockForWrite(); + MasterMap::iterator mit = master_map.find(key); + if (mit == master_map.end()) + mit = master_map.begin(); + for (; mit != master_map.end(); ++mit) + { + (*mit).removeAll(this); + if (mit.key() == key) + break; + } + master_map_lock.unlock(); +} - QString tmp = videodevice; tmp.detach(); - master_map[tmp] = (DTVChannel*) this; +DTVChannel *DTVChannel::GetMasterLock(const QString &key) +{ + master_map_lock.lockForRead(); + MasterMap::iterator mit = master_map.find(key); + if (mit == master_map.end() || (*mit).empty()) + { + master_map_lock.unlock(); + return NULL; + } + return (*mit).front(); +} - return this; +void DTVChannel::ReturnMasterLock(DTVChannelP &chan) +{ + if (chan != NULL) + { + chan = NULL; + master_map_lock.unlock(); + } } bool DTVChannel::SetChannelByString(const QString &channum) diff --git a/mythtv/libs/libmythtv/dtvchannel.h b/mythtv/libs/libmythtv/dtvchannel.h index 2a824978f1f..22be7384465 100644 --- a/mythtv/libs/libmythtv/dtvchannel.h +++ b/mythtv/libs/libmythtv/dtvchannel.h @@ -15,8 +15,9 @@ using namespace std; // Qt headers -#include +#include #include +#include // MythTV headers #include "dtvconfparserhelpers.h" // for DTVTunerType @@ -107,8 +108,11 @@ class DTVChannel : public ChannelBase void GetCachedPids(pid_cache_t &pid_cache) const; - DTVChannel *GetMaster(const QString &videodevice); - const DTVChannel *GetMaster(const QString &videodevice) const; + void RegisterForMaster(const QString &key); + void DeregisterForMaster(const QString &key); + static DTVChannel *GetMasterLock(const QString &key); + typedef DTVChannel* DTVChannelP; + static void ReturnMasterLock(DTVChannelP&); /// \brief Returns true if this is the first of a number of multi-rec devs virtual bool IsMaster(void) const { return false; } @@ -155,8 +159,9 @@ class DTVChannel : public ChannelBase /// This is a generated PMT for RAW pid tuning ProgramMapTable *genPMT; - static QMutex master_map_lock; - static QMap master_map; + typedef QMap > MasterMap; + static QReadWriteLock master_map_lock; + static MasterMap master_map; }; #endif // _DTVCHANNEL_H_ diff --git a/mythtv/libs/libmythtv/dvbchannel.cpp b/mythtv/libs/libmythtv/dvbchannel.cpp index 9dd47e977ea..315d1de0bf1 100644 --- a/mythtv/libs/libmythtv/dvbchannel.cpp +++ b/mythtv/libs/libmythtv/dvbchannel.cpp @@ -63,7 +63,7 @@ static DTVMultiplex dvbparams_to_dtvmultiplex( * \bug Only supports single input cards. */ DVBChannel::DVBChannel(const QString &aDevice, TVRec *parent) - : DTVChannel(parent), master(NULL), + : DTVChannel(parent), // Helper classes diseqc_tree(NULL), dvbcam(NULL), // Device info @@ -77,11 +77,11 @@ DVBChannel::DVBChannel(const QString &aDevice, TVRec *parent) fd_frontend(-1), device(aDevice), has_crc_bug(false) { + master_map_lock.lockForWrite(); QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device); - master = dynamic_cast(GetMaster(devname)); - master = (master == this) ? NULL : master; - - if (!master) + master_map[devname].push_back(this); // == RegisterForMaster + DVBChannel *master = dynamic_cast(master_map[devname].front()); + if (master == this) { dvbcam = new DVBCam(device); has_crc_bug = CardUtil::HasDVBCRCBug(device); @@ -91,20 +91,42 @@ DVBChannel::DVBChannel(const QString &aDevice, TVRec *parent) dvbcam = master->dvbcam; has_crc_bug = master->has_crc_bug; } + master_map_lock.unlock(); sigmon_delay = CardUtil::GetMinSignalMonitoringDelay(device); } DVBChannel::~DVBChannel() { - if (IsOpen()) - Close(); - - if (dvbcam && !master) + // set a new master if there are other instances and we're the master + // whether we are the master or not remove us from the map.. + master_map_lock.lockForWrite(); + QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device); + DVBChannel *master = dynamic_cast(master_map[devname].front()); + if (master == this) { - delete dvbcam; - dvbcam = NULL; + master_map[devname].pop_front(); + DVBChannel *new_master = NULL; + if (!master_map[devname].empty()) + new_master = dynamic_cast(master_map[devname].front()); + if (new_master) + new_master->is_open = master->is_open; } + else + { + master_map[devname].removeAll(this); + } + master_map_lock.unlock(); + + Close(); + + // if we're the last one out delete dvbcam + master_map_lock.lockForRead(); + MasterMap::iterator mit = master_map.find(devname); + if ((*mit).empty()) + delete dvbcam; + dvbcam = NULL; + master_map_lock.unlock(); // diseqc_tree is managed elsewhere } @@ -119,15 +141,19 @@ void DVBChannel::Close(DVBChannel *who) is_open.erase(it); - if (master) + QMutexLocker locker(&hw_lock); + + DVBChannel *master = GetMasterLock(); + if (master != NULL && master != this) { - QMutexLocker locker(&hw_lock); if (dvbcam->IsRunning()) dvbcam->SetPMT(this, NULL); master->Close(this); fd_frontend = -1; + ReturnMasterLock(master); return; } + ReturnMasterLock(master); // if we're the master we don't need this lock.. if (!is_open.empty()) return; // not all callers have closed the DVB channel yet.. @@ -135,7 +161,6 @@ void DVBChannel::Close(DVBChannel *who) if (diseqc_tree) diseqc_tree->Close(); - QMutexLocker locker(&hw_lock); if (fd_frontend >= 0) { close(fd_frontend); @@ -157,10 +182,14 @@ bool DVBChannel::Open(DVBChannel *who) return true; } - if (master) + DVBChannel *master = GetMasterLock(); + if (master != this) { if (!master->Open(who)) + { + ReturnMasterLock(master); return false; + } fd_frontend = master->fd_frontend; frontend_name = master->frontend_name; @@ -177,11 +206,14 @@ bool DVBChannel::Open(DVBChannel *who) if (!InitializeInputs()) { Close(); + ReturnMasterLock(master); return false; } + ReturnMasterLock(master); return true; } + ReturnMasterLock(master); // if we're the master we don't need this lock.. QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device); QByteArray devn = devname.toAscii(); @@ -609,13 +641,19 @@ bool DVBChannel::Tune(const DTVMultiplex &tuning, bool same_input) { QMutexLocker lock(&tune_lock); + QMutexLocker locker(&hw_lock); - if (master) + DVBChannel *master = GetMasterLock(); + if (master != this) { LOG(VB_CHANNEL, LOG_INFO, LOC + "tuning on slave channel"); SetSIStandard(tuning.sistandard); - return master->Tune(tuning, inputid, force_reset, false); + bool ok = master->Tune(tuning, inputid, force_reset, false); + ReturnMasterLock(master); + return ok; } + ReturnMasterLock(master); // if we're the master we don't need this lock.. + int intermediate_freq = 0; bool can_fec_auto = false; @@ -630,8 +668,6 @@ bool DVBChannel::Tune(const DTVMultiplex &tuning, desired_tuning = tuning; - QMutexLocker locker(&hw_lock); - if (fd_frontend < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!"); @@ -806,8 +842,14 @@ bool DVBChannel::IsTuningParamsProbeSupported(void) const return false; } - if (master) - return master->IsTuningParamsProbeSupported(); + const DVBChannel *master = GetMasterLock(); + if (master != this) + { + bool ok = master->IsTuningParamsProbeSupported(); + ReturnMasterLock(master); + return ok; + } + ReturnMasterLock(master); // if we're the master we don't need this lock.. if (diseqc_tree) { @@ -839,8 +881,14 @@ bool DVBChannel::ProbeTuningParams(DTVMultiplex &tuning) const return false; } - if (master) - return master->ProbeTuningParams(tuning); + const DVBChannel *master = GetMasterLock(); + if (master != this) + { + bool ok = master->ProbeTuningParams(tuning); + ReturnMasterLock(master); + return ok; + } + ReturnMasterLock(master); // if we're the master we don't need this lock.. if (diseqc_tree) { @@ -919,8 +967,14 @@ const DiSEqCDevRotor *DVBChannel::GetRotor(void) const // documented in dvbchannel.h bool DVBChannel::HasLock(bool *ok) const { - if (master) - return master->HasLock(ok); + const DVBChannel *master = GetMasterLock(); + if (master != this) + { + bool haslock = master->HasLock(ok); + ReturnMasterLock(master); + return haslock; + } + ReturnMasterLock(master); // if we're the master we don't need this lock.. fe_status_t status; memset(&status, 0, sizeof(status)); @@ -935,8 +989,14 @@ bool DVBChannel::HasLock(bool *ok) const // documented in dvbchannel.h double DVBChannel::GetSignalStrength(bool *ok) const { - if (master) - return master->GetSignalStrength(ok); + const DVBChannel *master = GetMasterLock(); + if (master != this) + { + double val = master->GetSignalStrength(ok); + ReturnMasterLock(master); + return val; + } + ReturnMasterLock(master); // if we're the master we don't need this lock.. // We use uint16_t for sig because this is correct for DVB API 4.0, // and works better than the correct int16_t for the 3.x API @@ -953,8 +1013,14 @@ double DVBChannel::GetSignalStrength(bool *ok) const // documented in dvbchannel.h double DVBChannel::GetSNR(bool *ok) const { - if (master) - return master->GetSNR(ok); + const DVBChannel *master = GetMasterLock(); + if (master != this) + { + double val = master->GetSNR(ok); + ReturnMasterLock(master); + return val; + } + ReturnMasterLock(master); // if we're the master we don't need this lock.. // We use uint16_t for sig because this is correct for DVB API 4.0, // and works better than the correct int16_t for the 3.x API @@ -971,8 +1037,14 @@ double DVBChannel::GetSNR(bool *ok) const // documented in dvbchannel.h double DVBChannel::GetBitErrorRate(bool *ok) const { - if (master) - return master->GetBitErrorRate(ok); + const DVBChannel *master = GetMasterLock(); + if (master != this) + { + double val = master->GetBitErrorRate(ok); + ReturnMasterLock(master); + return val; + } + ReturnMasterLock(master); // if we're the master we don't need this lock.. uint32_t ber = 0; int ret = ioctl(fd_frontend, FE_READ_BER, &ber); @@ -986,8 +1058,14 @@ double DVBChannel::GetBitErrorRate(bool *ok) const // documented in dvbchannel.h double DVBChannel::GetUncorrectedBlockCount(bool *ok) const { - if (master) - return master->GetUncorrectedBlockCount(ok); + const DVBChannel *master = GetMasterLock(); + if (master != this) + { + double val = master->GetUncorrectedBlockCount(ok); + ReturnMasterLock(master); + return val; + } + ReturnMasterLock(master); // if we're the master we don't need this lock.. uint32_t ublocks = 0; int ret = ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks); @@ -998,6 +1076,49 @@ double DVBChannel::GetUncorrectedBlockCount(bool *ok) const return (double) ublocks; } +DVBChannel *DVBChannel::GetMasterLock(void) +{ + QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device); + DTVChannel *master = DTVChannel::GetMasterLock(devname); + DVBChannel *dvbm = dynamic_cast(master); + if (master && !dvbm) + DTVChannel::ReturnMasterLock(master); + return dvbm; +} + +void DVBChannel::ReturnMasterLock(DVBChannelP &dvbm) +{ + DTVChannel *chan = static_cast(dvbm); + DTVChannel::ReturnMasterLock(chan); + dvbm = NULL; +} + +const DVBChannel *DVBChannel::GetMasterLock(void) const +{ + QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device); + DTVChannel *master = DTVChannel::GetMasterLock(devname); + DVBChannel *dvbm = dynamic_cast(master); + if (master && !dvbm) + DTVChannel::ReturnMasterLock(master); + return dvbm; +} + +void DVBChannel::ReturnMasterLock(DVBChannelCP &dvbm) +{ + DTVChannel *chan = + static_cast(const_cast(dvbm)); + DTVChannel::ReturnMasterLock(chan); + dvbm = NULL; +} + +bool DVBChannel::IsMaster(void) const +{ + const DVBChannel *master = GetMasterLock(); + bool is_master = (master == this); + ReturnMasterLock(master); + return is_master; +} + /** \fn drain_dvb_events(int) * \brief Reads all the events off the queue, so we can use select * in wait_for_backend(int,int). diff --git a/mythtv/libs/libmythtv/dvbchannel.h b/mythtv/libs/libmythtv/dvbchannel.h index ab5a2ebfbea..5287910f1ab 100644 --- a/mythtv/libs/libmythtv/dvbchannel.h +++ b/mythtv/libs/libmythtv/dvbchannel.h @@ -53,7 +53,7 @@ class DVBChannel : public DTVChannel QString GetCardNum(void) const { return device; }; /// Returns frontend name as reported by driver QString GetFrontendName(void) const; - bool IsMaster(void) const { return master == NULL; } + bool IsMaster(void) const; /// Returns true iff we have a faulty DVB driver that munges PMT bool HasCRCBug(void) const { return has_crc_bug; } uint GetMinSignalMonitorDelay(void) const { return sigmon_delay; } @@ -98,8 +98,15 @@ class DVBChannel : public DTVChannel bool CheckModulation(DTVModulation modulation) const; bool CheckCodeRate(DTVCodeRate rate) const; + typedef DVBChannel* DVBChannelP; + DVBChannel *GetMasterLock(void); + static void ReturnMasterLock(DVBChannelP &dvbm); + + typedef const DVBChannel* DVBChannelCP; + const DVBChannel *GetMasterLock(void) const; + static void ReturnMasterLock(DVBChannelCP &dvbm); + private: - DVBChannel *master; IsOpenMap is_open; // Data diff --git a/mythtv/libs/libmythtv/hdhrchannel.cpp b/mythtv/libs/libmythtv/hdhrchannel.cpp index 6784f94fd7c..abee603bdde 100644 --- a/mythtv/libs/libmythtv/hdhrchannel.cpp +++ b/mythtv/libs/libmythtv/hdhrchannel.cpp @@ -34,16 +34,24 @@ using namespace std; HDHRChannel::HDHRChannel(TVRec *parent, const QString &device) : DTVChannel(parent), - _device_id(device), _master(NULL), + _device_id(device), _stream_handler(NULL) { - _master = dynamic_cast(GetMaster(device)); - _master = (_master == this) ? NULL : _master; + RegisterForMaster(_device_id); } HDHRChannel::~HDHRChannel(void) { Close(); + DeregisterForMaster(_device_id); +} + +bool HDHRChannel::IsMaster(void) const +{ + DTVChannel *master = DTVChannel::GetMasterLock(_device_id); + bool is_master = (master == static_cast(this)); + DTVChannel::ReturnMasterLock(master); + return is_master; } bool HDHRChannel::Open(void) diff --git a/mythtv/libs/libmythtv/hdhrchannel.h b/mythtv/libs/libmythtv/hdhrchannel.h index 85f801ce8fe..05232454d7f 100644 --- a/mythtv/libs/libmythtv/hdhrchannel.h +++ b/mythtv/libs/libmythtv/hdhrchannel.h @@ -35,8 +35,7 @@ class HDHRChannel : public DTVChannel QString GetDevice(void) const { return _device_id; } virtual vector GetTunerTypes(void) const { return _tuner_types; } - virtual bool IsMaster(void) const - { return _master == NULL; } + virtual bool IsMaster(void) const; // Sets virtual bool SetChannelByString(const QString &channum); @@ -49,7 +48,6 @@ class HDHRChannel : public DTVChannel private: QString _device_id; - HDHRChannel *_master; HDHRStreamHandler *_stream_handler; vector _tuner_types; }; From d85b750fdea94d46d30b8d501d5f82c2d68b3e0a Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Fri, 5 Aug 2011 14:22:34 -0400 Subject: [PATCH 22/49] Refs #9704. Make new DB code more forgiving of NULL strings in NOT NULL columns. If the query fails with NULL bindings on strings, this tries to resend the query without any NULL strings and if that succeeds it prints an error message and proceeds. Note: If you see the DB error message, it really does indicate code that needs fixing. --- mythtv/libs/libmythbase/mythdb.cpp | 21 +++++++++++++++--- mythtv/libs/libmythbase/mythdb.h | 1 + mythtv/libs/libmythbase/mythdbcon.cpp | 31 ++++++++++++++++++++++++++- mythtv/libs/libmythbase/mythversion.h | 2 +- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/mythtv/libs/libmythbase/mythdb.cpp b/mythtv/libs/libmythbase/mythdb.cpp index 7af8157af28..cbfaa183acc 100644 --- a/mythtv/libs/libmythbase/mythdb.cpp +++ b/mythtv/libs/libmythbase/mythdb.cpp @@ -140,7 +140,17 @@ QString MythDB::toCommaList(const QMap &bindings, QString str = QString("%1").arg("", indent); for (; it != bindings.end(); ++it) { - const QString curBinding = it.key() + '=' + (*it).toString() + ','; + QString val = (*it).toString(); + if ((*it).isNull()) + { + val = "NULL"; + } + else if (it->type() == QVariant::String) + { + val = (it->toString().isNull()) ? + "NULL" : QString("\"%1\"").arg(val); + } + const QString curBinding = it.key() + '=' + val + ','; if ((curColumn > indent) && ((curBinding.length() + curColumn) > maxColumn)) { @@ -162,7 +172,7 @@ QString MythDB::toCommaList(const QMap &bindings, return str; } -void MythDB::DBError(const QString &where, const MSqlQuery& query) +QString MythDB::GetError(const QString &where, const MSqlQuery &query) { QString str = QString("DB Error (%1):\n").arg(where); @@ -175,7 +185,12 @@ void MythDB::DBError(const QString &where, const MSqlQuery& query) str += tmp; } str += DBErrorMessage(query.lastError()); - LOG(VB_GENERAL, LOG_ERR, str); + return str; +} + +void MythDB::DBError(const QString &where, const MSqlQuery &query) +{ + LOG(VB_GENERAL, LOG_ERR, GetError(where, query)); } QString MythDB::DBErrorMessage(const QSqlError& err) diff --git a/mythtv/libs/libmythbase/mythdb.h b/mythtv/libs/libmythbase/mythdb.h index 8f43979990a..68322275a4b 100644 --- a/mythtv/libs/libmythbase/mythdb.h +++ b/mythtv/libs/libmythbase/mythdb.h @@ -19,6 +19,7 @@ class MBASE_PUBLIC MythDB MDBManager *GetDBManager(void); Settings *GetOldSettings(void); + static QString GetError(const QString &where, const MSqlQuery &query); static void DBError(const QString &where, const MSqlQuery &query); static QString DBErrorMessage(const QSqlError &err); diff --git a/mythtv/libs/libmythbase/mythdbcon.cpp b/mythtv/libs/libmythbase/mythdbcon.cpp index 16dad09c6c1..77e4db64892 100644 --- a/mythtv/libs/libmythbase/mythdbcon.cpp +++ b/mythtv/libs/libmythbase/mythdbcon.cpp @@ -626,6 +626,35 @@ bool MSqlQuery::exec() if (!result && QSqlQuery::lastError().number() == 2006 && Reconnect()) result = QSqlQuery::exec(); + if (!result) + { + QString err = MythDB::GetError("MSqlQuery", *this); + MSqlBindings tmp = QSqlQuery::boundValues(); + bool has_null_strings = false; + for (MSqlBindings::iterator it = tmp.begin(); it != tmp.end(); ++it) + { + if (it->type() != QVariant::String) + continue; + if (it->isNull() || it->toString().isNull()) + { + has_null_strings = true; + *it = QVariant(QString("")); + } + } + if (has_null_strings) + { + bindValues(tmp); + result = QSqlQuery::exec(); + } + if (result) + { + LOG(VB_GENERAL, LOG_ERR, + QString("Original query failed, but resend with empty " + "strings in place of NULL strings worked. ") + + "\n" + err); + } + } + if (VERBOSE_LEVEL_CHECK(VB_DATABASE, LOG_DEBUG)) { QString str = lastQuery(); @@ -856,7 +885,7 @@ bool MSqlQuery::Reconnect(void) if (!m_last_prepared_query.isEmpty()) { MSqlBindings tmp = QSqlQuery::boundValues(); - if (!prepare(m_last_prepared_query)) + if (!QSqlQuery::prepare(m_last_prepared_query)) return false; bindValues(tmp); } diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h index 34cceaa5d63..db6425c6cc2 100644 --- a/mythtv/libs/libmythbase/mythversion.h +++ b/mythtv/libs/libmythbase/mythversion.h @@ -12,7 +12,7 @@ /// Update this whenever the plug-in API changes. /// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and /// libmythui class methods used by plug-ins. -#define MYTH_BINARY_VERSION "0.25.20110804-2" +#define MYTH_BINARY_VERSION "0.25.20110805-1" /** \brief Increment this whenever the MythTV network protocol changes. * From da10d33168ab02d2fb72226914313d4f95860730 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sat, 6 Aug 2011 11:21:10 -0400 Subject: [PATCH 23/49] Make RingBuffer dtor virtual. --- mythtv/libs/libmythtv/ringbuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythtv/libs/libmythtv/ringbuffer.h b/mythtv/libs/libmythtv/ringbuffer.h index 6073c56ddb3..2b0cd9272ee 100644 --- a/mythtv/libs/libmythtv/ringbuffer.h +++ b/mythtv/libs/libmythtv/ringbuffer.h @@ -47,7 +47,7 @@ class MTV_PUBLIC RingBuffer : protected QThread bool usereadahead = true, int timeout_ms = kDefaultOpenTimeout, bool stream_only = false); - ~RingBuffer(); + virtual ~RingBuffer(); // Sets void SetWriteBufferSize(int newSize); From 16dda801269ef7d6878ed7e6bc17edf1ed54f220 Mon Sep 17 00:00:00 2001 From: Paul Harrison Date: Sun, 7 Aug 2011 20:05:00 +0100 Subject: [PATCH 24/49] Silence a few compiler/analysis tool warnings spotted by Stuart M. --- .../mytharchive/mytharchive/mythburn.cpp | 2 +- .../mytharchive/recordingselector.cpp | 2 +- .../mythmusic/mythmusic/playbackbox.cpp | 22 ++++++++++++------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/mythplugins/mytharchive/mytharchive/mythburn.cpp b/mythplugins/mytharchive/mytharchive/mythburn.cpp index 22cfefcf198..c20aef7ee20 100644 --- a/mythplugins/mytharchive/mytharchive/mythburn.cpp +++ b/mythplugins/mytharchive/mytharchive/mythburn.cpp @@ -410,7 +410,7 @@ void MythBurn::updateArchiveList(void) else { delete busyPopup; - busyPopup = false; + busyPopup = NULL; } qApp->processEvents(); diff --git a/mythplugins/mytharchive/mytharchive/recordingselector.cpp b/mythplugins/mytharchive/mytharchive/recordingselector.cpp index 9af96a6732b..6276d3ab3f0 100644 --- a/mythplugins/mytharchive/mytharchive/recordingselector.cpp +++ b/mythplugins/mytharchive/mytharchive/recordingselector.cpp @@ -131,7 +131,7 @@ void RecordingSelector::Init(void) else { delete busyPopup; - busyPopup = false; + busyPopup = NULL; } GetRecordingListThread *thread = new GetRecordingListThread(this); diff --git a/mythplugins/mythmusic/mythmusic/playbackbox.cpp b/mythplugins/mythmusic/mythmusic/playbackbox.cpp index 66c7ab31774..b95cff27afa 100644 --- a/mythplugins/mythmusic/mythmusic/playbackbox.cpp +++ b/mythplugins/mythmusic/mythmusic/playbackbox.cpp @@ -1850,13 +1850,15 @@ void PlaybackBoxMusic::restorePosition(const QString &position) { curMeta = gMusicData->all_music->getMetadata(node->getInt()); if (curMeta) + { updateTrackInfo(curMeta); - maxTime = curMeta->Length() / 1000; + maxTime = curMeta->Length() / 1000; - QString time_string = getTimeString(maxTime, 0); + QString time_string = getTimeString(maxTime, 0); - bannerEnable(curMeta, show_album_art); + bannerEnable(curMeta, show_album_art); + } } } else @@ -1877,13 +1879,15 @@ void PlaybackBoxMusic::restorePosition(const QString &position) { curMeta = gMusicData->all_music->getMetadata(node->getInt()); if (curMeta) + { updateTrackInfo(curMeta); - maxTime = curMeta->Length() / 1000; + maxTime = curMeta->Length() / 1000; - QString time_string = getTimeString(maxTime, 0); + QString time_string = getTimeString(maxTime, 0); - bannerEnable(curMeta, show_album_art); + bannerEnable(curMeta, show_album_art); + } } } else @@ -2281,11 +2285,13 @@ void PlaybackBoxMusic::handleTreeListSignals(int node_int, IntVector *attributes curMeta = gMusicData->all_music->getMetadata(node_int); if (curMeta) + { updateTrackInfo(curMeta); - maxTime = curMeta->Length() / 1000; + maxTime = curMeta->Length() / 1000; - QString time_string = getTimeString(maxTime, 0); + QString time_string = getTimeString(maxTime, 0); + } if (gPlayer->getOutput() && gPlayer->getOutput()->IsPaused()) { From f2bf6325dd4a0599852cf467c653ca456362648e Mon Sep 17 00:00:00 2001 From: Paul Harrison Date: Sun, 7 Aug 2011 20:42:36 +0100 Subject: [PATCH 25/49] MythArchive: fix the thumb image finder. This works around the broken/incomplete cut list passed from ProgramInfo and also fixes a few compiler/static analysis tool warnings. --- .../mytharchive/mytharchive/thumbfinder.cpp | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/mythplugins/mytharchive/mytharchive/thumbfinder.cpp b/mythplugins/mytharchive/mytharchive/thumbfinder.cpp index 0f479923613..9dcac61cbbd 100644 --- a/mythplugins/mytharchive/mytharchive/thumbfinder.cpp +++ b/mythplugins/mytharchive/mytharchive/thumbfinder.cpp @@ -280,6 +280,21 @@ void ThumbFinder::loadCutList() progInfo->QueryCutList(m_deleteMap); delete progInfo; } + + // if the first mark is a end mark then add the start mark at the beginning + frm_dir_map_t::const_iterator it = m_deleteMap.begin(); + if (it.value() == MARK_CUT_END) + m_deleteMap.insert(0, MARK_CUT_START); + + + // if the last mark is a start mark then add the end mark at the end + it = m_deleteMap.end(); + --it; + if (it != m_deleteMap.end()) + { + if (it.value() == MARK_CUT_START) + m_deleteMap.insert(m_archiveItem->duration * m_fps, MARK_CUT_END); + } } void ThumbFinder::savePressed() @@ -430,12 +445,12 @@ bool ThumbFinder::getThumbImages() return false; } - if (m_archiveItem->type == "Recording") - loadCutList(); - if (!initAVCodec(m_archiveItem->filename)) return false; + if (m_archiveItem->type == "Recording") + loadCutList(); + // calculate the file duration taking the cut list into account m_finalDuration = calcFinalDuration(); @@ -658,7 +673,14 @@ int ThumbFinder::checkFramePosition(int frameNumber) for (it = m_deleteMap.begin(); it != m_deleteMap.end(); ++it) { int start = it.key(); + ++it; + if (it == m_deleteMap.end()) + { + LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: found a start cut but no cut end"); + break; + } + int end = it.key(); if (start <= frameNumber + diff) @@ -947,6 +969,12 @@ void ThumbFinder::updatePositionBar(int64_t frame) startdelta = size.width(); ++it; + if (it == m_deleteMap.end()) + { + LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: found a start cut but no cut end"); + break; + } + if (it.key() != 0) enddelta = (m_archiveItem->duration * m_fps) / it.key(); else @@ -983,7 +1011,14 @@ int ThumbFinder::calcFinalDuration() for (it = m_deleteMap.begin(); it != m_deleteMap.end(); ++it) { start = it.key(); + ++it; + if (it == m_deleteMap.end()) + { + LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: found a start cut but no cut end"); + break; + } + end = it.key(); cutLen += end - start; } From 01a91b76d70cfc2656910f686709af25e09d37ff Mon Sep 17 00:00:00 2001 From: Robert McNamara Date: Sun, 7 Aug 2011 15:04:35 -0700 Subject: [PATCH 26/49] MythGame: Add a intid to Game Metadata DB. This adds an auto-increment primary key to the game metadata DB, equivalent to the one in video metadata. Also adds a method to get all the Rom Info from the DB into a QList, which will be of use in writing a better game scanner (and for dissecting the DB queries and UI in the hopefully near future). --- mythplugins/mythgame/mythgame/dbcheck.cpp | 15 ++- mythplugins/mythgame/mythgame/gameui.cpp | 6 +- mythplugins/mythgame/mythgame/rominfo.cpp | 134 +++++++++++++++------- mythplugins/mythgame/mythgame/rominfo.h | 14 ++- 4 files changed, 124 insertions(+), 45 deletions(-) diff --git a/mythplugins/mythgame/mythgame/dbcheck.cpp b/mythplugins/mythgame/mythgame/dbcheck.cpp index f8b7205dfbf..cdae3279af6 100644 --- a/mythplugins/mythgame/mythgame/dbcheck.cpp +++ b/mythplugins/mythgame/mythgame/dbcheck.cpp @@ -10,7 +10,7 @@ using namespace std; #include "dbcheck.h" #include "gamesettings.h" -const QString currentDatabaseVersion = "1017"; +const QString currentDatabaseVersion = "1018"; static bool UpdateDBVersionNumber(const QString &newnumber) { @@ -424,5 +424,18 @@ QString("ALTER DATABASE %1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;") return false; } + if (dbver == "1017") + { + const QString updates[] = { + +"ALTER TABLE gamemetadata ADD intid int(11) NOT NULL AUTO_INCREMENT " +"PRIMARY KEY FIRST;", +"" +}; + + if (!performActualUpdate(updates, "1018", dbver)) + return false; + } + return true; } diff --git a/mythplugins/mythgame/mythgame/gameui.cpp b/mythplugins/mythgame/mythgame/gameui.cpp index 2f2e9dc6704..81606c66a7a 100644 --- a/mythplugins/mythgame/mythgame/gameui.cpp +++ b/mythplugins/mythgame/mythgame/gameui.cpp @@ -533,7 +533,7 @@ void GameUI::customEvent(QEvent *event) node->SetData(qVariantFromValue(romInfo)); node->setString(romInfo->Gamename()); - romInfo->UpdateDatabase(); + romInfo->SaveToDatabase(); updateChangedNode(node, romInfo); } else if (resultid == "detailsPopup") @@ -977,7 +977,7 @@ void GameUI::OnGameSearchDone(MetadataLookup *lookup) StartGameImageSet(node, coverart, fanart, screenshot); - metadata->UpdateDatabase(); + metadata->SaveToDatabase(); updateChangedNode(node, metadata); } @@ -1065,6 +1065,6 @@ void GameUI::handleDownloadedImages(MetadataLookup *lookup) metadata->setScreenshot(filename); } - metadata->UpdateDatabase(); + metadata->SaveToDatabase(); updateChangedNode(node, metadata); } diff --git a/mythplugins/mythgame/mythgame/rominfo.cpp b/mythplugins/mythgame/mythgame/rominfo.cpp index ea4a821d7e2..90d6f341ab8 100644 --- a/mythplugins/mythgame/mythgame/rominfo.cpp +++ b/mythplugins/mythgame/mythgame/rominfo.cpp @@ -16,45 +16,42 @@ bool operator==(const RomInfo& a, const RomInfo& b) return false; } -void RomInfo::UpdateDatabase() +void RomInfo::SaveToDatabase() { MSqlQuery query(MSqlQuery::InitCon()); - query.prepare("SELECT gamename,genre,year,country,plot,publisher, " - "favorite,screenshot,fanart,boxart,inetref " - "FROM gamemetadata " - "WHERE gametype = :GAMETYPE " - "AND romname = :ROMNAME"); - query.bindValue(":GAMETYPE", GameType()); - query.bindValue(":ROMNAME", Romname()); + bool inserting = false; - if (!query.exec()) + if (id == 0) + inserting = true; + + if (inserting) { - MythDB::DBError("RomInfo::UpdateDatabase", query); - return; + query.prepare("INSERT INTO gamemetadata " + "(system, romname, gamename, genre, year, gametype, " + "rompath, country, crc_value, diskcount, display, plot, " + "publisher, version, fanart, boxart, screenshot) " + "VALUES (:SYSTEM, :ROMNAME, :GAMENAME, :GENRE, :YEAR, " + ":GAMETYPE, :ROMPATH, :COUNTRY, :CRC32, '1', '1', :PLOT, " + ":PUBLISHER, :VERSION, :FANART, :BOXART, :SCREENSHOT)"); + + query.bindValue(":SYSTEM",System()); + query.bindValue(":ROMNAME",Romname()); + query.bindValue(":GAMENAME",Gamename()); + query.bindValue(":GENRE",Genre()); + query.bindValue(":YEAR",Year()); + query.bindValue(":GAMETYPE",GameType()); + query.bindValue(":ROMPATH",Rompath()); + query.bindValue(":COUNTRY",Country()); + query.bindValue(":CRC32", QString()); + query.bindValue(":PLOT", Plot()); + query.bindValue(":PUBLISHER", Publisher()); + query.bindValue(":VERSION", Version()); + query.bindValue(":FANART", Fanart()); + query.bindValue(":BOXART", Boxart()); + query.bindValue(":SCREENSHOT", Screenshot()); } - - if (!query.next()) - return; - - QString t_gamename = query.value(0).toString(); - QString t_genre = query.value(1).toString(); - QString t_year = query.value(2).toString(); - QString t_country = query.value(3).toString(); - QString t_plot = query.value(4).toString(); - QString t_publisher = query.value(5).toString(); - bool t_favourite = query.value(6).toBool(); - QString t_screenshot = query.value(7).toString(); - QString t_fanart = query.value(8).toString(); - QString t_boxart = query.value(9).toString(); - QString t_inetref = query.value(10).toString(); - - if ((t_gamename != Gamename()) || (t_genre != Genre()) || - (t_year != Year()) || (t_country != Country()) || - (t_plot != Plot()) || (t_publisher != Publisher()) || - (t_favourite != Favorite()) || (t_screenshot != Screenshot()) || - (t_fanart != Fanart()) || (t_boxart != Boxart()) || - (t_inetref != Inetref())) + else { query.prepare("UPDATE gamemetadata " "SET version = 'CUSTOM', " @@ -84,12 +81,12 @@ void RomInfo::UpdateDatabase() query.bindValue(":INETREF", Inetref()); query.bindValue(":GAMETYPE", GameType()); query.bindValue(":ROMNAME", Romname()); + } - if (!query.exec()) - { - MythDB::DBError("RomInfo::UpdateDatabase", query); - return; - } + if (!query.exec()) + { + MythDB::DBError("RomInfo::SaveToDatabase", query); + return; } } @@ -243,7 +240,7 @@ void RomInfo::fillData() QString thequery = "SELECT system,gamename,genre,year,romname,favorite," "rompath,country,crc_value,diskcount,gametype,plot,publisher," - "version,screenshot,fanart,boxart,inetref FROM gamemetadata " + "version,screenshot,fanart,boxart,inetref,intid FROM gamemetadata " "WHERE gamename = :GAMENAME " + systemtype + " ORDER BY diskcount DESC"; @@ -271,6 +268,7 @@ void RomInfo::fillData() setFanart(query.value(15).toString()); setBoxart(query.value(16).toString()); setInetref(query.value(17).toString()); + setId(query.value(18).toInt()); } setRomCount(romInDB(romname,gametype)); @@ -299,3 +297,61 @@ void RomInfo::fillData() } } +QList RomInfo::GetAllRomInfo() +{ + QList ret; + + MSqlQuery query(MSqlQuery::InitCon()); + + QString querystr = "SELECT intid,system,romname,gamename,genre,year,publisher," + "favorite,rompath,screenshot,fanart,plot,boxart," + "gametype,diskcount,country,crc_value,inetref,display," + "version FROM gamemetadata ORDER BY diskcount DESC"; + + query.prepare(querystr); + + if (!query.exec()) + { + MythDB::DBError("GetAllRomInfo", query); + return ret; + } + + while (query.next()) + { + RomInfo *add = new RomInfo( + query.value(0).toInt(), + query.value(2).toString(), + query.value(1).toString(), + query.value(3).toString(), + query.value(4).toString(), + query.value(5).toString(), + query.value(7).toBool(), + query.value(8).toString(), + query.value(15).toString(), + query.value(16).toString(), + query.value(14).toInt(), + query.value(13).toString(), + 0, QString(), + query.value(11).toString(), + query.value(6).toString(), + query.value(19).toString(), + query.value(9).toString(), + query.value(10).toString(), + query.value(12).toString(), + query.value(17).toString()); + ret.append(add); + } + + return ret; +} + +QString RomInfo::toString() +{ + return QString ("Rom Info:\n" + "ID: %1\n" + "Game Name: %2\n" + "Rom Name: %3\n" + "Rom Path: %4") + .arg(Id()).arg(Gamename()) + .arg(Romname()).arg(Rompath()); +} diff --git a/mythplugins/mythgame/mythgame/rominfo.h b/mythplugins/mythgame/mythgame/rominfo.h index 4868ccfd0ed..fac28753098 100644 --- a/mythplugins/mythgame/mythgame/rominfo.h +++ b/mythplugins/mythgame/mythgame/rominfo.h @@ -3,13 +3,16 @@ #include #include +#include int romInDB(QString rom, QString gametype); class RomInfo { public: - RomInfo(QString lromname = "", QString lsystem = "", QString lgamename ="", + static QList GetAllRomInfo(); + + RomInfo(int lid = 0, QString lromname = "", QString lsystem = "", QString lgamename ="", QString lgenre = "", QString lyear = "", bool lfavorite = FALSE, QString lrompath = "", QString lcountry ="", QString lcrc_value = "", int ldiskcount = 0, QString lgametype = "", int lromcount = 0, @@ -17,6 +20,7 @@ class RomInfo QString lversion = "", QString lscreenshot = "", QString lfanart = "", QString lboxart = "", QString linetref = "") { + id = lid; romname = lromname; system = lsystem; gamename = lgamename; @@ -41,6 +45,7 @@ class RomInfo RomInfo(const RomInfo &lhs) { + id = lhs.id; romname = lhs.romname; system = lhs.system; gamename = lhs.gamename; @@ -67,6 +72,9 @@ class RomInfo bool FindImage(QString BaseFileName, QString *result); + int Id() const { return id; } + void setId(const int &lid) { id = lid; } + QString Rompath() const { return rompath; } void setRompath(const QString &lrompath) { rompath = lrompath; } @@ -128,12 +136,14 @@ class RomInfo void setFavorite(bool updateDatabase = false); QString getExtension(); + QString toString(); void setField(QString field, QString data); void fillData(); - void UpdateDatabase(); + void SaveToDatabase(); protected: + int id; QString romname; QString system; QString gamename; From 68df557d4793ec88d538108fd58312de1fe533fd Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sun, 7 Aug 2011 20:34:09 -0400 Subject: [PATCH 27/49] Convert NULL strings to empty strings in settings table updates. --- mythtv/libs/libmythbase/mythdb.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mythtv/libs/libmythbase/mythdb.cpp b/mythtv/libs/libmythbase/mythdb.cpp index cbfaa183acc..6810304f76c 100644 --- a/mythtv/libs/libmythbase/mythdb.cpp +++ b/mythtv/libs/libmythbase/mythdb.cpp @@ -264,7 +264,7 @@ void MythDB::SaveSetting(const QString &key, const QString &newValue) } bool MythDB::SaveSettingOnHost(const QString &key, - const QString &newValue, + const QString &newValueRaw, const QString &host) { QString LOC = QString("SaveSettingOnHost('%1') ").arg(key); @@ -274,6 +274,8 @@ bool MythDB::SaveSettingOnHost(const QString &key, return false; } + QString newValue = (newValueRaw.isNull()) ? "" : newValueRaw; + if (d->ignoreDatabase) { if (host.toLower() == d->m_localhostname) @@ -696,8 +698,9 @@ double MythDB::GetFloatSettingOnHost(const QString &key, const QString &host) return (retval == sentinel) ? 0.0 : retval.toDouble(); } -void MythDB::SetSetting(const QString &key, const QString &newValue) +void MythDB::SetSetting(const QString &key, const QString &newValueRaw) { + QString newValue = (newValueRaw.isNull()) ? "" : newValueRaw; d->m_settings->SetSetting(key, newValue); ClearSettingsCache(key); } From e5784de119e06c8c21fdead0fd728fe773f7f6f0 Mon Sep 17 00:00:00 2001 From: Gavin Hurlbut Date: Sun, 7 Aug 2011 17:40:50 -0700 Subject: [PATCH 28/49] Fix HTTP Proxy usage. When we setup the http proxy, we were using as a type HttpProxy, when it should have been HttpCachingProxy (as we are using it *only* for HTTP requests). This allowed when we did a listen that it would try to proxy the incoming connections as far as I can tell. Also, to be absolutely sure, when we use a MythServer or the HTTPServer, we now set the connection's proxy to NoProxy before calling the listen. This keeps it from even trying. Fixes #9970 --- mythtv/libs/libmythbase/util.cpp | 2 +- mythtv/libs/libmythprotoserver/mythsocketmanager.cpp | 2 ++ mythtv/programs/mythbackend/mainserver.cpp | 2 ++ mythtv/programs/mythbackend/mediaserver.cpp | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mythtv/libs/libmythbase/util.cpp b/mythtv/libs/libmythbase/util.cpp index 917c54799cd..d00af0dcecc 100644 --- a/mythtv/libs/libmythbase/util.cpp +++ b/mythtv/libs/libmythbase/util.cpp @@ -1489,7 +1489,7 @@ void setHttpProxy(void) .arg(url.userName()).arg(url.password()) .arg(host).arg(port)); #endif - p = QNetworkProxy(QNetworkProxy::HttpProxy, + p = QNetworkProxy(QNetworkProxy::HttpCachingProxy, host, port, url.userName(), url.password()); QNetworkProxy::setApplicationProxy(p); return; diff --git a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp index b18eebcdcea..0cf7ed83a8e 100644 --- a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp +++ b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp @@ -10,6 +10,7 @@ using namespace std; #include #include #include +#include // MythTV #include "mythsocketmanager.h" @@ -144,6 +145,7 @@ bool MythSocketManager::Listen(int port) } m_server = new MythServer(); + m_server->setProxy(QNetworkProxy::NoProxy); if (!m_server->listen(gCoreContext->MythHostAddressAny(), port)) { LOG(VB_GENERAL, LOG_ERR, QString("Failed to bind port %1.").arg(port)); diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp index 7e3193b342b..b4ce3a38c3a 100644 --- a/mythtv/programs/mythbackend/mainserver.cpp +++ b/mythtv/programs/mythbackend/mainserver.cpp @@ -37,6 +37,7 @@ using namespace std; #include #include #include +#include #include "previewgeneratorqueue.h" #include "exitcodes.h" @@ -206,6 +207,7 @@ MainServer::MainServer(bool master, int port, gCoreContext->GetNumSetting("MasterBackendOverride", 0); mythserver = new MythServer(); + mythserver->setProxy(QNetworkProxy::NoProxy); if (!mythserver->listen(gCoreContext->MythHostAddressAny(), port)) { LOG(VB_GENERAL, LOG_ERR, QString("Failed to bind port %1. Exiting.") diff --git a/mythtv/programs/mythbackend/mediaserver.cpp b/mythtv/programs/mythbackend/mediaserver.cpp index c039017a9d3..3c1964dd997 100644 --- a/mythtv/programs/mythbackend/mediaserver.cpp +++ b/mythtv/programs/mythbackend/mediaserver.cpp @@ -18,6 +18,7 @@ #include "upnpcdsvideo.h" #include +#include #include "serviceHosts/mythServiceHost.h" #include "serviceHosts/guideServiceHost.h" @@ -72,6 +73,7 @@ void MediaServer::Init(bool bIsMaster, bool bDisableUPnp /* = FALSE */) if (!m_pHttpServer->isListening()) { + m_pHttpServer->setProxy(QNetworkProxy::NoProxy); if (!m_pHttpServer->listen(gCoreContext->MythHostAddressAny(), nPort)) { LOG(VB_GENERAL, LOG_ERR, "MediaServer::HttpServer Create Error"); From e03fc09b04061b4019f4c2dcbe8a60d870a9f024 Mon Sep 17 00:00:00 2001 From: Gavin Hurlbut Date: Mon, 8 Aug 2011 00:08:32 -0700 Subject: [PATCH 29/49] Silence the NULL hostname error in jobqueue Make it initialize the jobHost to QString("") now that we are being more careful about passing NULL. When we want to send jobs to any host, "" should work. --- mythtv/libs/libmythtv/jobqueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythtv/libs/libmythtv/jobqueue.cpp b/mythtv/libs/libmythtv/jobqueue.cpp index c4e867d7544..e8977b8967b 100644 --- a/mythtv/libs/libmythtv/jobqueue.cpp +++ b/mythtv/libs/libmythtv/jobqueue.cpp @@ -489,7 +489,7 @@ bool JobQueue::QueueRecordingJobs(const RecordingInfo &recinfo, int jobTypes) if (jobTypes != JOB_NONE) { - QString jobHost; + QString jobHost = QString(""); if (gCoreContext->GetNumSetting("JobsRunOnRecordHost", 0)) jobHost = recinfo.GetHostname(); From 6e37202bb8ffcbc35e62887a4cb9887afa5ab7e5 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 8 Aug 2011 13:55:04 +0100 Subject: [PATCH 30/49] Support reading of ID3v2 or ID3v1 tags in FLAC If an ID3 tag exists then we will read and write to that instead of the Vorbis comment tag. This includes support for albumart in ID3v2 tags found in FLAC files. The implementation is a little messy but I plan to refactor the metaio classes and this will do for now. --- .../mythmusic/mythmusic/avfdecoder.cpp | 8 +- mythplugins/mythmusic/mythmusic/metadata.cpp | 7 +- mythplugins/mythmusic/mythmusic/metaio.h | 6 + .../mythmusic/mythmusic/metaioflacvorbis.cpp | 28 +- .../mythmusic/mythmusic/metaioflacvorbis.h | 2 + mythplugins/mythmusic/mythmusic/metaioid3.cpp | 297 +++++++++++------- mythplugins/mythmusic/mythmusic/metaioid3.h | 29 +- .../mythmusic/mythmusic/metaiooggvorbis.cpp | 8 +- .../mythmusic/mythmusic/metaiotaglib.cpp | 8 +- .../mythmusic/mythmusic/metaiotaglib.h | 5 +- .../mythmusic/mythmusic/metaiowavpack.cpp | 8 +- 11 files changed, 262 insertions(+), 144 deletions(-) diff --git a/mythplugins/mythmusic/mythmusic/avfdecoder.cpp b/mythplugins/mythmusic/mythmusic/avfdecoder.cpp index 2e0e80f8dec..6327f1ff91d 100644 --- a/mythplugins/mythmusic/mythmusic/avfdecoder.cpp +++ b/mythplugins/mythmusic/mythmusic/avfdecoder.cpp @@ -508,7 +508,13 @@ MetaIO* avfDecoder::doCreateTagger(void) else if (extension == "ogg" || extension == "oga") return new MetaIOOggVorbis(); else if (extension == "flac") - return new MetaIOFLACVorbis(); + { + MetaIOID3 *file = new MetaIOID3(); + if (file->TagExists(filename)) + return file; + else + return new MetaIOFLACVorbis(); + } else if (extension == "m4a") return new MetaIOMP4(); else if (extension == "wv") diff --git a/mythplugins/mythmusic/mythmusic/metadata.cpp b/mythplugins/mythmusic/mythmusic/metadata.cpp index f0279df1edb..986d97cbf4b 100644 --- a/mythplugins/mythmusic/mythmusic/metadata.cpp +++ b/mythplugins/mythmusic/mythmusic/metadata.cpp @@ -917,7 +917,12 @@ MetaIO* Metadata::getTagger(void) else if (extension == "ogg" || extension == "oga") return &metaIOOggVorbis; else if (extension == "flac") - return &metaIOFLACVorbis; + { + if (metaIOID3.TagExists(m_filename)) + return &metaIOID3; + else + return &metaIOFLACVorbis; + } else if (extension == "m4a") return &metaIOMP4; else if (extension == "wv") diff --git a/mythplugins/mythmusic/mythmusic/metaio.h b/mythplugins/mythmusic/mythmusic/metaio.h index a0ed5e39bfb..b1ab4afc9db 100644 --- a/mythplugins/mythmusic/mythmusic/metaio.h +++ b/mythplugins/mythmusic/mythmusic/metaio.h @@ -101,6 +101,12 @@ class MetaIO void readFromFilename(Metadata *metadata); + virtual bool TagExists(const QString &filename) + { + (void)filename; + return false; + } + protected: private: diff --git a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp index 035bd3beeb2..82589aea4f5 100644 --- a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp +++ b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp @@ -52,7 +52,7 @@ bool MetaIOFLACVorbis::write(Metadata* mdata) if (!flacfile) return false; - TagLib::Ogg::XiphComment *tag = flacfile->xiphComment(); + TagLib::Ogg::XiphComment *tag = flacfile->xiphComment(true); if (!tag) { @@ -136,15 +136,27 @@ Metadata* MetaIOFLACVorbis::read(QString filename) metadata->setCompilation(compilation); if (metadata->Length() <= 0) - { - TagLib::FileRef *fileref = new TagLib::FileRef(flacfile); - metadata->setLength(getTrackLength(fileref)); - // FileRef takes ownership of flacfile, and is responsible for it's - // deletion. Messy. - delete fileref; - } + metadata->setLength(getTrackLength(flacfile)); else delete flacfile; return metadata; } + +bool MetaIOFLACVorbis::TagExists(const QString &filename) +{ + TagLib::FLAC::File *flacfile = OpenFile(filename); + + if (!flacfile) + return false; + + TagLib::Ogg::XiphComment *tag = flacfile->xiphComment(false); + + bool retval = false; + if (tag && !tag->isEmpty()) + retval = true; + + delete flacfile; + + return retval; +} diff --git a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h index e0d3c4fb234..a6445ed2b84 100644 --- a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h +++ b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h @@ -27,6 +27,8 @@ class MetaIOFLACVorbis : public MetaIOTagLib bool write(Metadata* mdata); Metadata* read(QString filename); + virtual bool TagExists(const QString &filename); + private: TagLib::FLAC::File *OpenFile(const QString &filename); }; diff --git a/mythplugins/mythmusic/mythmusic/metaioid3.cpp b/mythplugins/mythmusic/mythmusic/metaioid3.cpp index c914da0ff49..50d8e8c34ad 100644 --- a/mythplugins/mythmusic/mythmusic/metaioid3.cpp +++ b/mythplugins/mythmusic/mythmusic/metaioid3.cpp @@ -2,19 +2,26 @@ #include "metaioid3.h" #include "metadata.h" -// Libmyth +// Libmythbase #include #include +// Taglib +#include +#include + const String email = "music@mythtv.org"; // TODO username/ip/hostname? MetaIOID3::MetaIOID3(void) - : MetaIOTagLib() + : MetaIOTagLib(), + m_file(NULL), m_fileType(kMPEG) + { } MetaIOID3::~MetaIOID3(void) { + CloseFile(); } /*! @@ -23,18 +30,124 @@ MetaIOID3::~MetaIOID3(void) * \param filename The filename * \returns A taglib file object for this format */ -TagLib::MPEG::File *MetaIOID3::OpenFile(const QString &filename) +bool MetaIOID3::OpenFile(const QString &filename, bool forWriting) { - QByteArray fname = filename.toLocal8Bit(); - TagLib::MPEG::File *mpegfile = new TagLib::MPEG::File(fname.constData()); + + + // Check if file is already opened + if (m_file && (m_filename == filename) && + (!forWriting || !m_file->readOnly())) + return true; + + if (m_file) + { + LOG(VB_FILE, LOG_DEBUG, + QString("MetaIO switch file: %1 New File: %2 Type: %3") + .arg(m_filename) + .arg(filename) + .arg(m_fileType)); + } + + // If a file is open but it's not the requested file then close it first + if (m_file) + CloseFile(); + + m_filename = filename; + + QString extension = m_filename.section('.', -1); + + if (extension.toLower() == "flac") + m_fileType = kFLAC; + else if (extension.toLower() == "mp3") + m_fileType = kMPEG; + else + return false; + + QByteArray fname = m_filename.toLocal8Bit(); + // Open the file + switch (m_fileType) + { + case kMPEG : + m_file = new TagLib::MPEG::File(fname.constData()); + break; + case kFLAC : + m_file = new TagLib::FLAC::File(fname.constData()); + break; + } - if (!mpegfile->isOpen()) + // If the requested file could not be opened then close it and return false + if (!m_file->isOpen() || (forWriting && m_file->readOnly())) { - delete mpegfile; - mpegfile = NULL; + if (m_file->isOpen()) + LOG(VB_FILE, LOG_NOTICE, + QString("Could not open file for writing: %1").arg(m_filename)); + else + LOG(VB_FILE, LOG_ERR, + QString("Could not open file: %1").arg(m_filename)); + + CloseFile(); + return false; } - return mpegfile; + return true; +} + +bool MetaIOID3::SaveFile() +{ + if (!m_file) + return false; + + bool retval = m_file->save(); + + return retval; +} + +void MetaIOID3::CloseFile() +{ + LOG(VB_FILE, LOG_DEBUG, QString("MetaIO Close file: %1") + .arg(m_file->name())); + delete m_file; + m_file = NULL; + m_fileType = kMPEG; + m_filename.clear(); +} + +TagLib::ID3v2::Tag* MetaIOID3::GetID3v2Tag(bool create) +{ + if (!m_file) + return NULL; + + TagLib::ID3v2::Tag *tag = NULL; + switch (m_fileType) + { + case kMPEG : + tag = (static_cast(m_file))->ID3v2Tag(create); + break; + case kFLAC : + tag = (static_cast(m_file))->ID3v2Tag(create); + break; + } + + return tag; +} + +TagLib::ID3v1::Tag* MetaIOID3::GetID3v1Tag(bool create) +{ + if (!m_file) + return NULL; + + TagLib::ID3v1::Tag *tag = NULL; + switch (m_fileType) + { + case kMPEG : + tag = (static_cast(m_file))->ID3v1Tag(create); + break; + case kFLAC : + // Flac doesn't support ID3v1 + break; + } + + return tag; } /*! @@ -42,18 +155,13 @@ TagLib::MPEG::File *MetaIOID3::OpenFile(const QString &filename) */ bool MetaIOID3::write(Metadata* mdata) { - TagLib::MPEG::File *mpegfile = OpenFile(mdata->Filename()); - - if (!mpegfile) + if (!OpenFile(mdata->Filename()), true) return false; - TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); + TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (!tag) - { - delete mpegfile; return false; - } WriteGenericMetadata(tag, mdata); @@ -111,11 +219,10 @@ bool MetaIOID3::write(Metadata* mdata) tpe2frame->setText(QStringToTString(mdata->CompilationArtist())); } - bool result = mpegfile->save(); - - delete mpegfile; + if (!SaveFile()) + return false; - return result; + return true; } /*! @@ -123,29 +230,19 @@ bool MetaIOID3::write(Metadata* mdata) */ Metadata *MetaIOID3::read(QString filename) { - TagLib::MPEG::File *mpegfile = OpenFile(filename); - - if (!mpegfile) + if (!OpenFile(filename)) return NULL; - TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); + TagLib::ID3v2::Tag *tag = GetID3v2Tag(true); // Create tag if none are found - if (!tag) - { - delete mpegfile; - return NULL; - } - - // if there is no ID3v2 tag, try to read the ID3v1 tag and copy it to the ID3v2 tag structure + // if there is no ID3v2 tag, try to read the ID3v1 tag and copy it to + // the ID3v2 tag structure if (tag->isEmpty()) { - TagLib::ID3v1::Tag *tag_v1 = mpegfile->ID3v1Tag(); + TagLib::ID3v1::Tag *tag_v1 = GetID3v1Tag(); if (!tag_v1) - { - delete mpegfile; return NULL; - } if (!tag_v1->isEmpty()) { @@ -219,13 +316,8 @@ Metadata *MetaIOID3::read(QString filename) // 27 hours metadata->setCompilation(compilation); - - TagLib::FileRef *fileref = new TagLib::FileRef(mpegfile); - metadata->setLength(getTrackLength(fileref)); - // FileRef takes ownership of mpegfile, and is responsible for it's - // deletion. Messy. - delete fileref; - + metadata->setLength(getTrackLength(m_file)); + return metadata; } @@ -265,15 +357,13 @@ QImage* MetaIOID3::getAlbumArt(QString filename, ImageType type) } QByteArray fname = filename.toLocal8Bit(); - TagLib::MPEG::File *mpegfile = new TagLib::MPEG::File(fname.constData()); - if (mpegfile) + if (OpenFile(fname.constData())) { - if (mpegfile->isOpen() - && !mpegfile->ID3v2Tag()->frameListMap()["APIC"].isEmpty()) + TagLib::ID3v2::Tag *tag = GetID3v2Tag(); + if (tag && !tag->frameListMap()["APIC"].isEmpty()) { - TagLib::ID3v2::FrameList apicframes = - mpegfile->ID3v2Tag()->frameListMap()["APIC"]; + TagLib::ID3v2::FrameList apicframes = tag->frameListMap()["APIC"]; for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin(); it != apicframes.end(); ++it) @@ -288,8 +378,6 @@ QImage* MetaIOID3::getAlbumArt(QString filename, ImageType type) } } } - - delete mpegfile; } delete picture; @@ -307,21 +395,15 @@ AlbumArtList MetaIOID3::getAlbumArtList(const QString &filename) { AlbumArtList imageList; QByteArray fname = filename.toLocal8Bit(); - TagLib::MPEG::File *mpegfile = new TagLib::MPEG::File(fname.constData()); - if (mpegfile) + if (OpenFile(fname.constData())) { - TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); + TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (!tag) - { - delete mpegfile; return imageList; - } imageList = readAlbumArt(tag); - - delete mpegfile; } return imageList; @@ -368,7 +450,8 @@ AlbumArtList MetaIOID3::readAlbumArt(TagLib::ID3v2::Tag *tag) art->embedded = true; - QString ext = getExtFromMimeType(TStringToQString(frame->mimeType()).toLower()); + QString ext = getExtFromMimeType( + TStringToQString(frame->mimeType()).toLower()); switch (frame->type()) { @@ -454,7 +537,8 @@ AttachedPictureFrame* MetaIOID3::findAPIC(TagLib::ID3v2::Tag *tag, * * \Note We always save the image in JPEG format */ -bool MetaIOID3::writeAlbumArt(const QString &filename, const AlbumArtImage *albumart) +bool MetaIOID3::writeAlbumArt(const QString &filename, + const AlbumArtImage *albumart) { if (filename.isEmpty() || !albumart) return false; @@ -486,20 +570,17 @@ bool MetaIOID3::writeAlbumArt(const QString &filename, const AlbumArtImage *albu break; } - TagLib::MPEG::File *mpegfile = OpenFile(filename); - - if (!mpegfile) + QByteArray fname = filename.toLocal8Bit(); + if (!OpenFile(fname.constData(), true)) return false; - TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); + TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (!tag) - { - delete mpegfile; return false; - } - AttachedPictureFrame *apic = findAPIC(tag, type, QStringToTString(albumart->description)); + AttachedPictureFrame *apic = findAPIC(tag, type, + QStringToTString(albumart->description)); if (!apic) { @@ -517,8 +598,8 @@ bool MetaIOID3::writeAlbumArt(const QString &filename, const AlbumArtImage *albu apic->setPicture(bytevector); apic->setDescription(QStringToTString(albumart->description)); - mpegfile->save(); - delete mpegfile; + if (!SaveFile()) + return false; return true; } @@ -530,7 +611,8 @@ bool MetaIOID3::writeAlbumArt(const QString &filename, const AlbumArtImage *albu * \param albumart The Album Art image to remove * \returns True if successful */ -bool MetaIOID3::removeAlbumArt(const QString &filename, const AlbumArtImage *albumart) +bool MetaIOID3::removeAlbumArt(const QString &filename, + const AlbumArtImage *albumart) { if (filename.isEmpty() || !albumart) return false; @@ -555,35 +637,30 @@ bool MetaIOID3::removeAlbumArt(const QString &filename, const AlbumArtImage *alb break; } - TagLib::MPEG::File *mpegfile = OpenFile(filename); - - if (!mpegfile) + QByteArray fname = filename.toLocal8Bit(); + if (!OpenFile(fname.constData(), true)) return false; - TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); + TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (!tag) - { - delete mpegfile; return false; - } - AttachedPictureFrame *apic = findAPIC(tag, type, QStringToTString(albumart->description)); + AttachedPictureFrame *apic = findAPIC(tag, type, + QStringToTString(albumart->description)); if (!apic) - { - delete mpegfile; return false; - } tag->removeFrame(apic); - mpegfile->save(); - delete mpegfile; + if (!SaveFile()) + return false; return true; } -bool MetaIOID3::changeImageType(const QString &filename, const AlbumArtImage* albumart, +bool MetaIOID3::changeImageType(const QString &filename, + const AlbumArtImage* albumart, ImageType newType) { if (!albumart) @@ -612,25 +689,19 @@ bool MetaIOID3::changeImageType(const QString &filename, const AlbumArtImage* al break; } - TagLib::MPEG::File *mpegfile = OpenFile(filename); - - if (!mpegfile) + QByteArray fname = filename.toLocal8Bit(); + if (!OpenFile(fname.constData(), true)) return false; - TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); + TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (!tag) - { - delete mpegfile; return false; - } - AttachedPictureFrame *apic = findAPIC(tag, type, QStringToTString(albumart->description)); + AttachedPictureFrame *apic = findAPIC(tag, type, + QStringToTString(albumart->description)); if (!apic) - { - delete mpegfile; return false; - } // set the new image type switch (newType) @@ -652,8 +723,8 @@ bool MetaIOID3::changeImageType(const QString &filename, const AlbumArtImage* al break; } - mpegfile->save(); - delete mpegfile; + if (!SaveFile()) + return false; return true; } @@ -726,23 +797,20 @@ bool MetaIOID3::writeVolatileMetadata(const Metadata* mdata) QString filename = mdata->Filename(); int rating = mdata->Rating(); int playcount = mdata->PlayCount(); - TagLib::MPEG::File *mpegfile = OpenFile(filename); - if (!mpegfile) + QByteArray fname = filename.toLocal8Bit(); + if (!OpenFile(fname.constData(), true)) return false; - TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); + TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (!tag) - { - delete mpegfile; return false; - } bool result = (writeRating(tag, rating) && writePlayCount(tag, playcount)); - mpegfile->save(); - delete mpegfile; + if (!SaveFile()) + return false; return result; } @@ -766,3 +834,20 @@ bool MetaIOID3::writeRating(TagLib::ID3v2::Tag *tag, int rating) return true; } + +bool MetaIOID3::TagExists(const QString &filename) +{ + if (!OpenFile(filename)) + return false; + + TagLib::ID3v1::Tag *v1_tag = GetID3v1Tag(); + TagLib::ID3v2::Tag *v2_tag = GetID3v2Tag(); + + bool retval = false; + + if ((v2_tag && !v2_tag->isEmpty()) || + (v1_tag && !v1_tag->isEmpty())) + retval = true; + + return retval; +} diff --git a/mythplugins/mythmusic/mythmusic/metaioid3.h b/mythplugins/mythmusic/mythmusic/metaioid3.h index 52a1f242426..9a5b7ccf3a8 100644 --- a/mythplugins/mythmusic/mythmusic/metaioid3.h +++ b/mythplugins/mythmusic/mythmusic/metaioid3.h @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include // QT @@ -22,7 +20,6 @@ using TagLib::ID3v2::UserTextIdentificationFrame; using TagLib::ID3v2::TextIdentificationFrame; using TagLib::ID3v2::PopularimeterFrame; using TagLib::ID3v2::AttachedPictureFrame; -using TagLib::MPEG::Properties; /*! * \class MetaIOID3 @@ -39,7 +36,7 @@ class MetaIOID3 : public MetaIOTagLib MetaIOID3(void); virtual ~MetaIOID3(void); - bool write(Metadata* mdata); + virtual bool write(Metadata* mdata); bool writeVolatileMetadata(const Metadata* mdata); bool writeAlbumArt(const QString &filename, const AlbumArtImage *albumart); @@ -51,20 +48,36 @@ class MetaIOID3 : public MetaIOTagLib bool supportsEmbeddedImages(void) { return true; } - bool changeImageType(const QString &filename, const AlbumArtImage *albumart, ImageType newType); + bool changeImageType(const QString &filename, const AlbumArtImage *albumart, + ImageType newType); + + virtual bool TagExists(const QString &filename); private: - TagLib::MPEG::File *OpenFile(const QString &filename); + bool OpenFile(const QString &filename, bool forWriting = false); + bool SaveFile(); + void CloseFile(); + + TagLib::ID3v2::Tag* GetID3v2Tag(bool create = false); + TagLib::ID3v1::Tag* GetID3v1Tag(bool create = false); bool writePlayCount(TagLib::ID3v2::Tag *tag, int playcount); bool writeRating(TagLib::ID3v2::Tag *tag, int rating); AlbumArtList readAlbumArt(TagLib::ID3v2::Tag *tag); - UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, const String &description); + UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, + const String &description); PopularimeterFrame* findPOPM(TagLib::ID3v2::Tag *tag, const String &email); - AttachedPictureFrame* findAPIC(TagLib::ID3v2::Tag *tag, const AttachedPictureFrame::Type &type, + AttachedPictureFrame* findAPIC(TagLib::ID3v2::Tag *tag, + const AttachedPictureFrame::Type &type, const String &description = String::null); QString getExtFromMimeType(const QString &mimeType); + + TagLib::File *m_file; + QString m_filename; + + typedef enum { kMPEG, kFLAC } TagType; + TagType m_fileType; }; #endif diff --git a/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp b/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp index ce1f0dc746b..dc730606855 100644 --- a/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp +++ b/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp @@ -134,13 +134,7 @@ Metadata* MetaIOOggVorbis::read(QString filename) metadata->setCompilation(compilation); if (metadata->Length() <= 0) - { - TagLib::FileRef *fileref = new TagLib::FileRef(oggfile); - metadata->setLength(getTrackLength(fileref)); - // FileRef takes ownership of oggfile, and is responsible for it's - // deletion. Messy. - delete fileref; - } + metadata->setLength(getTrackLength(oggfile)); else delete oggfile; diff --git a/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp b/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp index ed904ac0617..968ca6ad61d 100644 --- a/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp +++ b/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp @@ -13,6 +13,7 @@ #include #include #include +#include /* Redefine the TString conversion macros */ #undef QStringToTString @@ -98,7 +99,7 @@ void MetaIOTagLib::ReadGenericMetadata(Tag *tag, Metadata *metadata) * \param file Pointer to file object * \returns An integer (signed!) to represent the length in milliseconds. */ -int MetaIOTagLib::getTrackLength(TagLib::FileRef *file) +int MetaIOTagLib::getTrackLength(TagLib::File *file) { int milliseconds = 0; @@ -119,8 +120,9 @@ int MetaIOTagLib::getTrackLength(QString filename) int milliseconds = 0; QByteArray fname = filename.toLocal8Bit(); TagLib::FileRef *file = new TagLib::FileRef(fname.constData()); - - milliseconds = getTrackLength(file); + + if (file && file->audioProperties()) + milliseconds = file->audioProperties()->length() * 1000; // If we didn't get a valid length, add the metadata but show warning. if (milliseconds <= 1000) diff --git a/mythplugins/mythmusic/mythmusic/metaiotaglib.h b/mythplugins/mythmusic/mythmusic/metaiotaglib.h index e7173b963b4..09580eceeff 100644 --- a/mythplugins/mythmusic/mythmusic/metaiotaglib.h +++ b/mythplugins/mythmusic/mythmusic/metaiotaglib.h @@ -7,7 +7,6 @@ // Taglib #include -#include using TagLib::File; using TagLib::Tag; @@ -26,9 +25,9 @@ class MetaIOTagLib : public MetaIO virtual bool write(Metadata* mdata) = 0; virtual Metadata* read(QString filename) = 0; - + protected: - int getTrackLength(TagLib::FileRef *file); + int getTrackLength(TagLib::File *file); int getTrackLength(QString filename); void ReadGenericMetadata(TagLib::Tag *tag, Metadata *metadata); void WriteGenericMetadata(TagLib::Tag *tag, Metadata *metadata); diff --git a/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp b/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp index 6648c00c05d..5103a2d5c37 100644 --- a/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp +++ b/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp @@ -115,13 +115,7 @@ Metadata* MetaIOWavPack::read(QString filename) metadata->setCompilation(compilation); if (metadata->Length() <= 0) - { - TagLib::FileRef *fileref = new TagLib::FileRef(wpfile); - metadata->setLength(getTrackLength(fileref)); - // FileRef takes ownership of wpfile, and is responsible for it's - // deletion. Messy. - delete fileref; - } + metadata->setLength(getTrackLength(wpfile)); else delete wpfile; From a160548762955d175878f1bbd10d7e146e9460da Mon Sep 17 00:00:00 2001 From: Robert McNamara Date: Mon, 8 Aug 2011 06:25:24 -0700 Subject: [PATCH 31/49] MythGame: Add an in-menu Game Scan. This is a MythUI game scanner implementation which does a couple of relevant things. Firstly and most importantly, it allows the user to perform game scans in the "Play Games" UI rather than hunting down the old game scanner in the Setup Menus. It also makes certain Metadata methods more parallel to the metadata functions in libmythmetadata for simplicity (SaveToDatabase, DeleteFromDatabase, etc. called on the metadata object) The old scanner is left in place for the short term since this one is a ground-up reimplementation and I may have missed a few things or done something in some wrong way. For my purposes, though, it's working properly. I do still have a bit more to do to add a few random features of the old scanner (automatically detecting screenshots, etc). This commit also does a little more work to extricate the UI code from the database code. As a result, there's still some repeated functionality here until I'm confident enough to rip out the old stuff in a later refactor. Still to do is more fully removing the DB code from the UI code, further cleanup of the new scanner, then a reimplementation of the UI code to parallel other MythTV metadata browsers (three view, etc). --- mythplugins/mythgame/mythgame/gamehandler.h | 4 +- mythplugins/mythgame/mythgame/gamescan.cpp | 264 ++++++++++++++++++++ mythplugins/mythgame/mythgame/gamescan.h | 93 +++++++ mythplugins/mythgame/mythgame/gameui.cpp | 67 +++-- mythplugins/mythgame/mythgame/gameui.h | 6 + mythplugins/mythgame/mythgame/mythgame.pro | 4 +- mythplugins/mythgame/mythgame/rominfo.cpp | 70 ++++++ mythplugins/mythgame/mythgame/rominfo.h | 3 + 8 files changed, 492 insertions(+), 19 deletions(-) create mode 100644 mythplugins/mythgame/mythgame/gamescan.cpp create mode 100644 mythplugins/mythgame/mythgame/gamescan.h diff --git a/mythplugins/mythgame/mythgame/gamehandler.h b/mythplugins/mythgame/mythgame/gamehandler.h index 63adbe092ff..ffd97ad57ac 100644 --- a/mythplugins/mythgame/mythgame/gamehandler.h +++ b/mythplugins/mythgame/mythgame/gamehandler.h @@ -107,12 +107,14 @@ class GameHandler : public QObject QString SystemScreenShots() const { return screenshots; } uint GamePlayerID() const { return gameplayerid; } QString GameType() const { return gametype; } + QStringList ValidExtensions() const { return validextensions; } void clearAllMetadata(void); - protected: static GameHandler* GetHandler(RomInfo *rominfo); static GameHandler* GetHandlerByName(QString systemname); + + protected: void customEvent(QEvent *event); bool rebuild; diff --git a/mythplugins/mythgame/mythgame/gamescan.cpp b/mythplugins/mythgame/mythgame/gamescan.cpp new file mode 100644 index 00000000000..667b637562d --- /dev/null +++ b/mythplugins/mythgame/mythgame/gamescan.cpp @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gamescan.h" +#include "gamehandler.h" +#include "rominfo.h" + +class MythUIProgressDialog; + +GameScannerThread::GameScannerThread(QObject *parent) : + m_DBDataChanged(false) +{ + m_parent = parent; + m_HasGUI = gCoreContext->HasGUI(); +} + +GameScannerThread::~GameScannerThread() +{ +} + +void GameScannerThread::run() +{ + threadRegister("GameScanner"); + + LOG(VB_GENERAL, LOG_INFO, QString("Beginning Game Scan.")); + + m_files.clear(); + m_remove.clear(); + m_dbgames = RomInfo::GetAllRomInfo(); + + buildFileList(); + verifyFiles(); + updateDB(); + + threadDeregister(); +} + + +void GameScannerThread::removeOrphan(const int id) +{ + RomInfo *info = RomInfo::GetRomInfoById(id); + if (info) + { + info->DeleteFromDatabase(); + delete info; + info = NULL; + } +} + +void GameScannerThread::verifyFiles() +{ + int counter = 0; + + if (m_HasGUI) + SendProgressEvent(counter, (uint)m_dbgames.count(), + tr("Verifying game files")); + + // For every file we know about, check to see if it still exists. + for (QList::iterator p = m_dbgames.begin(); + p != m_dbgames.end(); ++p) + { + RomInfo *info = *p; + QString romfile = info->Romname(); + QString system = info->System(); + QString gametype = info->GameType(); + if (!romfile.isEmpty()) + { + bool found = false; + for (QList::iterator p = m_files.begin(); + p != m_files.end(); ++p) + { + if ((*p).romfile == romfile && + (*p).gametype == gametype) + { + // We're done here, this file matches one in the DB + (*p).indb = true; + found = true; + continue; + } + } + if (!found) + { + m_remove.append(info->Id()); + } + } + if (m_HasGUI) + SendProgressEvent(++counter); + + delete info; + info = NULL; + } +} + +void GameScannerThread::updateDB() +{ + uint counter = 0; + if (m_HasGUI) + SendProgressEvent(counter, (uint)(m_files.size() + m_remove.size()), + tr("Updating game database")); + + for (QList::iterator p = m_files.begin(); + p != m_files.end(); ++p) + { + if (!(*p).indb) + { + RomInfo *add = new RomInfo(0, (*p).romfile, (*p).system, + (*p).romname, "", "", "", (*p).rompath, + "", "", 0, (*p).gametype, 0, "", "", "", + "", "", "", "", ""); + add->SaveToDatabase(); + m_DBDataChanged = true; + } + if (m_HasGUI) + SendProgressEvent(++counter); + } + + for (QList::iterator p = m_remove.begin(); + p != m_remove.end(); ++p) + { + removeOrphan(*p); + m_DBDataChanged = true; + } +} + +bool GameScannerThread::buildFileList() +{ + if (m_handlers.size() == 0) + return false; + + int counter = 0; + + if (m_HasGUI) + SendProgressEvent(counter, (uint)m_handlers.size(), + tr("Searching for games...")); + + for (QList::const_iterator iter = m_handlers.begin(); + iter != m_handlers.end(); ++iter) + { + QDir dir((*iter)->SystemRomPath()); + QStringList extensions = (*iter)->ValidExtensions(); + QStringList filters; + for (QStringList::iterator i = extensions.begin(); + i != extensions.end(); ++i) + { + filters.append(QString("*.%1").arg(*i)); + } + + dir.setNameFilters(filters); + dir.setFilter(QDir::Files | QDir::Readable | QDir::NoDotAndDotDot); + + QStringList files = dir.entryList(); + for (QStringList::iterator i = files.begin(); + i != files.end(); ++i) + { + RomFileInfo info; + info.system = (*iter)->SystemName(); + info.gametype = (*iter)->GameType(); + info.romfile = *i; + info.rompath = (*iter)->SystemRomPath(); + info.romname = QFileInfo(*i).baseName(); + info.indb = false; + m_files.append(info); + } + + if (m_HasGUI) + SendProgressEvent(++counter); + } + + return true; +} + +void GameScannerThread::SendProgressEvent(uint progress, uint total, + QString messsage) +{ + if (!m_dialog) + return; + + ProgressUpdateEvent *pue = new ProgressUpdateEvent(progress, total, + messsage); + QApplication::postEvent(m_dialog, pue); +} + +GameScanner::GameScanner() +{ + m_scanThread = new GameScannerThread(this); +} + +GameScanner::~GameScanner() +{ + if (m_scanThread && m_scanThread->wait()) + delete m_scanThread; +} + +void GameScanner::doScan(QList handlers) +{ + if (m_scanThread->isRunning()) + return; + + if (gCoreContext->HasGUI()) + { + MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); + + MythUIProgressDialog *progressDlg = new MythUIProgressDialog("", + popupStack, "gamescanprogressdialog"); + + if (progressDlg->Create()) + { + popupStack->AddScreen(progressDlg, false); + connect(m_scanThread, SIGNAL(finished()), + progressDlg, SLOT(Close())); + connect(m_scanThread, SIGNAL(finished()), + SLOT(finishedScan())); + } + else + { + delete progressDlg; + progressDlg = NULL; + } + m_scanThread->SetProgressDialog(progressDlg); + } + + m_scanThread->SetHandlers(handlers); + m_scanThread->start(); +} + +void GameScanner::doScanAll() +{ + QList hlist; + + MSqlQuery query(MSqlQuery::InitCon()); + query.prepare("SELECT DISTINCT playername FROM gameplayers " + "WHERE playername <> '';"); + + if (!query.exec()) + MythDB::DBError("doScanAll - selecting playername", query); + + while (query.next()) + { + QString name = query.value(0).toString(); + GameHandler *hnd = GameHandler::GetHandlerByName(name); + if (hnd) + hlist.append(hnd); + } + + doScan(hlist); +} + +void GameScanner::finishedScan() +{ + emit finished(m_scanThread->getDataChanged()); +} + +//////////////////////////////////////////////////////////////////////// diff --git a/mythplugins/mythgame/mythgame/gamescan.h b/mythplugins/mythgame/mythgame/gamescan.h new file mode 100644 index 00000000000..cd688b414fa --- /dev/null +++ b/mythplugins/mythgame/mythgame/gamescan.h @@ -0,0 +1,93 @@ +#ifndef GAMESCAN_H +#define GAMESCAN_H + +#include +#include + +#include // for moc +#include +#include +#include + +class QStringList; + +class MythUIProgressDialog; +class GameHandler; +class RomInfo; + +struct RomFileInfo +{ + QString system; + QString gametype; + QString romfile; + QString rompath; + QString romname; + bool indb; +}; + +typedef QList< RomFileInfo > RomFileInfoList; + +class GameScannerThread : public QThread +{ + Q_OBJECT + + public: + GameScannerThread(QObject *parent); + ~GameScannerThread(); + + void run(); + + void SetHandlers(QList handlers) { m_handlers = handlers; }; + void SetProgressDialog(MythUIProgressDialog *dialog) { m_dialog = dialog; }; + + bool getDataChanged() { return m_DBDataChanged; }; + + private: + + void removeOrphan(const int id); + + void verifyFiles(); + void updateDB(); + + bool buildFileList(); + + void SendProgressEvent(uint progress, uint total = 0, + QString message = QString()); + + QObject *m_parent; + bool m_HasGUI; + + QList m_handlers; + + RomFileInfoList m_files; + QList m_remove; + QList m_dbgames; + + MythUIProgressDialog *m_dialog; + + bool m_DBDataChanged; +}; + +class GameScanner : public QObject +{ + Q_OBJECT + + public: + GameScanner(); + ~GameScanner(); + + void doScan(QList handlers); + void doScanAll(void); + + signals: + void finished(bool); + + public slots: + void finishedScan(); + + private: + GameScannerThread *m_scanThread; + bool m_cancel; +}; + +#endif diff --git a/mythplugins/mythgame/mythgame/gameui.cpp b/mythplugins/mythgame/mythgame/gameui.cpp index 81606c66a7a..02c7610f500 100644 --- a/mythplugins/mythgame/mythgame/gameui.cpp +++ b/mythplugins/mythgame/mythgame/gameui.cpp @@ -18,6 +18,7 @@ #include "rominfo.h" #include "gamedetails.h" #include "romedit.h" +#include "gamescan.h" #include "gameui.h" class GameTreeInfo @@ -41,7 +42,8 @@ class GameTreeInfo Q_DECLARE_METATYPE(GameTreeInfo *) GameUI::GameUI(MythScreenStack *parent) - : MythScreenType(parent, "GameUI"), m_busyPopup(0) + : MythScreenType(parent, "GameUI"), m_busyPopup(0), + m_scanner(NULL) { m_popupStack = GetMythMainWindow()->GetStack("popup stack"); @@ -84,6 +86,15 @@ bool GameUI::Create() m_gameShowFileName = gCoreContext->GetSetting("GameShowFileNames").toInt(); + Load(); + + BuildFocusList(); + + return true; +} + +void GameUI::Load() +{ m_gameTree = new MythGenericTree("game root", 0, false); // create system filter to only select games where handlers are present @@ -157,10 +168,6 @@ bool GameUI::Create() m_gameTree->addNode(new_node); m_gameUITree->AssignTree(m_gameTree); - - BuildFocusList(); - - return true; } bool GameUI::keyPressEvent(QKeyEvent *event) @@ -412,17 +419,19 @@ void GameUI::showInfo() void GameUI::showMenu() { MythGenericTree *node = m_gameUITree->GetCurrentNode(); - if (isLeaf(node)) - { - MythScreenStack *popupStack = GetMythMainWindow()-> - GetStack("popup stack"); - MythDialogBox *showMenuPopup = + + MythScreenStack *popupStack = GetMythMainWindow()-> + GetStack("popup stack"); + MythDialogBox *showMenuPopup = new MythDialogBox(node->getString(), popupStack, "showMenuPopup"); - if (showMenuPopup->Create()) - { - showMenuPopup->SetReturnEvent(this, "showMenuPopup"); + if (showMenuPopup->Create()) + { + showMenuPopup->SetReturnEvent(this, "showMenuPopup"); + showMenuPopup->AddButton(tr("Scan For Changes")); + if (isLeaf(node)) + { RomInfo *romInfo = qVariantValue(node->GetData()); if (romInfo) { @@ -434,11 +443,11 @@ void GameUI::showMenu() showMenuPopup->AddButton(tr("Retrieve Details")); showMenuPopup->AddButton(tr("Edit Details")); } - popupStack->AddScreen(showMenuPopup); } - else - delete showMenuPopup; + popupStack->AddScreen(showMenuPopup); } + else + delete showMenuPopup; } void GameUI::searchStart(void) @@ -500,6 +509,10 @@ void GameUI::customEvent(QEvent *event) { edit(); } + if (resulttext == tr("Scan For Changes")) + { + doScan(); + } else if (resulttext == tr("Show Information")) { showInfo(); @@ -1068,3 +1081,25 @@ void GameUI::handleDownloadedImages(MetadataLookup *lookup) metadata->SaveToDatabase(); updateChangedNode(node, metadata); } + +void GameUI::doScan() +{ + if (!m_scanner) + m_scanner = new GameScanner(); + connect(m_scanner, SIGNAL(finished(bool)), SLOT(reloadAllData(bool))); + m_scanner->doScanAll(); +} + +void GameUI::reloadAllData(bool dbChanged) +{ + delete m_scanner; + m_scanner = NULL; + + if (dbChanged) + { + delete m_gameTree; + m_gameTree = NULL; + Load(); + } +} + diff --git a/mythplugins/mythgame/mythgame/gameui.h b/mythplugins/mythgame/mythgame/gameui.h index 9d92d46ab91..79e9e3f07fe 100644 --- a/mythplugins/mythgame/mythgame/gameui.h +++ b/mythplugins/mythgame/mythgame/gameui.h @@ -19,6 +19,7 @@ class RomInfo; class QTimer; class QKeyEvent; class QEvent; +class GameScanner; class GameUI : public MythScreenType { @@ -29,6 +30,7 @@ class GameUI : public MythScreenType ~GameUI(); bool Create(); + void Load(); bool keyPressEvent(QKeyEvent *event); public slots: @@ -42,6 +44,8 @@ class GameUI : public MythScreenType void OnGameSearchDone(MetadataLookup *lookup); void StartGameImageSet(MythGenericTree *node, QStringList coverart, QStringList fanart, QStringList screenshot); + void doScan(void); + void reloadAllData(bool dbchanged); private: void updateRomInfo(RomInfo *rom); @@ -88,6 +92,8 @@ class GameUI : public MythScreenType MetadataDownload *m_query; MetadataImageDownload *m_imageDownload; + + GameScanner *m_scanner; }; #endif diff --git a/mythplugins/mythgame/mythgame/mythgame.pro b/mythplugins/mythgame/mythgame/mythgame.pro index eca91598fc7..0c26fa5e8e0 100644 --- a/mythplugins/mythgame/mythgame/mythgame.pro +++ b/mythplugins/mythgame/mythgame/mythgame.pro @@ -20,11 +20,11 @@ INSTALLS += target installscripts installgiantbomb installgiantbombxsl # Input HEADERS += gamehandler.h rominfo.h unzip.h gamesettings.h gameui.h -HEADERS += rom_metadata.h romedit.h gamedetails.h +HEADERS += rom_metadata.h romedit.h gamedetails.h gamescan.h SOURCES += main.cpp gamehandler.cpp rominfo.cpp gameui.cpp unzip.c SOURCES += gamesettings.cpp dbcheck.cpp rom_metadata.cpp romedit.cpp -SOURCES += gamedetails.cpp +SOURCES += gamedetails.cpp gamescan.cpp DEFINES += MPLUGIN_API diff --git a/mythplugins/mythgame/mythgame/rominfo.cpp b/mythplugins/mythgame/mythgame/rominfo.cpp index 90d6f341ab8..7a694ed8ab7 100644 --- a/mythplugins/mythgame/mythgame/rominfo.cpp +++ b/mythplugins/mythgame/mythgame/rominfo.cpp @@ -27,6 +27,9 @@ void RomInfo::SaveToDatabase() if (inserting) { + LOG(VB_GENERAL, LOG_INFO, LOC + QString("Adding %1 - %2").arg(Rompath()) + .arg(Romname())); + query.prepare("INSERT INTO gamemetadata " "(system, romname, gamename, genre, year, gametype, " "rompath, country, crc_value, diskcount, display, plot, " @@ -90,6 +93,25 @@ void RomInfo::SaveToDatabase() } } +void RomInfo::DeleteFromDatabase() +{ + LOG(VB_GENERAL, LOG_INFO, LOC + QString("Removing %1 - %2").arg(Rompath()) + .arg(Romname())); + + MSqlQuery query(MSqlQuery::InitCon()); + + query.prepare("DELETE FROM gamemetadata WHERE " + "romname = :ROMNAME AND " + "rompath = :ROMPATH "); + + query.bindValue(":ROMNAME",Romname()); + query.bindValue(":ROMPATH",Rompath()); + + if (!query.exec()) + MythDB::DBError("purgeGameDB", query); + +} + // Return the count of how many times this appears in the db already int romInDB(QString rom, QString gametype) { @@ -345,6 +367,54 @@ QList RomInfo::GetAllRomInfo() return ret; } +RomInfo *RomInfo::GetRomInfoById(int id) +{ + RomInfo *ret = new RomInfo(); + + MSqlQuery query(MSqlQuery::InitCon()); + + QString querystr = "SELECT intid,system,romname,gamename,genre,year,publisher," + "favorite,rompath,screenshot,fanart,plot,boxart," + "gametype,diskcount,country,crc_value,inetref,display," + "version FROM gamemetadata WHERE intid = :INTID"; + + query.prepare(querystr); + query.bindValue(":INTID", id); + + if (!query.exec()) + { + MythDB::DBError("GetRomInfoById", query); + return ret; + } + + if (query.next()) + { + ret = new RomInfo( + query.value(0).toInt(), + query.value(2).toString(), + query.value(1).toString(), + query.value(3).toString(), + query.value(4).toString(), + query.value(5).toString(), + query.value(7).toBool(), + query.value(8).toString(), + query.value(15).toString(), + query.value(16).toString(), + query.value(14).toInt(), + query.value(13).toString(), + 0, QString(), + query.value(11).toString(), + query.value(6).toString(), + query.value(19).toString(), + query.value(9).toString(), + query.value(10).toString(), + query.value(12).toString(), + query.value(17).toString()); + } + + return ret; +} + QString RomInfo::toString() { return QString ("Rom Info:\n" diff --git a/mythplugins/mythgame/mythgame/rominfo.h b/mythplugins/mythgame/mythgame/rominfo.h index fac28753098..d7a2212e874 100644 --- a/mythplugins/mythgame/mythgame/rominfo.h +++ b/mythplugins/mythgame/mythgame/rominfo.h @@ -11,6 +11,7 @@ class RomInfo { public: static QList GetAllRomInfo(); + static RomInfo *GetRomInfoById(int id); RomInfo(int lid = 0, QString lromname = "", QString lsystem = "", QString lgamename ="", QString lgenre = "", QString lyear = "", bool lfavorite = FALSE, @@ -140,7 +141,9 @@ class RomInfo void setField(QString field, QString data); void fillData(); + void SaveToDatabase(); + void DeleteFromDatabase(); protected: int id; From 8642ea645fbb2b251f79788e1f76a8f62b6389a3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 8 Aug 2011 14:36:04 +0100 Subject: [PATCH 32/49] Const fixes for MetaIO classes --- mythplugins/mythmusic/mythmusic/metadata.cpp | 5 ---- mythplugins/mythmusic/mythmusic/metadata.h | 8 +++--- mythplugins/mythmusic/mythmusic/metaio.cpp | 11 ++++---- mythplugins/mythmusic/mythmusic/metaio.h | 25 +++++++++++-------- .../mythmusic/mythmusic/metaioavfcomment.cpp | 8 +++--- .../mythmusic/mythmusic/metaioavfcomment.h | 6 ++--- .../mythmusic/mythmusic/metaioflacvorbis.cpp | 4 +-- .../mythmusic/mythmusic/metaioflacvorbis.h | 4 +-- mythplugins/mythmusic/mythmusic/metaioid3.cpp | 6 ++--- mythplugins/mythmusic/mythmusic/metaioid3.h | 6 ++--- mythplugins/mythmusic/mythmusic/metaiomp4.cpp | 9 ++++--- mythplugins/mythmusic/mythmusic/metaiomp4.h | 6 ++--- .../mythmusic/mythmusic/metaiooggvorbis.cpp | 4 +-- .../mythmusic/mythmusic/metaiooggvorbis.h | 4 +-- .../mythmusic/mythmusic/metaiotaglib.cpp | 4 +-- .../mythmusic/mythmusic/metaiotaglib.h | 8 +++--- .../mythmusic/mythmusic/metaiowavpack.cpp | 4 +-- .../mythmusic/mythmusic/metaiowavpack.h | 4 +-- 18 files changed, 64 insertions(+), 62 deletions(-) diff --git a/mythplugins/mythmusic/mythmusic/metadata.cpp b/mythplugins/mythmusic/mythmusic/metadata.cpp index 986d97cbf4b..53751e28354 100644 --- a/mythplugins/mythmusic/mythmusic/metadata.cpp +++ b/mythplugins/mythmusic/mythmusic/metadata.cpp @@ -724,11 +724,6 @@ void Metadata::incRating() m_changed = true; } -QDateTime Metadata::LastPlay() -{ - return m_lastplay; -} - void Metadata::setLastPlay() { m_lastplay = QDateTime::currentDateTime(); diff --git a/mythplugins/mythmusic/mythmusic/metadata.h b/mythplugins/mythmusic/mythmusic/metadata.h index d4f6884e1a1..ae6bbee7a71 100644 --- a/mythplugins/mythmusic/mythmusic/metadata.h +++ b/mythplugins/mythmusic/mythmusic/metadata.h @@ -145,7 +145,7 @@ class Metadata QString FormatArtist(); QString FormatTitle(); - QString Genre() { return m_genre; } + QString Genre() const { return m_genre; } void setGenre(const QString &lgenre) { m_genre = lgenre; } void setDirectoryId(int ldirectoryid) { m_directoryid = ldirectoryid; } @@ -160,7 +160,7 @@ class Metadata void setGenreId(int lgenreid) { m_genreid = lgenreid; } int getGenreId() const { return m_genreid; } - int Year() { return m_year; } + int Year() const { return m_year; } void setYear(int lyear) { m_year = lyear; } int Track() const { return m_tracknum; } @@ -189,7 +189,7 @@ class Metadata void incRating(); void setRating(int lrating) { m_rating = lrating; } - QDateTime LastPlay(); + QDateTime LastPlay() const { return m_lastplay; } void setLastPlay(); int PlayCount() const { return m_playcount; } @@ -218,7 +218,7 @@ class Metadata void persist(void) const; void UpdateModTime(void) const; - bool hasChanged() {return m_changed;} + bool hasChanged() const { return m_changed; } int compare(const Metadata *other) const; static void setArtistAndTrackFormats(); diff --git a/mythplugins/mythmusic/mythmusic/metaio.cpp b/mythplugins/mythmusic/mythmusic/metaio.cpp index a8d19d4a8ac..1840ba88c4e 100644 --- a/mythplugins/mythmusic/mythmusic/metaio.cpp +++ b/mythplugins/mythmusic/mythmusic/metaio.cpp @@ -27,10 +27,11 @@ MetaIO::~MetaIO() * \param filename The filename to try and determine metadata for. * \returns Metadata Pointer, or NULL on error. */ -void MetaIO::readFromFilename(QString filename, +void MetaIO::readFromFilename(const QString &filename, QString &artist, QString &album, QString &title, QString &genre, int &tracknum) { + QString lfilename = filename; // Clear artist.clear(); album.clear(); @@ -40,8 +41,8 @@ void MetaIO::readFromFilename(QString filename, int part_num = 0; // Replace - filename.replace('_', ' '); - filename.section('.', 0, -2); + lfilename.replace('_', ' '); + lfilename.section('.', 0, -2); QStringList fmt_list = mFilenameFormat.split("/"); QStringList::iterator fmt_it = fmt_list.begin(); @@ -52,7 +53,7 @@ void MetaIO::readFromFilename(QString filename, fmt_it = fmt_list.begin(); for(; fmt_it != fmt_list.end(); fmt_it++, part_num++) { - QString part_str = filename.section( "/", part_num, part_num); + QString part_str = lfilename.section( "/", part_num, part_num); if ( *fmt_it == "GENRE" ) genre = part_str; @@ -100,7 +101,7 @@ void MetaIO::readFromFilename(QString filename, * \param filename The filename to try and determine metadata for. * \returns Metadata Pointer, or NULL on error. */ -Metadata* MetaIO::readFromFilename(QString filename, bool blnLength) +Metadata* MetaIO::readFromFilename(const QString &filename, bool blnLength) { QString artist, album, title, genre; int tracknum = 0, length = 0; diff --git a/mythplugins/mythmusic/mythmusic/metaio.h b/mythplugins/mythmusic/mythmusic/metaio.h index b1ab4afc9db..b41ef5f5eff 100644 --- a/mythplugins/mythmusic/mythmusic/metaio.h +++ b/mythplugins/mythmusic/mythmusic/metaio.h @@ -21,7 +21,7 @@ class MetaIO * \param mdata A pointer to a Metadata object * \returns Boolean to indicate success/failure. */ - virtual bool write(Metadata* mdata) = 0; + virtual bool write(const Metadata* mdata) = 0; /*! * \brief Writes rating and playcount back to a file @@ -41,7 +41,7 @@ class MetaIO * \param filename The filename to read metadata from. * \returns Metadata pointer or NULL on error */ - virtual Metadata* read(QString filename) = 0; + virtual Metadata* read(const QString &filename) = 0; /*! * \brief Does the tag support embedded cover art. @@ -65,21 +65,25 @@ class MetaIO return AlbumArtList(); } - virtual bool writeAlbumArt(const QString &filename, const AlbumArtImage *albumart) + virtual bool writeAlbumArt(const QString &filename, + const AlbumArtImage *albumart) { (void)filename; (void)albumart; return false; } - virtual bool removeAlbumArt(const QString &filename, const AlbumArtImage *albumart) + virtual bool removeAlbumArt(const QString &filename, + const AlbumArtImage *albumart) { (void)filename; (void)albumart; return false; } - virtual bool changeImageType(const QString &filename, const AlbumArtImage *albumart, ImageType newType) + virtual bool changeImageType(const QString &filename, + const AlbumArtImage *albumart, + ImageType newType) { (void)filename; (void)albumart; @@ -87,17 +91,18 @@ class MetaIO return false; } - virtual QImage *getAlbumArt(QString filename, ImageType type) + virtual QImage *getAlbumArt(const QString &filename, ImageType type) { (void)filename; (void)type; return false; } - void readFromFilename(QString filename, QString &artist, QString &album, - QString &title, QString &genre, int &tracknum); + void readFromFilename(const QString &filename, QString &artist, + QString &album, QString &title, QString &genre, + int &tracknum); - Metadata* readFromFilename(QString filename, bool blnLength = false); + Metadata* readFromFilename(const QString &filename, bool blnLength = false); void readFromFilename(Metadata *metadata); @@ -110,7 +115,7 @@ class MetaIO protected: private: - virtual int getTrackLength(QString filename) = 0; + virtual int getTrackLength(const QString &filename) = 0; QString mFilename; QString mFilenameFormat; diff --git a/mythplugins/mythmusic/mythmusic/metaioavfcomment.cpp b/mythplugins/mythmusic/mythmusic/metaioavfcomment.cpp index 51d6d6a13f2..0f4d9c6c009 100644 --- a/mythplugins/mythmusic/mythmusic/metaioavfcomment.cpp +++ b/mythplugins/mythmusic/mythmusic/metaioavfcomment.cpp @@ -25,17 +25,17 @@ MetaIOAVFComment::~MetaIOAVFComment(void) /*! * \copydoc MetaIO::write() */ -bool MetaIOAVFComment::write(Metadata* mdata) +bool MetaIOAVFComment::write(const Metadata* mdata) { // Wont implement.... - mdata = mdata; // -Wall annoyance + (void)mdata; // -Wall annoyance return false; } /*! * \copydoc MetaIO::read() */ -Metadata* MetaIOAVFComment::read(QString filename) +Metadata* MetaIOAVFComment::read(const QString &filename) { QString artist, compilation_artist, album, title, genre; int year = 0, tracknum = 0, length = 0; @@ -103,7 +103,7 @@ Metadata* MetaIOAVFComment::read(QString filename) * \param filename The filename for which we want to find the length. * \returns An integer (signed!) to represent the length in seconds. */ -int MetaIOAVFComment::getTrackLength(QString filename) +int MetaIOAVFComment::getTrackLength(const QString &filename) { AVFormatContext* p_context = NULL; AVFormatParameters* p_params = NULL; diff --git a/mythplugins/mythmusic/mythmusic/metaioavfcomment.h b/mythplugins/mythmusic/mythmusic/metaioavfcomment.h index fd85791f400..0c67215cf53 100644 --- a/mythplugins/mythmusic/mythmusic/metaioavfcomment.h +++ b/mythplugins/mythmusic/mythmusic/metaioavfcomment.h @@ -22,11 +22,11 @@ class MetaIOAVFComment : public MetaIO MetaIOAVFComment(void); virtual ~MetaIOAVFComment(void); - bool write(Metadata* mdata); - Metadata* read(QString filename); + bool write(const Metadata* mdata); + Metadata* read(const QString &filename); private: - int getTrackLength(QString filename); + int getTrackLength(const QString &filename); int getTrackLength(AVFormatContext* p_context); }; diff --git a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp index 82589aea4f5..3461f04825a 100644 --- a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp +++ b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp @@ -42,7 +42,7 @@ TagLib::FLAC::File *MetaIOFLACVorbis::OpenFile(const QString &filename) /*! * \copydoc MetaIO::write() */ -bool MetaIOFLACVorbis::write(Metadata* mdata) +bool MetaIOFLACVorbis::write(const Metadata* mdata) { if (!mdata) return false; @@ -93,7 +93,7 @@ bool MetaIOFLACVorbis::write(Metadata* mdata) /*! * \copydoc MetaIO::read() */ -Metadata* MetaIOFLACVorbis::read(QString filename) +Metadata* MetaIOFLACVorbis::read(const QString &filename) { TagLib::FLAC::File *flacfile = OpenFile(filename); diff --git a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h index a6445ed2b84..96d7497e1b7 100644 --- a/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h +++ b/mythplugins/mythmusic/mythmusic/metaioflacvorbis.h @@ -24,8 +24,8 @@ class MetaIOFLACVorbis : public MetaIOTagLib MetaIOFLACVorbis(void); virtual ~MetaIOFLACVorbis(void); - bool write(Metadata* mdata); - Metadata* read(QString filename); + bool write(const Metadata* mdata); + Metadata* read(const QString &filename); virtual bool TagExists(const QString &filename); diff --git a/mythplugins/mythmusic/mythmusic/metaioid3.cpp b/mythplugins/mythmusic/mythmusic/metaioid3.cpp index 50d8e8c34ad..7f45bc33c57 100644 --- a/mythplugins/mythmusic/mythmusic/metaioid3.cpp +++ b/mythplugins/mythmusic/mythmusic/metaioid3.cpp @@ -153,7 +153,7 @@ TagLib::ID3v1::Tag* MetaIOID3::GetID3v1Tag(bool create) /*! * \copydoc MetaIO::write() */ -bool MetaIOID3::write(Metadata* mdata) +bool MetaIOID3::write(const Metadata* mdata) { if (!OpenFile(mdata->Filename()), true) return false; @@ -228,7 +228,7 @@ bool MetaIOID3::write(Metadata* mdata) /*! * \copydoc MetaIO::read() */ -Metadata *MetaIOID3::read(QString filename) +Metadata *MetaIOID3::read(const QString &filename) { if (!OpenFile(filename)) return NULL; @@ -328,7 +328,7 @@ Metadata *MetaIOID3::read(QString filename) * \param type The type of image we want - front/back etc * \returns A pointer to a QImage owned by the caller or NULL if not found. */ -QImage* MetaIOID3::getAlbumArt(QString filename, ImageType type) +QImage* MetaIOID3::getAlbumArt(const QString &filename, ImageType type) { QImage *picture = new QImage(); diff --git a/mythplugins/mythmusic/mythmusic/metaioid3.h b/mythplugins/mythmusic/mythmusic/metaioid3.h index 9a5b7ccf3a8..9fbb68bdbf4 100644 --- a/mythplugins/mythmusic/mythmusic/metaioid3.h +++ b/mythplugins/mythmusic/mythmusic/metaioid3.h @@ -36,15 +36,15 @@ class MetaIOID3 : public MetaIOTagLib MetaIOID3(void); virtual ~MetaIOID3(void); - virtual bool write(Metadata* mdata); + virtual bool write(const Metadata* mdata); bool writeVolatileMetadata(const Metadata* mdata); bool writeAlbumArt(const QString &filename, const AlbumArtImage *albumart); bool removeAlbumArt(const QString &filename, const AlbumArtImage *albumart); - Metadata* read(QString filename); + Metadata* read(const QString &filename); AlbumArtList getAlbumArtList(const QString &filename); - QImage *getAlbumArt(QString filename, ImageType type); + QImage *getAlbumArt(const QString &filename, ImageType type); bool supportsEmbeddedImages(void) { return true; } diff --git a/mythplugins/mythmusic/mythmusic/metaiomp4.cpp b/mythplugins/mythmusic/mythmusic/metaiomp4.cpp index c2a4a7e77fe..863086a8ce2 100644 --- a/mythplugins/mythmusic/mythmusic/metaiomp4.cpp +++ b/mythplugins/mythmusic/mythmusic/metaiomp4.cpp @@ -27,7 +27,7 @@ MetaIOMP4::~MetaIOMP4(void) /*! * \copydoc MetaIO::write() */ -bool MetaIOMP4::write(Metadata* mdata) +bool MetaIOMP4::write(const Metadata* mdata) { if (!mdata) return false; @@ -79,7 +79,7 @@ bool MetaIOMP4::write(Metadata* mdata) /*! * \copydoc MetaIO::read() */ -Metadata* MetaIOMP4::read(QString filename) +Metadata* MetaIOMP4::read(const QString &filename) { QString title, artist, album, genre; int year = 0, tracknum = 0, length = 0; @@ -179,7 +179,7 @@ QString MetaIOMP4::getFieldValue(AVFormatContext* context, const char* tagname) * \param filename The filename for which we want to find the length. * \returns An integer (signed!) to represent the length in seconds. */ -int MetaIOMP4::getTrackLength(QString filename) +int MetaIOMP4::getTrackLength(const QString &filename) { AVFormatContext* p_context = NULL; AVFormatParameters* p_params = NULL; @@ -227,7 +227,8 @@ int MetaIOMP4::getTrackLength(AVFormatContext* pContext) * \param title Title * \param genre Genre */ -void MetaIOMP4::metadataSanityCheck(QString *artist, QString *album, QString *title, QString *genre) +void MetaIOMP4::metadataSanityCheck(QString *artist, QString *album, + QString *title, QString *genre) { if (artist->isEmpty()) artist->append("Unknown Artist"); diff --git a/mythplugins/mythmusic/mythmusic/metaiomp4.h b/mythplugins/mythmusic/mythmusic/metaiomp4.h index b3a282ebf3a..14f89d3be3f 100644 --- a/mythplugins/mythmusic/mythmusic/metaiomp4.h +++ b/mythplugins/mythmusic/mythmusic/metaiomp4.h @@ -19,11 +19,11 @@ class MetaIOMP4 : public MetaIO MetaIOMP4(void); virtual ~MetaIOMP4(void); - bool write(Metadata* mdata); - Metadata* read(QString filename); + bool write(const Metadata* mdata); + Metadata* read(const QString &filename); private: - int getTrackLength(QString filename); + int getTrackLength(const QString &filename); int getTrackLength(AVFormatContext* p_context); QString getFieldValue(AVFormatContext* context, const char* tagname); void metadataSanityCheck(QString *artist, QString *album, QString *title, QString *genre); diff --git a/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp b/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp index dc730606855..1ea3e8d78e1 100644 --- a/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp +++ b/mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp @@ -40,7 +40,7 @@ TagLib::Ogg::Vorbis::File *MetaIOOggVorbis::OpenFile(const QString &filename) /*! * \copydoc MetaIO::write() */ -bool MetaIOOggVorbis::write(Metadata* mdata) +bool MetaIOOggVorbis::write(const Metadata* mdata) { if (!mdata) return false; @@ -91,7 +91,7 @@ bool MetaIOOggVorbis::write(Metadata* mdata) /*! * \copydoc MetaIO::read() */ -Metadata* MetaIOOggVorbis::read(QString filename) +Metadata* MetaIOOggVorbis::read(const QString &filename) { TagLib::Ogg::Vorbis::File *oggfile = OpenFile(filename); diff --git a/mythplugins/mythmusic/mythmusic/metaiooggvorbis.h b/mythplugins/mythmusic/mythmusic/metaiooggvorbis.h index bb4d2c5dd8b..9428cff9140 100644 --- a/mythplugins/mythmusic/mythmusic/metaiooggvorbis.h +++ b/mythplugins/mythmusic/mythmusic/metaiooggvorbis.h @@ -24,8 +24,8 @@ class MetaIOOggVorbis : public MetaIOTagLib MetaIOOggVorbis(void); ~MetaIOOggVorbis(void); - bool write(Metadata* mdata); - Metadata* read(QString filename); + bool write(const Metadata* mdata); + Metadata* read(const QString &filename); private: TagLib::Ogg::Vorbis::File *OpenFile(const QString &filename); diff --git a/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp b/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp index 968ca6ad61d..2bc3ab4334b 100644 --- a/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp +++ b/mythplugins/mythmusic/mythmusic/metaiotaglib.cpp @@ -37,7 +37,7 @@ MetaIOTagLib::~MetaIOTagLib(void) * \param tag A pointer to the tag * \param metadata Pointer to the metadata */ -void MetaIOTagLib::WriteGenericMetadata(Tag *tag, Metadata *metadata) +void MetaIOTagLib::WriteGenericMetadata(Tag *tag, const Metadata *metadata) { if (!tag || !metadata) return; @@ -115,7 +115,7 @@ int MetaIOTagLib::getTrackLength(TagLib::File *file) * \param filename The filename for which we want to find the length. * \returns An integer (signed!) to represent the length in milliseconds. */ -int MetaIOTagLib::getTrackLength(QString filename) +int MetaIOTagLib::getTrackLength(const QString &filename) { int milliseconds = 0; QByteArray fname = filename.toLocal8Bit(); diff --git a/mythplugins/mythmusic/mythmusic/metaiotaglib.h b/mythplugins/mythmusic/mythmusic/metaiotaglib.h index 09580eceeff..18b5bc76410 100644 --- a/mythplugins/mythmusic/mythmusic/metaiotaglib.h +++ b/mythplugins/mythmusic/mythmusic/metaiotaglib.h @@ -23,14 +23,14 @@ class MetaIOTagLib : public MetaIO MetaIOTagLib(void); virtual ~MetaIOTagLib(void); - virtual bool write(Metadata* mdata) = 0; - virtual Metadata* read(QString filename) = 0; + virtual bool write(const Metadata* mdata) = 0; + virtual Metadata* read(const QString &filename) = 0; protected: int getTrackLength(TagLib::File *file); - int getTrackLength(QString filename); + int getTrackLength(const QString &filename); void ReadGenericMetadata(TagLib::Tag *tag, Metadata *metadata); - void WriteGenericMetadata(TagLib::Tag *tag, Metadata *metadata); + void WriteGenericMetadata(TagLib::Tag *tag, const Metadata *metadata); }; #endif diff --git a/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp b/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp index 5103a2d5c37..c7a294cea5a 100644 --- a/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp +++ b/mythplugins/mythmusic/mythmusic/metaiowavpack.cpp @@ -40,7 +40,7 @@ TagLib::WavPack::File *MetaIOWavPack::OpenFile(const QString &filename) /*! * \copydoc MetaIO::write() */ -bool MetaIOWavPack::write(Metadata* mdata) +bool MetaIOWavPack::write(const Metadata* mdata) { if (!mdata) return false; @@ -82,7 +82,7 @@ bool MetaIOWavPack::write(Metadata* mdata) /*! * \copydoc MetaIO::read() */ -Metadata* MetaIOWavPack::read(QString filename) +Metadata* MetaIOWavPack::read(const QString &filename) { TagLib::WavPack::File *wpfile = OpenFile(filename); diff --git a/mythplugins/mythmusic/mythmusic/metaiowavpack.h b/mythplugins/mythmusic/mythmusic/metaiowavpack.h index 118977a1486..98c70e80662 100644 --- a/mythplugins/mythmusic/mythmusic/metaiowavpack.h +++ b/mythplugins/mythmusic/mythmusic/metaiowavpack.h @@ -26,8 +26,8 @@ class MetaIOWavPack : public MetaIOTagLib MetaIOWavPack(void); virtual ~MetaIOWavPack(void); - bool write(Metadata* mdata); - Metadata* read(QString filename); + bool write(const Metadata* mdata); + Metadata* read(const QString &filename); private: TagLib::WavPack::File *OpenFile(const QString &filename); From 47d67e6722092471069c52d1b0a37509477b5d85 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Tue, 2 Aug 2011 12:58:32 -0400 Subject: [PATCH 33/49] This adds two new classes MThread and MThreadPool to be used instead of QThread and QThreadPool. These mirror the API's of the Qt classes but also add a requirement for a QString naming the thread or naming the runnable which are used for debugging. These wrappers also make sure mysql connections are torn down properly and have a number of safety checks and assurances. The destructor for MThread also makes sure that a thread has stopped running before we allow the QThread to be deleted. And MThreaPool makes sure all it's threads have stopped running. MThread has a Cleanup() method that attempts to shut down any threads that are running, it only works for threads that exit on a call to exit(), which includes any threads using the Qt event loop. It will also print out the names of the threads that are still running for debugging purposes. MThread has one special constructor. It takes a QRunnable* and runs it instead of the Qt event loop in the default run() implementation. Unlike MThreadPool and QThreadPool, MThread does not delete this runnable when it exits. This allows you to run something with less boilerplate code. Just like with QThread in Qt4 it really is better to use the Qt event loop rather than write your own. As you don't use the Qt event loop QObject deleteLater's are not executed until the thread exits, Qt events and timers do not work making Qt networking classes misbehave and signals/slots are generally unsafe. However, many of the threads with event loops in MythTV were written before Qt allowed an event loop outside the main thread so this syntactic sugar just lets us handle that with less lines of code. There are a few other differences with respect to Qt's classes other than requiring a name. First, MThread does not inherit from QObject, if you need QObject services in a threading class you will need to inherit from QObject seperately. Note when you inherit from QObject, you must inherit from no more than one QObject based class and it must be first in the list of classes your class inherits from (a Qt restriction). Second, QThread doesn't implement most of QThread's static methods, notably QThread::currentThread(). It does make the underlying QThread available via the qthread() method.. but the usual reason to use QThread::currentThread() is to check which thread you are running in.. for this there is a set of helper functions is_current_thread(MThread&), is_current_thread(QThread*), and is_current_thread(MThread*) which you can use instead. Finally, MThreadPool does not have reserveThread() and releaseThread() calls; instead use startReserved(). The reserveThread() and releaseThread() API is not a good API because it doesn't ensure that your runnable starts right away even though the thread will eventually not be counted amoung those forcing other threads to go to the queue rather than running right away. --- .../mytharchive/recordingselector.cpp | 16 +- .../mythgallery/galleryfilterdlg.cpp | 18 +- .../mythgallery/mythgallery/glsingleview.cpp | 25 +- .../mythgallery/mythgallery/glsingleview.h | 5 +- .../mythgallery/mythgallery/iconview.cpp | 26 +- .../mythgallery/mythgallery/iconview.h | 4 +- .../mythgallery/thumbgenerator.cpp | 19 +- .../mythgallery/mythgallery/thumbgenerator.h | 6 +- .../mythmusic/mythmusic/avfdecoder.cpp | 8 +- mythplugins/mythmusic/mythmusic/cddecoder.cpp | 8 +- mythplugins/mythmusic/mythmusic/cdrip.cpp | 34 +- mythplugins/mythmusic/mythmusic/cdrip.h | 7 +- .../mythmusic/mythmusic/databasebox.cpp | 9 +- mythplugins/mythmusic/mythmusic/databasebox.h | 5 +- mythplugins/mythmusic/mythmusic/decoder.cpp | 4 +- mythplugins/mythmusic/mythmusic/decoder.h | 4 +- .../mythmusic/mythmusic/importmusic.cpp | 8 +- mythplugins/mythmusic/mythmusic/importmusic.h | 4 +- mythplugins/mythmusic/mythmusic/metadata.cpp | 8 +- mythplugins/mythmusic/mythmusic/metadata.h | 4 +- .../mythmusic/mythmusic/playbackbox.cpp | 2 +- .../mythmusic/mythmusic/playlistcontainer.cpp | 16 +- .../mythmusic/mythmusic/playlistcontainer.h | 4 +- mythtv/libs/libmyth/audio/audiooutputbase.cpp | 5 +- mythtv/libs/libmyth/audio/audiooutputbase.h | 4 +- .../libs/libmyth/audio/audiopulsehandler.cpp | 8 +- mythtv/libs/libmyth/audio/audiopulsehandler.h | 3 +- mythtv/libs/libmyth/mythcontext.cpp | 4 +- mythtv/libs/libmyth/mythmediamonitor.cpp | 8 +- mythtv/libs/libmyth/mythmediamonitor.h | 4 +- mythtv/libs/libmyth/netgrabbermanager.cpp | 14 +- mythtv/libs/libmyth/netgrabbermanager.h | 11 +- mythtv/libs/libmyth/programinfoupdater.cpp | 9 +- mythtv/libs/libmyth/programinfoupdater.h | 4 +- mythtv/libs/libmythbase/libmythbase.pro | 4 +- mythtv/libs/libmythbase/logging.cpp | 16 +- mythtv/libs/libmythbase/logging.h | 12 +- mythtv/libs/libmythbase/mthread.cpp | 315 +++++++++++ mythtv/libs/libmythbase/mthread.h | 120 ++++ mythtv/libs/libmythbase/mthreadpool.cpp | 512 ++++++++++++++++++ mythtv/libs/libmythbase/mthreadpool.h | 61 +++ mythtv/libs/libmythbase/mythcorecontext.cpp | 15 +- mythtv/libs/libmythbase/mythdb.cpp | 3 +- mythtv/libs/libmythbase/mythdbcon.cpp | 125 ++--- mythtv/libs/libmythbase/mythdbcon.h | 13 +- .../libs/libmythbase/mythdownloadmanager.cpp | 17 +- mythtv/libs/libmythbase/mythdownloadmanager.h | 4 +- .../libs/libmythbase/mythsignalingtimer.cpp | 12 +- mythtv/libs/libmythbase/mythsignalingtimer.h | 4 +- mythtv/libs/libmythbase/mythsocketthread.cpp | 6 +- mythtv/libs/libmythbase/mythsocketthread.h | 5 +- mythtv/libs/libmythbase/mythsystem.cpp | 5 - mythtv/libs/libmythbase/mythsystem.h | 4 +- mythtv/libs/libmythbase/system-unix.cpp | 48 +- mythtv/libs/libmythbase/system-unix.h | 14 +- mythtv/libs/libmythbase/system-windows.cpp | 56 +- mythtv/libs/libmythbase/system-windows.h | 20 +- .../libs/libmythmetadata/metadatadownload.cpp | 9 +- .../libs/libmythmetadata/metadatadownload.h | 7 +- .../libmythmetadata/metadataimagedownload.cpp | 9 +- .../libmythmetadata/metadataimagedownload.h | 4 +- mythtv/libs/libmythmetadata/videoscan.cpp | 22 +- mythtv/libs/libmythmetadata/videoscan.h | 6 +- .../libmythprotoserver/mythsocketmanager.cpp | 11 +- .../requesthandler/deletethread.cpp | 6 +- .../requesthandler/deletethread.h | 6 +- .../requesthandler/fileserverhandler.cpp | 2 +- mythtv/libs/libmythtv/DeviceReadBuffer.cpp | 12 +- mythtv/libs/libmythtv/DeviceReadBuffer.h | 6 +- mythtv/libs/libmythtv/NuppelVideoRecorder.cpp | 8 +- mythtv/libs/libmythtv/NuppelVideoRecorder.h | 15 +- mythtv/libs/libmythtv/ThreadedFileWriter.cpp | 18 +- mythtv/libs/libmythtv/ThreadedFileWriter.h | 13 +- mythtv/libs/libmythtv/asisignalmonitor.cpp | 2 +- mythtv/libs/libmythtv/asistreamhandler.cpp | 6 + mythtv/libs/libmythtv/asistreamhandler.h | 2 +- mythtv/libs/libmythtv/bdringbuffer.cpp | 2 +- mythtv/libs/libmythtv/channelbase.h | 1 - .../libmythtv/channelscan/channelscan_sm.cpp | 22 +- .../libmythtv/channelscan/channelscan_sm.h | 25 +- mythtv/libs/libmythtv/dvbcam.cpp | 12 +- mythtv/libs/libmythtv/dvbcam.h | 22 +- mythtv/libs/libmythtv/dvbsignalmonitor.cpp | 2 +- mythtv/libs/libmythtv/dvbstreamhandler.cpp | 5 +- mythtv/libs/libmythtv/dvbstreamhandler.h | 2 +- mythtv/libs/libmythtv/eitscanner.cpp | 28 +- mythtv/libs/libmythtv/eitscanner.h | 18 +- mythtv/libs/libmythtv/fifowriter.cpp | 10 +- mythtv/libs/libmythtv/fifowriter.h | 7 +- .../libs/libmythtv/firewiresignalmonitor.cpp | 6 +- mythtv/libs/libmythtv/firewiresignalmonitor.h | 9 +- mythtv/libs/libmythtv/hdhrstreamhandler.cpp | 7 +- mythtv/libs/libmythtv/hdhrstreamhandler.h | 2 +- .../libmythtv/iptv/iptvchannelfetcher.cpp | 40 +- .../libs/libmythtv/iptv/iptvchannelfetcher.h | 18 +- mythtv/libs/libmythtv/iptvsignalmonitor.cpp | 6 +- mythtv/libs/libmythtv/iptvsignalmonitor.h | 14 +- mythtv/libs/libmythtv/jobqueue.cpp | 12 +- mythtv/libs/libmythtv/jobqueue.h | 21 +- mythtv/libs/libmythtv/linuxfirewiredevice.cpp | 15 +- mythtv/libs/libmythtv/linuxfirewiredevice.h | 20 +- mythtv/libs/libmythtv/mhi.cpp | 11 +- mythtv/libs/libmythtv/mhi.h | 26 +- mythtv/libs/libmythtv/mythcommflagplayer.cpp | 15 +- mythtv/libs/libmythtv/mythplayer.cpp | 47 +- mythtv/libs/libmythtv/mythplayer.h | 6 +- mythtv/libs/libmythtv/mythsystemevent.cpp | 25 +- mythtv/libs/libmythtv/previewgenerator.cpp | 23 +- mythtv/libs/libmythtv/previewgenerator.h | 8 +- .../libs/libmythtv/previewgeneratorqueue.cpp | 14 +- mythtv/libs/libmythtv/previewgeneratorqueue.h | 6 +- .../libmythtv/privatedecoder_crystalhd.cpp | 10 +- .../libs/libmythtv/privatedecoder_crystalhd.h | 8 +- mythtv/libs/libmythtv/recorderbase.h | 21 +- mythtv/libs/libmythtv/ringbuffer.cpp | 11 +- mythtv/libs/libmythtv/ringbuffer.h | 6 +- mythtv/libs/libmythtv/signalmonitor.cpp | 9 +- mythtv/libs/libmythtv/signalmonitor.h | 11 +- mythtv/libs/libmythtv/streamhandler.cpp | 3 +- mythtv/libs/libmythtv/streamhandler.h | 4 +- mythtv/libs/libmythtv/tv_play.cpp | 2 + mythtv/libs/libmythtv/tv_play.h | 2 - mythtv/libs/libmythtv/tv_rec.cpp | 20 +- mythtv/libs/libmythtv/tv_rec.h | 29 +- mythtv/libs/libmythtv/tvbrowsehelper.cpp | 5 +- mythtv/libs/libmythtv/tvbrowsehelper.h | 12 +- mythtv/libs/libmythtv/v4lrecorder.h | 21 +- mythtv/libs/libmythtv/videosource.h | 3 +- mythtv/libs/libmythui/AppleRemote.cpp | 7 +- mythtv/libs/libmythui/AppleRemote.h | 7 +- mythtv/libs/libmythui/jsmenu.cpp | 7 +- mythtv/libs/libmythui/jsmenu.h | 6 +- mythtv/libs/libmythui/lirc.cpp | 10 +- mythtv/libs/libmythui/lirc.h | 5 +- mythtv/libs/libmythui/mythrender_vdpau.cpp | 2 +- mythtv/libs/libmythui/mythscreentype.cpp | 8 +- mythtv/libs/libmythui/mythuihelper.cpp | 10 +- mythtv/libs/libmythui/mythuihelper.h | 4 +- mythtv/libs/libmythupnp/ssdp.cpp | 7 +- mythtv/libs/libmythupnp/ssdp.h | 4 +- mythtv/libs/libmythupnp/taskqueue.cpp | 8 +- mythtv/libs/libmythupnp/taskqueue.h | 8 +- mythtv/libs/libmythupnp/threadpool.cpp | 7 +- mythtv/libs/libmythupnp/threadpool.h | 4 +- mythtv/programs/mythbackend/autoexpire.cpp | 8 +- mythtv/programs/mythbackend/autoexpire.h | 16 +- mythtv/programs/mythbackend/housekeeper.cpp | 14 +- mythtv/programs/mythbackend/housekeeper.h | 19 +- mythtv/programs/mythbackend/main.cpp | 1 - mythtv/programs/mythbackend/mainserver.cpp | 27 +- mythtv/programs/mythbackend/mainserver.h | 8 +- mythtv/programs/mythbackend/scheduler.cpp | 18 +- mythtv/programs/mythbackend/scheduler.h | 10 +- .../mythfrontend/audiogeneralsettings.cpp | 5 +- .../mythfrontend/audiogeneralsettings.h | 20 +- .../mythfrontend/backendconnectionmanager.cpp | 10 +- .../programs/mythfrontend/networkcontrol.cpp | 11 +- mythtv/programs/mythfrontend/networkcontrol.h | 26 +- .../mythfrontend/playbackboxhelper.cpp | 16 +- .../programs/mythfrontend/playbackboxhelper.h | 8 +- .../mythfrontend/programinfocache.cpp | 11 +- mythtv/programs/mythfrontend/themechooser.cpp | 8 +- mythtv/programs/mythfrontend/upnpscanner.cpp | 11 +- mythtv/programs/mythfrontend/upnpscanner.h | 8 +- mythtv/programs/mythtranscode/mpeg2fix.cpp | 1 + 165 files changed, 1897 insertions(+), 1020 deletions(-) create mode 100644 mythtv/libs/libmythbase/mthread.cpp create mode 100644 mythtv/libs/libmythbase/mthread.h create mode 100644 mythtv/libs/libmythbase/mthreadpool.cpp create mode 100644 mythtv/libs/libmythbase/mthreadpool.h diff --git a/mythplugins/mytharchive/mytharchive/recordingselector.cpp b/mythplugins/mytharchive/mytharchive/recordingselector.cpp index 6276d3ab3f0..db80787def4 100644 --- a/mythplugins/mytharchive/mytharchive/recordingselector.cpp +++ b/mythplugins/mytharchive/mytharchive/recordingselector.cpp @@ -9,11 +9,11 @@ #include #include #include -#include // mythtv #include #include +#include #include #include #include @@ -24,26 +24,26 @@ #include #include #include -#include "mythlogging.h" +#include // mytharchive #include "recordingselector.h" #include "archiveutil.h" -class GetRecordingListThread : public QThread +class GetRecordingListThread : public MThread { public: - GetRecordingListThread(RecordingSelector *parent) + GetRecordingListThread(RecordingSelector *parent) : + MThread("GetRecordingList"), m_parent(parent) { - m_parent = parent; start(); } virtual void run(void) { - threadRegister("GetRecordingList"); + RunProlog(); m_parent->getRecordingList(); - threadDeregister(); + RunEpilog(); } RecordingSelector *m_parent; @@ -138,7 +138,7 @@ void RecordingSelector::Init(void) while (thread->isRunning()) { qApp->processEvents(); - usleep(100); + usleep(2000); } if (!m_recordingList || m_recordingList->size() == 0) diff --git a/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp b/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp index 4d66cf7a103..72b8ba11ebb 100644 --- a/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp +++ b/mythplugins/mythgallery/mythgallery/galleryfilterdlg.cpp @@ -28,6 +28,7 @@ using namespace std; #include #include #include +#include // MythGallery headers #include "galleryfilterdlg.h" @@ -35,7 +36,7 @@ using namespace std; #define LOC QString("GalleryFilterDlg:") -class FilterScanThread : public QThread +class FilterScanThread : public MThread { public: FilterScanThread(const QString& dir, const GalleryFilter& flt, @@ -52,21 +53,20 @@ class FilterScanThread : public QThread FilterScanThread::FilterScanThread(const QString& dir, const GalleryFilter& flt, int *dirCount, int *imageCount, - int *movieCount) + int *movieCount) : + MThread("FilterScan"), m_filter(flt), m_dir(dir), m_dirCount(dirCount), + m_imgCount(imageCount), m_movCount(movieCount) { - m_dir = dir; - m_filter = flt; - m_dirCount = dirCount; - m_imgCount = imageCount; - m_movCount = movieCount; } void FilterScanThread::run() { - threadRegister("FilterScan"); + RunProlog(); + GalleryFilter::TestFilter(m_dir, m_filter, m_dirCount, m_imgCount, m_movCount); - threadDeregister(); + + RunEpilog(); } GalleryFilterDialog::GalleryFilterDialog(MythScreenStack *parent, QString name, diff --git a/mythplugins/mythgallery/mythgallery/glsingleview.cpp b/mythplugins/mythgallery/mythgallery/glsingleview.cpp index eeb8a86b984..a95724bfc74 100644 --- a/mythplugins/mythgallery/mythgallery/glsingleview.cpp +++ b/mythplugins/mythgallery/mythgallery/glsingleview.cpp @@ -1517,12 +1517,16 @@ void GLSingleView::FindRandXY(float &x_loc, float &y_loc) y_loc = -1 * y_loc; } -KenBurnsImageLoader::KenBurnsImageLoader(GLSingleView *singleView, ThumbList &itemList, QSize texSize, QSize screenSize) +KenBurnsImageLoader::KenBurnsImageLoader( + GLSingleView *singleView, ThumbList &itemList, + QSize texSize, QSize screenSize) : + MThread("KenBurnsImageLoader"), + m_singleView(singleView), + m_itemList(itemList), + m_pos(0), + m_screenSize(screenSize), + m_texSize(texSize) { - m_singleView = singleView; - m_itemList = itemList; - m_texSize = texSize; - m_screenSize = screenSize; } void KenBurnsImageLoader::Initialize(int pos) @@ -1532,18 +1536,23 @@ void KenBurnsImageLoader::Initialize(int pos) void KenBurnsImageLoader::run() { - threadRegister("KenBurnsImageLoader"); + RunProlog(); ThumbItem *item = m_itemList.at(m_pos); if (!item) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("No item at %1").arg(m_pos)); + RunEpilog(); return; } QImage image(item->GetPath()); if (image.isNull()) + { + RunEpilog(); return; - + } + m_singleView->LoadImage(QGLWidget::convertToGLFormat(image.scaled(m_texSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)), image.size()); m_singleView->Ready(); - threadDeregister(); + + RunEpilog(); } diff --git a/mythplugins/mythgallery/mythgallery/glsingleview.h b/mythplugins/mythgallery/mythgallery/glsingleview.h index 3e7cf619aea..1fb55035811 100644 --- a/mythplugins/mythgallery/mythgallery/glsingleview.h +++ b/mythplugins/mythgallery/mythgallery/glsingleview.h @@ -25,8 +25,9 @@ // MythTV plugin headers -#include #include +#include +#include // MythGallery headers #include "imageview.h" @@ -155,7 +156,7 @@ class GLSingleView : public QGLWidget, public ImageView }; -class KenBurnsImageLoader : public QThread +class KenBurnsImageLoader : public MThread { public: KenBurnsImageLoader(GLSingleView *singleView, ThumbList &itemList, QSize m_texSize, QSize m_screenSize); diff --git a/mythplugins/mythgallery/mythgallery/iconview.cpp b/mythplugins/mythgallery/mythgallery/iconview.cpp index 44ccbe828dd..03adabe9a77 100644 --- a/mythplugins/mythgallery/mythgallery/iconview.cpp +++ b/mythplugins/mythgallery/mythgallery/iconview.cpp @@ -39,10 +39,10 @@ using namespace std; #include #include #include +#include #include #include #include -#include "mythlogging.h" // MythGallery headers #include "galleryutil.h" @@ -58,7 +58,7 @@ using namespace std; QEvent::Type ChildCountEvent::kEventType = (QEvent::Type) QEvent::registerEventType(); -class FileCopyThread: public QThread +class FileCopyThread : public MThread { public: FileCopyThread(IconView *parent, bool move); @@ -71,20 +71,19 @@ class FileCopyThread: public QThread volatile int m_progress; }; -FileCopyThread::FileCopyThread(IconView *parent, bool move) +FileCopyThread::FileCopyThread(IconView *parent, bool move) : + MThread("FileCopy"), m_move(move), m_parent(parent), m_progress(0) { - m_move = move; - m_parent = parent; - m_progress = 0; } void FileCopyThread::run() { + RunProlog(); + QStringList::iterator it; QFileInfo fi; QFileInfo dest; - threadRegister("FileCopy"); m_progress = 0; for (it = m_parent->m_itemMarked.begin(); it != m_parent->m_itemMarked.end(); it++) @@ -97,7 +96,8 @@ void FileCopyThread::run() m_progress++; } - threadDeregister(); + + RunEpilog(); } /////////////////////////////////////////////////////////////////////////////// @@ -1509,9 +1509,9 @@ ThumbItem *IconView::GetCurrentThumb(void) /////////////////////////////////////////////////////////////////////////////// -ChildCountThread::ChildCountThread(QObject *parent) +ChildCountThread::ChildCountThread(QObject *parent) : + MThread("ChildCountThread"), m_parent(parent) { - m_parent = parent; } ChildCountThread::~ChildCountThread() @@ -1536,7 +1536,8 @@ void ChildCountThread::cancel() void ChildCountThread::run() { - threadRegister("ChildCount"); + RunProlog(); + while (moreWork()) { QString file; @@ -1558,7 +1559,8 @@ void ChildCountThread::run() // inform parent we have got a count ready for it QApplication::postEvent(m_parent, new ChildCountEvent(ccd)); } - threadDeregister(); + + RunEpilog(); } bool ChildCountThread::moreWork() diff --git a/mythplugins/mythgallery/mythgallery/iconview.h b/mythplugins/mythgallery/mythgallery/iconview.h index c72185ddcdf..4972fa78910 100644 --- a/mythplugins/mythgallery/mythgallery/iconview.h +++ b/mythplugins/mythgallery/mythgallery/iconview.h @@ -25,7 +25,6 @@ #include #include #include -#include // MythTV headers #include @@ -34,6 +33,7 @@ #include #include #include +#include // MythGallery headers #include "galleryfilter.h" @@ -176,7 +176,7 @@ class ChildCountEvent : public QEvent static Type kEventType; }; -class ChildCountThread : public QThread +class ChildCountThread : public MThread { public: diff --git a/mythplugins/mythgallery/mythgallery/thumbgenerator.cpp b/mythplugins/mythgallery/mythgallery/thumbgenerator.cpp index af53d7d1c45..86073ad82c6 100644 --- a/mythplugins/mythgallery/mythgallery/thumbgenerator.cpp +++ b/mythplugins/mythgallery/mythgallery/thumbgenerator.cpp @@ -28,10 +28,11 @@ #include // myth -#include "mythtv/mythcontext.h" -#include "mythtv/util.h" #include +#include #include +#include +#include // mythgallery #include "config.h" @@ -49,12 +50,10 @@ QEvent::Type ThumbGenEvent::kEventType = (QEvent::Type) QEvent::registerEventType(); -ThumbGenerator::ThumbGenerator(QObject *parent, int w, int h) +ThumbGenerator::ThumbGenerator(QObject *parent, int w, int h) : + MThread("ThumbGenerator"), m_parent(parent), + m_isGallery(false), m_width(w), m_height(h) { - m_parent = parent; - m_width = w; - m_height = h; - m_isGallery = false; } ThumbGenerator::~ThumbGenerator() @@ -95,7 +94,8 @@ void ThumbGenerator::cancel() void ThumbGenerator::run() { - threadRegister("ThumbGenerator"); + RunProlog(); + while (moreWork()) { @@ -180,7 +180,8 @@ void ThumbGenerator::run() } } } - threadDeregister(); + + RunEpilog(); } bool ThumbGenerator::moreWork() diff --git a/mythplugins/mythgallery/mythgallery/thumbgenerator.h b/mythplugins/mythgallery/mythgallery/thumbgenerator.h index e2645d8adb6..25fc4883f38 100644 --- a/mythplugins/mythgallery/mythgallery/thumbgenerator.h +++ b/mythplugins/mythgallery/mythgallery/thumbgenerator.h @@ -22,11 +22,11 @@ #ifndef THUMBGENERATOR_H #define THUMBGENERATOR_H -#include -#include #include #include +#include + class QObject; class QImage; @@ -47,7 +47,7 @@ class ThumbGenEvent : public QEvent static Type kEventType; }; -class ThumbGenerator : public QThread +class ThumbGenerator : public MThread { public: diff --git a/mythplugins/mythmusic/mythmusic/avfdecoder.cpp b/mythplugins/mythmusic/mythmusic/avfdecoder.cpp index 6327f1ff91d..52ac4045538 100644 --- a/mythplugins/mythmusic/mythmusic/avfdecoder.cpp +++ b/mythplugins/mythmusic/mythmusic/avfdecoder.cpp @@ -88,6 +88,7 @@ avfDecoder::avfDecoder(const QString &file, DecoderFactory *d, QIODevice *i, m_byteIOContext(NULL), errcode(0), m_samples(NULL) { + setObjectName("avfDecoder"); setFilename(file); memset(&m_params, 0, sizeof(AVFormatParameters)); } @@ -372,10 +373,13 @@ void avfDecoder::deinit() void avfDecoder::run() { + RunProlog(); if (!inited) + { + RunEpilog(); return; + } - threadRegister("avfDecoder"); AVPacket pkt, tmp_pkt; char *s; int data_size, dec_len; @@ -496,7 +500,7 @@ void avfDecoder::run() } deinit(); - threadDeregister(); + RunEpilog(); } MetaIO* avfDecoder::doCreateTagger(void) diff --git a/mythplugins/mythmusic/mythmusic/cddecoder.cpp b/mythplugins/mythmusic/mythmusic/cddecoder.cpp index 4ce663aa37a..d602f6ef7a8 100644 --- a/mythplugins/mythmusic/mythmusic/cddecoder.cpp +++ b/mythplugins/mythmusic/mythmusic/cddecoder.cpp @@ -53,6 +53,7 @@ CdDecoder::CdDecoder(const QString &file, DecoderFactory *d, QIODevice *i, start(0), end(0), curpos(0) { + setObjectName("CdDecoder"); setFilename(file); } @@ -188,10 +189,13 @@ static void paranoia_cb(long inpos, int function) void CdDecoder::run() { + RunProlog(); if (!inited) + { + RunEpilog(); return; + } - threadRegister("CdDecoder"); stat = DecoderEvent::Decoding; { DecoderEvent e((DecoderEvent::Type) stat); @@ -284,7 +288,7 @@ void CdDecoder::run() } deinit(); - threadDeregister(); + RunEpilog(); } void CdDecoder::setCDSpeed(int speed) diff --git a/mythplugins/mythmusic/mythmusic/cdrip.cpp b/mythplugins/mythmusic/mythmusic/cdrip.cpp index ac5d26b90ee..561e7a619f9 100644 --- a/mythplugins/mythmusic/mythmusic/cdrip.cpp +++ b/mythplugins/mythmusic/mythmusic/cdrip.cpp @@ -83,30 +83,30 @@ QEvent::Type RipStatusEvent::kFinishedEvent = QEvent::Type RipStatusEvent::kEncoderErrorEvent = (QEvent::Type) QEvent::registerEventType(); -CDScannerThread::CDScannerThread(Ripper *ripper) +CDScannerThread::CDScannerThread(Ripper *ripper) : + MThread("CDScanner"), m_parent(ripper) { - m_parent = ripper; } void CDScannerThread::run() { - threadRegister("CDScanner"); + RunProlog(); m_parent->scanCD(); - threadDeregister(); + RunEpilog(); } /////////////////////////////////////////////////////////////////////////////// -CDEjectorThread::CDEjectorThread(Ripper *ripper) +CDEjectorThread::CDEjectorThread(Ripper *ripper) : + MThread("CDEjector"), m_parent(ripper) { - m_parent = ripper; } void CDEjectorThread::run() { - threadRegister("CDEjector"); + RunProlog(); m_parent->ejectCD(); - threadDeregister(); + RunEpilog(); } /////////////////////////////////////////////////////////////////////////////// @@ -150,6 +150,7 @@ static void paranoia_cb(long inpos, int function) CDRipperThread::CDRipperThread(RipStatus *parent, QString device, QVector *tracks, int quality) : + MThread("CDRipper"), m_parent(parent), m_quit(false), m_CDdevice(device), m_quality(quality), m_tracks(tracks), m_totalSectors(0), @@ -176,10 +177,13 @@ bool CDRipperThread::isCancelled(void) void CDRipperThread::run(void) { + RunProlog(); if (!m_tracks->size() > 0) + { + RunEpilog(); return; + } - threadRegister("CDRipper"); Metadata *track = m_tracks->at(0)->metadata; QString tots; @@ -301,6 +305,7 @@ void CDRipperThread::run(void) LOG(VB_GENERAL, LOG_ERR, "MythMusic: Encoder failed" " to open file for writing"); + RunEpilog(); return; } } @@ -313,12 +318,16 @@ void CDRipperThread::run(void) new RipStatusEvent(RipStatusEvent::kEncoderErrorEvent, "Failed to create encoder")); LOG(VB_GENERAL, LOG_ERR, "MythMusic: No encoder, failing"); + RunEpilog(); return; } ripTrack(m_CDdevice, encoder.get(), trackno + 1); if (isCancelled()) + { + RunEpilog(); return; + } // save the metadata to the DB if (m_tracks->at(trackno)->active) @@ -337,7 +346,7 @@ void CDRipperThread::run(void) QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kFinishedEvent, "")); - threadDeregister(); + RunEpilog(); } int CDRipperThread::ripTrack(QString &cddevice, Encoder *encoder, int tracknum) @@ -600,7 +609,7 @@ void Ripper::startScanCD(void) OpenBusyPopup(message); m_scanThread = new CDScannerThread(this); - connect(m_scanThread, SIGNAL(finished()), SLOT(ScanFinished())); + connect(m_scanThread->qthread(), SIGNAL(finished()), SLOT(ScanFinished())); m_scanThread->start(); } @@ -1200,7 +1209,8 @@ void Ripper::startEjectCD() OpenBusyPopup(message); m_ejectThread = new CDEjectorThread(this); - connect(m_ejectThread, SIGNAL(finished()), SLOT(EjectFinished())); + connect(m_ejectThread->qthread(), + SIGNAL(finished()), SLOT(EjectFinished())); m_ejectThread->start(); } diff --git a/mythplugins/mythmusic/mythmusic/cdrip.h b/mythplugins/mythmusic/mythmusic/cdrip.h index 5edc10b4f02..6b3d980cf9b 100644 --- a/mythplugins/mythmusic/mythmusic/cdrip.h +++ b/mythplugins/mythmusic/mythmusic/cdrip.h @@ -7,6 +7,7 @@ #include #include +#include class MythUIText; class MythUITextEdit; @@ -19,7 +20,7 @@ class CdDecoder; class Encoder; class Ripper; -class CDScannerThread: public QThread +class CDScannerThread: public MThread { public: CDScannerThread(Ripper *ripper); @@ -29,7 +30,7 @@ class CDScannerThread: public QThread Ripper *m_parent; }; -class CDEjectorThread: public QThread +class CDEjectorThread: public MThread { public: CDEjectorThread(Ripper *ripper); @@ -48,7 +49,7 @@ typedef struct class RipStatus; -class CDRipperThread: public QThread +class CDRipperThread: public MThread { public: CDRipperThread(RipStatus *parent, QString device, diff --git a/mythplugins/mythmusic/mythmusic/databasebox.cpp b/mythplugins/mythmusic/mythmusic/databasebox.cpp index 007cc3ecc93..67971692565 100644 --- a/mythplugins/mythmusic/mythmusic/databasebox.cpp +++ b/mythplugins/mythmusic/mythmusic/databasebox.cpp @@ -1270,16 +1270,15 @@ void DatabaseBox::setCDTitle(const QString& title) cditem->setText(title); } -ReadCDThread::ReadCDThread(const QString &dev) +ReadCDThread::ReadCDThread(const QString &dev) : + MThread("ReadCD"), m_CDdevice(dev), cd_status_changed(false) { - m_CDdevice = dev; - cd_status_changed = false; } void ReadCDThread::run() { + RunProlog(); #ifndef USING_MINGW - threadRegister("ReadCD"); // lock all_music and cd_status_changed while running thread QMutexLocker locker(getLock()); @@ -1368,7 +1367,7 @@ void ReadCDThread::run() } delete decoder; - threadDeregister(); #endif // USING_MINGW + RunEpilog(); } diff --git a/mythplugins/mythmusic/mythmusic/databasebox.h b/mythplugins/mythmusic/mythmusic/databasebox.h index 6f770abeca3..22d7a7d94c9 100644 --- a/mythplugins/mythmusic/mythmusic/databasebox.h +++ b/mythplugins/mythmusic/mythmusic/databasebox.h @@ -5,20 +5,21 @@ using namespace std; #include -#include #include #include "metadata.h" #include "playlist.h" + #include #include #include +#include class TreeCheckItem; class QTimer; class QKeyEvent; -class ReadCDThread : public QThread +class ReadCDThread : public MThread { public: diff --git a/mythplugins/mythmusic/mythmusic/decoder.cpp b/mythplugins/mythmusic/mythmusic/decoder.cpp index d605d15d52b..96c233236ac 100644 --- a/mythplugins/mythmusic/mythmusic/decoder.cpp +++ b/mythplugins/mythmusic/mythmusic/decoder.cpp @@ -24,8 +24,8 @@ QEvent::Type DecoderEvent::Finished = QEvent::Type DecoderEvent::Error = (QEvent::Type) QEvent::registerEventType(); -Decoder::Decoder(DecoderFactory *d, QIODevice *i, AudioOutput *o) - : fctry(d), in(i), out(o) +Decoder::Decoder(DecoderFactory *d, QIODevice *i, AudioOutput *o) : + MThread("MythMusicDecoder"), fctry(d), in(i), out(o) { } diff --git a/mythplugins/mythmusic/mythmusic/decoder.h b/mythplugins/mythmusic/mythmusic/decoder.h index 8557aed1967..add37bad950 100644 --- a/mythplugins/mythmusic/mythmusic/decoder.h +++ b/mythplugins/mythmusic/mythmusic/decoder.h @@ -5,13 +5,13 @@ #include #include -#include #include #include #include "config.h" #include +#include class Metadata; class MetaIO; @@ -63,7 +63,7 @@ class DecoderEvent : public MythEvent QString *error_msg; }; -class Decoder : public QThread, public MythObservable +class Decoder : public MThread, public MythObservable { public: virtual ~Decoder(); diff --git a/mythplugins/mythmusic/mythmusic/importmusic.cpp b/mythplugins/mythmusic/mythmusic/importmusic.cpp index 198f0caabb5..ceccbebdac3 100644 --- a/mythplugins/mythmusic/mythmusic/importmusic.cpp +++ b/mythplugins/mythmusic/mythmusic/importmusic.cpp @@ -62,16 +62,16 @@ static bool copyFile(const QString &src, const QString &dst) /////////////////////////////////////////////////////////////////////////////// -FileScannerThread::FileScannerThread(ImportMusicDialog *parent) +FileScannerThread::FileScannerThread(ImportMusicDialog *parent) : + MThread("FileScanner"), m_parent(parent) { - m_parent = parent; } void FileScannerThread::run() { - threadRegister("FileScanner"); + RunProlog(); m_parent->doScan(); - threadDeregister(); + RunEpilog(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/mythplugins/mythmusic/mythmusic/importmusic.h b/mythplugins/mythmusic/mythmusic/importmusic.h index b03cf2341eb..c813062b946 100644 --- a/mythplugins/mythmusic/mythmusic/importmusic.h +++ b/mythplugins/mythmusic/mythmusic/importmusic.h @@ -5,10 +5,10 @@ #include using namespace std; -#include #include #include +#include class Metadata; class ImportMusicDialog; @@ -28,7 +28,7 @@ typedef struct bool metadataHasChanged; } TrackInfo; -class FileScannerThread: public QThread +class FileScannerThread: public MThread { public: FileScannerThread(ImportMusicDialog *parent); diff --git a/mythplugins/mythmusic/mythmusic/metadata.cpp b/mythplugins/mythmusic/mythmusic/metadata.cpp index 53751e28354..82523d57d05 100644 --- a/mythplugins/mythmusic/mythmusic/metadata.cpp +++ b/mythplugins/mythmusic/mythmusic/metadata.cpp @@ -928,18 +928,18 @@ MetaIO* Metadata::getTagger(void) //-------------------------------------------------------------------------- -MetadataLoadingThread::MetadataLoadingThread(AllMusic *parent_ptr) +MetadataLoadingThread::MetadataLoadingThread(AllMusic *parent_ptr) : + MThread("MetadataLoading"), parent(parent_ptr) { - parent = parent_ptr; } void MetadataLoadingThread::run() { - threadRegister("MetadataLoading"); + RunProlog(); //if you want to simulate a big music collection load //sleep(3); parent->resync(); - threadDeregister(); + RunEpilog(); } AllMusic::AllMusic(QString path_assignment, QString a_startdir) diff --git a/mythplugins/mythmusic/mythmusic/metadata.h b/mythplugins/mythmusic/mythmusic/metadata.h index ae6bbee7a71..e637ea8c8cb 100644 --- a/mythplugins/mythmusic/mythmusic/metadata.h +++ b/mythplugins/mythmusic/mythmusic/metadata.h @@ -8,10 +8,10 @@ using namespace std; // qt #include #include -#include // mythtv #include +#include // mythmusic #include "treecheckitem.h" @@ -348,7 +348,7 @@ class MusicNode //--------------------------------------------------------------------------- -class MetadataLoadingThread : public QThread +class MetadataLoadingThread : public MThread { public: diff --git a/mythplugins/mythmusic/mythmusic/playbackbox.cpp b/mythplugins/mythmusic/mythmusic/playbackbox.cpp index b95cff27afa..bdda60763f5 100644 --- a/mythplugins/mythmusic/mythmusic/playbackbox.cpp +++ b/mythplugins/mythmusic/mythmusic/playbackbox.cpp @@ -1006,7 +1006,7 @@ void PlaybackBoxMusic::occasionallyCheckCD() postUpdate(); } - if (scan_for_cd && !cd_reader_thread->running()) + if (scan_for_cd && !cd_reader_thread->isRunning()) cd_reader_thread->start(); } diff --git a/mythplugins/mythmusic/mythmusic/playlistcontainer.cpp b/mythplugins/mythmusic/mythmusic/playlistcontainer.cpp index f8ecb66559a..143f734ef7f 100644 --- a/mythplugins/mythmusic/mythmusic/playlistcontainer.cpp +++ b/mythplugins/mythmusic/mythmusic/playlistcontainer.cpp @@ -6,21 +6,20 @@ #include "mythlogging.h" PlaylistLoadingThread::PlaylistLoadingThread(PlaylistContainer *parent_ptr, - AllMusic *all_music_ptr) + AllMusic *all_music_ptr) : + MThread("PlaylistLoading"), parent(parent_ptr), all_music(all_music_ptr) { - parent = parent_ptr; - all_music = all_music_ptr; } void PlaylistLoadingThread::run() { - threadRegister("PlaylistLoading"); - while(!all_music->doneLoading()) + RunProlog(); + while (!all_music->doneLoading()) { - sleep(1); + msleep(250); } parent->load(); - threadDeregister(); + RunEpilog(); } #define LOC QString("PlaylistContainer: ") @@ -68,7 +67,8 @@ PlaylistContainer::PlaylistContainer(AllMusic *all_music, const QString &host_na PlaylistContainer::~PlaylistContainer() { playlists_loader->wait(); - playlists_loader->deleteLater(); + delete playlists_loader; + playlists_loader = NULL; if (active_playlist) delete active_playlist; diff --git a/mythplugins/mythmusic/mythmusic/playlistcontainer.h b/mythplugins/mythmusic/mythmusic/playlistcontainer.h index 56d7e4eb2c7..abc4b31293b 100644 --- a/mythplugins/mythmusic/mythmusic/playlistcontainer.h +++ b/mythplugins/mythmusic/mythmusic/playlistcontainer.h @@ -1,11 +1,11 @@ #ifndef _PLAYLIST_CONTAINER_H_ #define _PLAYLIST_CONTAINER_H_ -#include +#include "mthread.h" #include "playlist.h" -class PlaylistLoadingThread : public QThread +class PlaylistLoadingThread : public MThread { public: PlaylistLoadingThread(PlaylistContainer *parent_ptr, diff --git a/mythtv/libs/libmyth/audio/audiooutputbase.cpp b/mythtv/libs/libmyth/audio/audiooutputbase.cpp index 836912ccd62..5afbd8b42a8 100644 --- a/mythtv/libs/libmyth/audio/audiooutputbase.cpp +++ b/mythtv/libs/libmyth/audio/audiooutputbase.cpp @@ -45,6 +45,7 @@ static const char *quality_string(int q) } AudioOutputBase::AudioOutputBase(const AudioSettings &settings) : + MThread("AudioOutputBase"), // protected channels(-1), codec(CODEC_ID_NONE), bytes_per_frame(0), output_bytes_per_frame(0), @@ -1692,11 +1693,11 @@ void AudioOutputBase::Drain() */ void AudioOutputBase::run(void) { - threadRegister("AudioOutputBase"); + RunProlog(); VBAUDIO(QString("kickoffOutputAudioLoop: pid = %1").arg(getpid())); OutputAudioLoop(); VBAUDIO("kickoffOutputAudioLoop exiting"); - threadDeregister(); + RunEpilog(); } int AudioOutputBase::readOutputData(unsigned char*, int) diff --git a/mythtv/libs/libmyth/audio/audiooutputbase.h b/mythtv/libs/libmyth/audio/audiooutputbase.h index 84dbda2aa48..86df8b5c375 100644 --- a/mythtv/libs/libmyth/audio/audiooutputbase.h +++ b/mythtv/libs/libmyth/audio/audiooutputbase.h @@ -12,12 +12,12 @@ using namespace std; #include #include #include -#include // MythTV headers #include "audiooutput.h" #include "samplerate.h" #include "mythlogging.h" +#include "mthread.h" #define VBAUDIO(str) LOG(VB_AUDIO, LOG_INFO, LOC + str) #define VBAUDIOTS(str) LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + str) @@ -48,7 +48,7 @@ class AsyncLooseLock // Forward declaration of SPDIF encoder class SPDIFEncoder; -class AudioOutputBase : public AudioOutput, public QThread +class AudioOutputBase : public AudioOutput, public MThread { public: AudioOutputBase(const AudioSettings &settings); diff --git a/mythtv/libs/libmyth/audio/audiopulsehandler.cpp b/mythtv/libs/libmyth/audio/audiopulsehandler.cpp index 63be092b9d4..3f6fb035403 100644 --- a/mythtv/libs/libmyth/audio/audiopulsehandler.cpp +++ b/mythtv/libs/libmyth/audio/audiopulsehandler.cpp @@ -1,7 +1,11 @@ +#include +#include #include + +#include "audiopulsehandler.h" #include "mythlogging.h" +#include "mthread.h" #include "util.h" -#include "audiopulsehandler.h" #define LOC QString("Pulse: ") @@ -269,7 +273,7 @@ bool PulseHandler::SuspendInternal(bool suspend) return false; // just in case it all goes pete tong - if (QThread::currentThread() != m_thread) + if (!is_current_thread(m_thread)) LOG(VB_AUDIO, LOG_WARNING, LOC + "PulseHandler called from a different thread"); diff --git a/mythtv/libs/libmyth/audio/audiopulsehandler.h b/mythtv/libs/libmyth/audio/audiopulsehandler.h index 872c4872b4a..ad1ffd2dbc6 100644 --- a/mythtv/libs/libmyth/audio/audiopulsehandler.h +++ b/mythtv/libs/libmyth/audio/audiopulsehandler.h @@ -1,9 +1,10 @@ #ifndef AUDIOPULSEHANDLER_H #define AUDIOPULSEHANDLER_H -#include #include +class QThread; + class PulseHandler { public: diff --git a/mythtv/libs/libmyth/mythcontext.cpp b/mythtv/libs/libmyth/mythcontext.cpp index 1636124d2f5..fd77f8c001f 100644 --- a/mythtv/libs/libmyth/mythcontext.cpp +++ b/mythtv/libs/libmyth/mythcontext.cpp @@ -1107,10 +1107,10 @@ bool MythContext::Init(const bool gui, MythContext::~MythContext() { - if (QThreadPool::globalInstance()->activeThreadCount()) + if (MThreadPool::globalInstance()->activeThreadCount()) LOG(VB_GENERAL, LOG_INFO, "Waiting for threads to exit."); - QThreadPool::globalInstance()->waitForDone(); + MThreadPool::globalInstance()->waitForDone(); logStop(); delete gCoreContext; diff --git a/mythtv/libs/libmyth/mythmediamonitor.cpp b/mythtv/libs/libmyth/mythmediamonitor.cpp index 11be9886410..198a9914cc2 100644 --- a/mythtv/libs/libmyth/mythmediamonitor.cpp +++ b/mythtv/libs/libmyth/mythmediamonitor.cpp @@ -34,8 +34,8 @@ using namespace std; MediaMonitor *MediaMonitor::c_monitor = NULL; // MonitorThread -MonitorThread::MonitorThread(MediaMonitor* pMon, unsigned long interval) - : QThread() +MonitorThread::MonitorThread(MediaMonitor* pMon, unsigned long interval) : + MThread("Monitor") { m_Monitor = pMon; m_Interval = interval; @@ -45,13 +45,13 @@ MonitorThread::MonitorThread(MediaMonitor* pMon, unsigned long interval) // loop and check it's devices. void MonitorThread::run(void) { - threadRegister("Monitor"); + RunProlog(); while (m_Monitor && m_Monitor->IsActive()) { m_Monitor->CheckDevices(); msleep(m_Interval); } - threadDeregister(); + RunEpilog(); } //////////////////////////////////////////////////////////////////////// diff --git a/mythtv/libs/libmyth/mythmediamonitor.h b/mythtv/libs/libmyth/mythmediamonitor.h index ea5fa97dcc7..b723bbcea4c 100644 --- a/mythtv/libs/libmyth/mythmediamonitor.h +++ b/mythtv/libs/libmyth/mythmediamonitor.h @@ -3,10 +3,10 @@ #include #include -#include #include #include +#include "mthread.h" #include "mythexp.h" #include "mythmedia.h" @@ -20,7 +20,7 @@ struct MHData }; class MediaMonitor; -class MonitorThread : public QThread +class MonitorThread : public MThread { public: MonitorThread(MediaMonitor* pMon, unsigned long interval); diff --git a/mythtv/libs/libmyth/netgrabbermanager.cpp b/mythtv/libs/libmyth/netgrabbermanager.cpp index 522cb74df4a..a494ba1190e 100644 --- a/mythtv/libs/libmyth/netgrabbermanager.cpp +++ b/mythtv/libs/libmyth/netgrabbermanager.cpp @@ -25,7 +25,7 @@ GrabberScript::GrabberScript(const QString& title, const QString& image, const bool& search, const bool& tree, const QString& description, const QString& commandline, const double& version) : - m_lock(QMutex::Recursive) + MThread("GrabberScript"), m_lock(QMutex::Recursive) { m_title = title; m_image = image; @@ -45,7 +45,7 @@ GrabberScript::~GrabberScript() void GrabberScript::run() { - threadRegister("GrabberScript"); + RunProlog(); QMutexLocker locker(&m_lock); QString commandline = m_commandline; @@ -89,7 +89,7 @@ void GrabberScript::run() .arg(m_title)); emit finished(); - threadDeregister(); + RunEpilog(); } void GrabberScript::parseDBTree(const QString &feedtitle, const QString &path, @@ -186,7 +186,8 @@ void GrabberManager::refreshAll() m_refreshAll = true; } -GrabberDownloadThread::GrabberDownloadThread(QObject *parent) +GrabberDownloadThread::GrabberDownloadThread(QObject *parent) : + MThread("GrabberDownload") { m_parent = parent; m_refreshAll = false; @@ -217,7 +218,8 @@ void GrabberDownloadThread::refreshAll() void GrabberDownloadThread::run() { - threadRegister("GrabberDownload"); + RunProlog(); + m_scripts = findAllDBTreeGrabbers(); uint updateFreq = gCoreContext->GetNumSetting( "netsite.updateFreq", 24); @@ -238,7 +240,7 @@ void GrabberDownloadThread::run() if (m_parent) QCoreApplication::postEvent(m_parent, new GrabberUpdateEvent()); - threadDeregister(); + RunEpilog(); } Search::Search() diff --git a/mythtv/libs/libmyth/netgrabbermanager.h b/mythtv/libs/libmyth/netgrabbermanager.h index 833f21a6c89..3ac3de7198e 100644 --- a/mythtv/libs/libmyth/netgrabbermanager.h +++ b/mythtv/libs/libmyth/netgrabbermanager.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include "mthread.h" #include #include #include @@ -13,7 +13,7 @@ #include "mythexp.h" #include "mythsystem.h" -class MPUBLIC GrabberScript : public QThread +class MPUBLIC GrabberScript : public QObject, public MThread { Q_OBJECT @@ -106,8 +106,10 @@ class MPUBLIC GrabberUpdateEvent : public QEvent ~GrabberUpdateEvent() {} }; -class MPUBLIC GrabberDownloadThread : public QThread +class MPUBLIC GrabberDownloadThread : public QObject, public MThread { + Q_OBJECT + public: GrabberDownloadThread(QObject *parent); @@ -116,6 +118,9 @@ class MPUBLIC GrabberDownloadThread : public QThread void refreshAll(); void cancel(); + signals: + void finished(); + protected: void run(); diff --git a/mythtv/libs/libmyth/programinfoupdater.cpp b/mythtv/libs/libmyth/programinfoupdater.cpp index 5d69a6ea419..838cc6f35b5 100644 --- a/mythtv/libs/libmyth/programinfoupdater.cpp +++ b/mythtv/libs/libmyth/programinfoupdater.cpp @@ -1,7 +1,9 @@ +// MythTV headers #include "programinfoupdater.h" +#include "mthreadpool.h" +#include "mythlogging.h" #include "remoteutil.h" #include "compat.h" -#include "mythlogging.h" uint qHash(const PIKey &k) { @@ -35,7 +37,7 @@ void ProgramInfoUpdater::insert( if (!isRunning) { isRunning = true; - QThreadPool::globalInstance()->start(this); + MThreadPool::globalInstance()->start(this, "ProgramInfoUpdater"); } else moreWork.wakeAll(); @@ -45,8 +47,6 @@ void ProgramInfoUpdater::run(void) { bool workDone; - threadRegister("ProgramInfoUpdater"); - do { workDone = false; @@ -106,7 +106,6 @@ void ProgramInfoUpdater::run(void) lock.unlock(); } while( workDone ); - threadDeregister(); isRunning = false; } diff --git a/mythtv/libs/libmyth/programinfoupdater.h b/mythtv/libs/libmyth/programinfoupdater.h index 14ae63e3ef5..6d3042da627 100644 --- a/mythtv/libs/libmyth/programinfoupdater.h +++ b/mythtv/libs/libmyth/programinfoupdater.h @@ -9,11 +9,11 @@ using namespace std; // Qt headers -#include +#include #include +#include #include #include -#include typedef enum PIAction { kPIAdd, diff --git a/mythtv/libs/libmythbase/libmythbase.pro b/mythtv/libs/libmythbase/libmythbase.pro index 690ed73c525..6961839333e 100644 --- a/mythtv/libs/libmythbase/libmythbase.pro +++ b/mythtv/libs/libmythbase/libmythbase.pro @@ -23,6 +23,7 @@ HEADERS += util.h mythhdd.h mythcdrom.h autodeletedeque.h dbutil.h HEADERS += mythhttppool.h mythhttphandler.h mythdeque.h mythlogging.h HEADERS += mythbaseutil.h referencecounter.h version.h mythcommandlineparser.h HEADERS += mythscheduler.h +HEADERS += mthread.h mthreadpool.h SOURCES += mythsocket.cpp mythsocketthread.cpp msocketdevice.cpp SOURCES += mythdbcon.cpp mythdb.cpp oldsettings.cpp @@ -35,6 +36,7 @@ SOURCES += unzip.cpp iso639.cpp iso3166.cpp mythmedia.cpp util.cpp SOURCES += mythhdd.cpp mythcdrom.cpp dbutil.cpp SOURCES += mythhttppool.cpp mythhttphandler.cpp logging.cpp SOURCES += referencecounter.cpp mythcommandlineparser.cpp +SOURCES += mthread.cpp mthreadpool.cpp win32:SOURCES += msocketdevice_win.cpp unix { @@ -59,7 +61,7 @@ inc.files += mythcorecontext.h mythsystem.h storagegroup.h inc.files += mythcoreutil.h mythlocale.h mythdownloadmanager.h inc.files += mythtranslation.h iso639.h iso3166.h mythmedia.h util.h inc.files += mythcdrom.h autodeletedeque.h dbutil.h mythhttppool.h mythdeque.h -inc.files += referencecounter.h mythcommandlineparser.h +inc.files += referencecounter.h mythcommandlineparser.h mthread.h mthreadpool.h # Allow both #include and #include inc2.path = $${PREFIX}/include/mythtv/libmyth diff --git a/mythtv/libs/libmythbase/logging.cpp b/mythtv/libs/libmythbase/logging.cpp index b6708e0af1c..bf6c0938730 100644 --- a/mythtv/libs/libmythbase/logging.cpp +++ b/mythtv/libs/libmythbase/logging.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -423,7 +422,7 @@ bool DatabaseLogger::logqmsg(LoggingItem_t *item) m_host = strdup((char *)gCoreContext->GetHostName() .toLocal8Bit().constData()); - MSqlQuery query(MSqlQuery::LogCon()); + MSqlQuery query(MSqlQuery::InitCon()); query.prepare( m_query ); query.bindValue(":HOST", m_host); query.bindValue(":APPLICATION", m_application); @@ -446,6 +445,7 @@ bool DatabaseLogger::logqmsg(LoggingItem_t *item) } DBLoggerThread::DBLoggerThread(DatabaseLogger *logger) : + MThread("DBLogger"), m_logger(logger), m_queue(new QQueue), m_wait(new QWaitCondition()), aborted(false) { @@ -465,7 +465,8 @@ DBLoggerThread::~DBLoggerThread() void DBLoggerThread::run(void) { - threadRegister("DBLogger"); + RunProlog(); + LoggingItem_t *item; QMutexLocker qLock(&m_queueMutex); @@ -502,8 +503,7 @@ void DBLoggerThread::run(void) qLock.relock(); } - MSqlQuery::CloseLogCon(); - threadDeregister(); + RunEpilog(); } void DBLoggerThread::stop(void) @@ -539,7 +539,7 @@ bool DatabaseLogger::isDatabaseReady() bool DatabaseLogger::tableExists(const QString &table) { bool result = false; - MSqlQuery query(MSqlQuery::LogCon()); + MSqlQuery query(MSqlQuery::InitCon()); if (query.isConnected()) { QString sql = "SELECT INFORMATION_SCHEMA.TABLES.TABLE_NAME " @@ -622,6 +622,7 @@ void setThreadTid( LoggingItem_t *item ) LoggerThread::LoggerThread() : + MThread("Logger"), m_wait(new QWaitCondition()), aborted(false) { char *debug = getenv("VERBOSE_THREADS"); @@ -652,7 +653,7 @@ LoggerThread::~LoggerThread() void LoggerThread::run(void) { - threadRegister("Logger"); + RunProlog(); LoggingItem_t *item; logThreadFinished = false; @@ -750,6 +751,7 @@ void LoggerThread::run(void) } logThreadFinished = true; + RunEpilog(); } void LoggerThread::stop(void) diff --git a/mythtv/libs/libmythbase/logging.h b/mythtv/libs/libmythbase/logging.h index dcc87e86b8a..6fcb2bfac99 100644 --- a/mythtv/libs/libmythbase/logging.h +++ b/mythtv/libs/libmythbase/logging.h @@ -3,7 +3,6 @@ #ifdef __cplusplus #include -#include #include #include #include @@ -15,6 +14,7 @@ #include "mythbaseexp.h" // MBASE_PUBLIC , etc. #include "verbosedefs.h" +#include "mthread.h" #define LOGLINE_MAX 2048 @@ -105,9 +105,8 @@ class DatabaseLogger : public LoggerBase { }; class QWaitCondition; -class LoggerThread : public QThread { - Q_OBJECT - +class LoggerThread : public MThread +{ public: LoggerThread(); ~LoggerThread(); @@ -120,9 +119,8 @@ class LoggerThread : public QThread { #define MAX_QUEUE_LEN 1000 -class DBLoggerThread : public QThread { - Q_OBJECT - +class DBLoggerThread : public MThread +{ public: DBLoggerThread(DatabaseLogger *logger); ~DBLoggerThread(); diff --git a/mythtv/libs/libmythbase/mthread.cpp b/mythtv/libs/libmythbase/mthread.cpp new file mode 100644 index 00000000000..da54bc113fc --- /dev/null +++ b/mythtv/libs/libmythbase/mthread.cpp @@ -0,0 +1,315 @@ +/* -*- Mode: c++ -*- + * + * Class MThread + * + * Copyright (C) Daniel Kristjansson 2011 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +using namespace std; + +// Qt headers +#include +#include +#include + +// MythTV headers +#include "mythlogging.h" +#include "mythdbcon.h" +#include "mthread.h" +#include "mythtimer.h" +#include "mythdb.h" + +bool is_current_thread(MThread *thread) +{ + if (!thread) + return false; + return QThread::currentThread() == thread->qthread(); +} + +bool is_current_thread(QThread *thread) +{ + if (!thread) + return false; + return QThread::currentThread() == thread; +} + +bool is_current_thread(MThread &thread) +{ + return QThread::currentThread() == thread.qthread(); +} + +class MThreadInternal : public QThread +{ + public: + MThreadInternal(MThread &parent) : m_parent(parent) {} + virtual void run(void) { m_parent.run(); } + + void QThreadRun(void) { QThread::run(); } + int QThreadExec(void) { return QThread::exec(); } + + static void SetTerminationEnabled(bool enabled = true) + { QThread::setTerminationEnabled(enabled); } + + static void Sleep(unsigned long time) { QThread::sleep(time); } + static void MSleep(unsigned long time) { QThread::msleep(time); } + static void USleep(unsigned long time) { QThread::usleep(time); } + + private: + MThread &m_parent; +}; + +static QMutex s_all_threads_lock; +static QSet s_all_threads; + +MThread::MThread(const QString &objectName) : + m_thread(new MThreadInternal(*this)), m_runnable(NULL), + m_prolog_executed(true), m_epilog_executed(true) +{ + m_thread->setObjectName(objectName); + QMutexLocker locker(&s_all_threads_lock); + s_all_threads.insert(this); +} + +MThread::MThread(const QString &objectName, QRunnable *runnable) : + m_thread(new MThreadInternal(*this)), m_runnable(runnable), + m_prolog_executed(false), m_epilog_executed(false) +{ + m_thread->setObjectName(objectName); + QMutexLocker locker(&s_all_threads_lock); + s_all_threads.insert(this); +} + +MThread::~MThread() +{ + if (!m_prolog_executed) + { + LOG(VB_GENERAL, LOG_CRIT, "MThread prolog was never run!"); + } + if (!m_epilog_executed) + { + LOG(VB_GENERAL, LOG_CRIT, "MThread epilog was never run!"); + } + if (m_thread->isRunning()) + { + LOG(VB_GENERAL, LOG_CRIT, + "MThread destructor called while thread still running!"); + m_thread->wait(); + } + + { + QMutexLocker locker(&s_all_threads_lock); + s_all_threads.remove(this); + } + + delete m_thread; + m_thread = NULL; +} + +void MThread::Cleanup(void) +{ + QMutexLocker locker(&s_all_threads_lock); + QSet badGuys; + QSet::const_iterator it; + for (it = s_all_threads.begin(); it != s_all_threads.end(); ++it) + { + if ((*it)->isRunning()) + { + badGuys.insert(*it); + (*it)->exit(1); + } + } + + if (badGuys.empty()) + return; + + // logging has been stopped so we need to use iostream... + cerr<<"Error: Not all threads were shut down properly: "<objectName()) + <<" is still running"< 0) + (*it)->wait(left); + } +} + +void MThread::GetAllThreadNames(QStringList &list) +{ + QMutexLocker locker(&s_all_threads_lock); + QSet::const_iterator it; + for (it = s_all_threads.begin(); it != s_all_threads.end(); ++it) + list.push_back((*it)->objectName()); +} + +void MThread::GetAllRunningThreadNames(QStringList &list) +{ + QMutexLocker locker(&s_all_threads_lock); + QSet::const_iterator it; + for (it = s_all_threads.begin(); it != s_all_threads.end(); ++it) + { + if ((*it)->isRunning()) + list.push_back((*it)->objectName()); + } +} + +void MThread::RunProlog(void) +{ + if (QThread::currentThread() != m_thread) + { + LOG(VB_GENERAL, LOG_CRIT, + "RunProlog can only be executed in the run() method of a thread."); + return; + } + setTerminationEnabled(false); + threadRegister(m_thread->objectName()); + m_prolog_executed = true; +} + +void MThread::RunEpilog(void) +{ + if (QThread::currentThread() != m_thread) + { + LOG(VB_GENERAL, LOG_CRIT, + "RunEpilog can only be executed in the run() method of a thread."); + return; + } + GetMythDB()->GetDBManager()->CloseDatabases(); + threadDeregister(); + m_epilog_executed = true; +} + +QThread *MThread::qthread(void) +{ + return m_thread; +} + +void MThread::setObjectName(const QString &name) +{ + m_thread->setObjectName(name); +} + +QString MThread::objectName(void) const +{ + return m_thread->objectName(); +} + +void MThread::setPriority(QThread::Priority priority) +{ + m_thread->setPriority(priority); +} + +QThread::Priority MThread::priority(void) const +{ + return m_thread->priority(); +} + +bool MThread::isFinished(void) const +{ + return m_thread->isFinished(); +} + +bool MThread::isRunning(void) const +{ + return m_thread->isRunning(); +} + +void MThread::setStackSize(uint stackSize) +{ + m_thread->setStackSize(stackSize); +} + +uint MThread::stackSize(void) const +{ + return m_thread->stackSize(); +} + +void MThread::exit(int retcode) +{ + m_thread->exit(retcode); +} + +void MThread::start(QThread::Priority p) +{ + m_prolog_executed = false; + m_epilog_executed = false; + m_thread->start(p); +} + +void MThread::terminate(void) +{ + m_thread->terminate(); +} + +void MThread::quit(void) +{ + m_thread->quit(); +} + +bool MThread::wait(unsigned long time) +{ + if (m_thread->isRunning()) + return m_thread->wait(time); + return true; +} + +void MThread::run(void) +{ + RunProlog(); + if (m_runnable) + m_runnable->run(); + else + m_thread->QThreadRun(); + RunEpilog(); +} + +int MThread::exec(void) +{ + return m_thread->QThreadExec(); +} + +void MThread::setTerminationEnabled(bool enabled) +{ + MThreadInternal::SetTerminationEnabled(enabled); +} + +void MThread::sleep(unsigned long time) +{ + MThreadInternal::Sleep(time); +} + +void MThread::msleep(unsigned long time) +{ + MThreadInternal::MSleep(time); +} + +void MThread::usleep(unsigned long time) +{ + MThreadInternal::USleep(time); +} + +/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythbase/mthread.h b/mythtv/libs/libmythbase/mthread.h new file mode 100644 index 00000000000..3d65b3fe1ed --- /dev/null +++ b/mythtv/libs/libmythbase/mthread.h @@ -0,0 +1,120 @@ +#ifndef _MYTH_THREAD_H_ +#define _MYTH_THREAD_H_ + +#include + +#include "mythbaseexp.h" + +class MThreadInternal; +class QStringList; +class QRunnable; +class MThread; + +/// Use this to determine if you are in the named thread. +bool MBASE_PUBLIC is_current_thread(MThread *thread); +/// Use this to determine if you are in the named thread. +bool MBASE_PUBLIC is_current_thread(QThread *thread); +/// Use this to determine if you are in the named thread. +bool MBASE_PUBLIC is_current_thread(MThread &thread); + +/** This is a wrapper around QThread that does several additional things. + * + * First it requires that you set the thread's name which is used for + * debugging. + * + * It adds RunProlog() and RunEpilog() which are called automatically + * when you don't override run(), but must be called explicitly if + * you do. These take care of setting up logging and take care of + * dealing with QSqlConnections which are per-thread variables. + * + * It also adds some sanity checking to the destructor so a thread + * can not be deleted while it still running. + * + * Optionally it can be given a QRunnable to run in MThread::run() + * instead of calling QThread::run() (which starts an event loop.) + * When you override MThread::run() or use a QRunnable you are + * responsible for stopping the thread, MThread::exit() will not + * work. + * + */ +class MBASE_PUBLIC MThread +{ + friend class MThreadInternal; + public: + /// Standard constuctor + explicit MThread(const QString &objectName); + /// Use this constuctor if you want the default run() method to + /// run the QRunnable's run() method instead of entering the Qt + /// event loop. Unlike MThreadPool, MThread will not delete a + /// runnable with the autoDelete property set. + explicit MThread(const QString &objectName, QRunnable *runnable); + virtual ~MThread(); + + /// Sets up a thread, call this if you reimplement run(). + void RunProlog(void); + /// Cleans up a thread's resources, call this if you reimplement run(). + void RunEpilog(void); + + /// Returns the thread, this will always return the same pointer + /// no matter how often you restart the thread. + QThread *qthread(void); + + void setObjectName(const QString &name); + QString objectName(void) const; + + void setPriority(QThread::Priority priority); + QThread::Priority priority(void) const; + + bool isFinished(void) const; + bool isRunning(void) const; + + void setStackSize(uint stackSize); + uint stackSize(void) const; + + /// Use this to exit from the thread if you are using a Qt event loop. + void exit(int retcode = 0); + /// \brief Tell MThread to start running the thread in the near future. + void start(QThread::Priority = QThread::InheritPriority); + /// \brief Kill a thread unsafely. + /// + /// This should never be called on a thread while it holds a mutex + /// or semaphore, since those locks will never be unlocked. Use + /// the static setTerminationEnabled(true) to tell MThread when + /// it is safe to terminate the thread and setTerminationEnabled(false) + /// to tell it that termination is not safe again. + void terminate(void); + void quit(void); ///< calls exit(0) + + public: + bool wait(unsigned long time = ULONG_MAX); + + /// This will print out all the running threads, call exit(1) on + /// each and then wait up to 5 seconds total for all the threads + /// to exit. + static void Cleanup(void); + static void GetAllThreadNames(QStringList &list); + static void GetAllRunningThreadNames(QStringList &list); + + static const int kDefaultStartTimeout; + protected: + /// \brief Run's the Qt event loop unless we have a QRunnable, + /// in which case we run the runnable run instead. + /// \note If you override this method you must call RunProlog + /// before you do any work and RunEpilog before you exit + /// the run method. + virtual void run(void); + /// Enters the qt event loop. call exit or quit to exit thread + int exec(void); + + static void setTerminationEnabled(bool enabled = true); + static void sleep(unsigned long time); + static void msleep(unsigned long time); + static void usleep(unsigned long time); + + MThreadInternal *m_thread; + QRunnable *m_runnable; + bool m_prolog_executed; + bool m_epilog_executed; +}; + +#endif // _MYTH_THREAD_H_ diff --git a/mythtv/libs/libmythbase/mthreadpool.cpp b/mythtv/libs/libmythbase/mthreadpool.cpp new file mode 100644 index 00000000000..9c0b8cd0893 --- /dev/null +++ b/mythtv/libs/libmythbase/mthreadpool.cpp @@ -0,0 +1,512 @@ +/* -*- Mode: c++ -*- + * + * Class MThreadPool + * + * Copyright (C) Daniel Kristjansson 2011 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C++ headers +#include +using namespace std; + +// Qt headers +#include +#include +#include +#include +#include +#include +#include +#include + +// MythTV headers +#include "mthreadpool.h" +#include "mythlogging.h" +#include "mythtimer.h" +#include "mthread.h" + +typedef QPair MPoolEntry; +typedef QList MPoolQueue; +typedef QMap MPoolQueues; + +class MPoolThread : public MThread +{ + public: + MPoolThread(MThreadPool &pool, int timeout) : + MThread("PT"), m_pool(pool), m_expiry_timeout(timeout), + m_do_run(true), m_reserved(false) + { + QMutexLocker locker(&s_lock); + setObjectName(QString("PT%1").arg(s_thread_num)); + s_thread_num++; + } + + void run(void) + { + RunProlog(); + + MythTimer t; + t.start(); + QMutexLocker locker(&m_lock); + while (true) + { + if (m_do_run && !m_runnable) + m_wait.wait(locker.mutex(), m_expiry_timeout+1); + + if (!m_runnable) + { + m_do_run = false; + + locker.unlock(); + m_pool.NotifyDone(this); + locker.relock(); + break; + } + + if (!m_runnable_name.isEmpty()) + threadRegister(m_runnable_name); + + m_runnable->run(); + if (m_runnable->autoDelete()) + delete m_runnable; + if (m_reserved) + m_pool.ReleaseThread(); + m_reserved = false; + m_runnable = NULL; + + threadDeregister(); + threadRegister(objectName()); + t.start(); + + if (m_do_run) + { + locker.unlock(); + m_pool.NotifyAvailable(this); + locker.relock(); + } + else + { + locker.unlock(); + m_pool.NotifyDone(this); + locker.relock(); + break; + } + } + + RunEpilog(); + } + + bool SetRunnable(QRunnable *runnable, QString runnableName, + bool reserved) + { + QMutexLocker locker(&m_lock); + if (m_do_run && (m_runnable == NULL)) + { + m_runnable = runnable; + m_runnable_name = runnableName; + m_reserved = reserved; + m_wait.wakeAll(); + return true; + } + return false; + } + + void Shutdown(void) + { + QMutexLocker locker(&m_lock); + m_do_run = false; + m_wait.wakeAll(); + } + + QMutex m_lock; + QWaitCondition m_wait; + MThreadPool &m_pool; + int m_expiry_timeout; + bool m_do_run; + QString m_runnable_name; + bool m_reserved; + + static QMutex s_lock; + static uint s_thread_num; +}; +QMutex MPoolThread::s_lock; +uint MPoolThread::s_thread_num = 0; + +////////////////////////////////////////////////////////////////////// + +class MThreadPoolPrivate +{ + public: + MThreadPoolPrivate(const QString &name) : + m_name(name), + m_running(true), + m_expiry_timeout(120 * 1000), + m_max_thread_count(QThread::idealThreadCount()), + m_reserve_thread(0) + { + } + + int GetRealMaxThread(void) + { + return max(m_max_thread_count,1) + m_reserve_thread; + } + + mutable QMutex m_lock; + QString m_name; + QWaitCondition m_wait; + bool m_running; + int m_expiry_timeout; + int m_max_thread_count; + int m_reserve_thread; + + MPoolQueues m_run_queues; + QSet m_avail_threads; + QSet m_running_threads; + QList m_delete_threads; + + static QMutex s_pool_lock; + static MThreadPool *s_pool; + static QList s_all_pools; +}; + +QMutex MThreadPoolPrivate::s_pool_lock(QMutex::Recursive); +MThreadPool *MThreadPoolPrivate::s_pool = NULL; +QList MThreadPoolPrivate::s_all_pools; + +////////////////////////////////////////////////////////////////////// + +MThreadPool::MThreadPool(const QString &name) : + m_priv(new MThreadPoolPrivate(name)) +{ + QMutexLocker locker(&MThreadPoolPrivate::s_pool_lock); + MThreadPoolPrivate::s_all_pools.push_back(this); +} + +MThreadPool::~MThreadPool() +{ + Stop(); + DeletePoolThreads(); + { + QMutexLocker locker(&MThreadPoolPrivate::s_pool_lock); + MThreadPoolPrivate::s_all_pools.removeAll(this); + } + delete m_priv; + m_priv = NULL; +} + +void MThreadPool::Stop(void) +{ + QMutexLocker locker(&m_priv->m_lock); + m_priv->m_running = false; + QSet::iterator it = m_priv->m_avail_threads.begin(); + for (; it != m_priv->m_avail_threads.end(); ++it) + (*it)->Shutdown(); + it = m_priv->m_running_threads.begin(); + for (; it != m_priv->m_running_threads.end(); ++it) + (*it)->Shutdown(); + m_priv->m_wait.wakeAll(); +} + +void MThreadPool::DeletePoolThreads(void) +{ + waitForDone(); + + QMutexLocker locker(&m_priv->m_lock); + QSet::iterator it = m_priv->m_avail_threads.begin(); + for (; it != m_priv->m_avail_threads.end(); ++it) + { + m_priv->m_delete_threads.push_front(*it); + } + m_priv->m_avail_threads.clear(); + + while (!m_priv->m_delete_threads.empty()) + { + MPoolThread *thread = m_priv->m_delete_threads.back(); + locker.unlock(); + + thread->wait(); + + locker.relock(); + delete thread; + if (m_priv->m_delete_threads.back() == thread) + m_priv->m_delete_threads.pop_back(); + else + m_priv->m_delete_threads.removeAll(thread); + } +} + +MThreadPool *MThreadPool::globalInstance(void) +{ + QMutexLocker locker(&MThreadPoolPrivate::s_pool_lock); + if (!MThreadPoolPrivate::s_pool) + MThreadPoolPrivate::s_pool = new MThreadPool("GlobalPool"); + return MThreadPoolPrivate::s_pool; +} + +void MThreadPool::StopAllPools(void) +{ + QMutexLocker locker(&MThreadPoolPrivate::s_pool_lock); + QList::iterator it; + for (it = MThreadPoolPrivate::s_all_pools.begin(); + it != MThreadPoolPrivate::s_all_pools.end(); ++it) + { + (*it)->Stop(); + } +} + +void MThreadPool::ShutdownAllPools(void) +{ + QMutexLocker locker(&MThreadPoolPrivate::s_pool_lock); + QList::iterator it; + for (it = MThreadPoolPrivate::s_all_pools.begin(); + it != MThreadPoolPrivate::s_all_pools.end(); ++it) + { + (*it)->Stop(); + } + for (it = MThreadPoolPrivate::s_all_pools.begin(); + it != MThreadPoolPrivate::s_all_pools.end(); ++it) + { + (*it)->DeletePoolThreads(); + } +} + +void MThreadPool::start(QRunnable *runnable, QString debugName, int priority) +{ + QMutexLocker locker(&m_priv->m_lock); + if (TryStartInternal(runnable, debugName, false)) + return; + + MPoolQueues::iterator it = m_priv->m_run_queues.find(priority); + if (it != m_priv->m_run_queues.end()) + { + (*it).push_back(MPoolEntry(runnable,debugName)); + } + else + { + MPoolQueue list; + list.push_back(MPoolEntry(runnable,debugName)); + m_priv->m_run_queues[priority] = list; + } +} + +void MThreadPool::startReserved( + QRunnable *runnable, QString debugName, int priority) +{ + QMutexLocker locker(&m_priv->m_lock); + TryStartInternal(runnable, debugName, true); +} + + +bool MThreadPool::tryStart(QRunnable *runnable, QString debugName) +{ + QMutexLocker locker(&m_priv->m_lock); + return TryStartInternal(runnable, debugName, false); +} + +bool MThreadPool::TryStartInternal( + QRunnable *runnable, QString debugName, bool reserved) +{ + if (!m_priv->m_running) + return false; + + while (!m_priv->m_delete_threads.empty()) + { + m_priv->m_delete_threads.back()->wait(); + delete m_priv->m_delete_threads.back(); + m_priv->m_delete_threads.pop_back(); + } + + while (m_priv->m_avail_threads.begin() != m_priv->m_avail_threads.end()) + { + MPoolThread *thread = *m_priv->m_avail_threads.begin(); + m_priv->m_avail_threads.erase(m_priv->m_avail_threads.begin()); + m_priv->m_running_threads.insert(thread); + if (reserved) + m_priv->m_reserve_thread++; + if (thread->SetRunnable(runnable, debugName, reserved)) + { + return true; + } + else + { + if (reserved) + m_priv->m_reserve_thread--; + thread->Shutdown(); + m_priv->m_running_threads.remove(thread); + m_priv->m_delete_threads.push_front(thread); + } + } + + if (reserved || + m_priv->m_running_threads.size() < m_priv->GetRealMaxThread()) + { + m_priv->m_reserve_thread++; + MPoolThread *thread = new MPoolThread(*this, m_priv->m_expiry_timeout); + m_priv->m_running_threads.insert(thread); + thread->SetRunnable(runnable, debugName, reserved); + thread->start(); + return true; + } + + return false; +} + +void MThreadPool::NotifyAvailable(MPoolThread *thread) +{ + QMutexLocker locker(&m_priv->m_lock); + + if (!m_priv->m_running) + { + m_priv->m_running_threads.remove(thread); + thread->Shutdown(); + m_priv->m_delete_threads.push_front(thread); + m_priv->m_wait.wakeAll(); + return; + } + + MPoolQueues::iterator it = m_priv->m_run_queues.begin(); + if (it == m_priv->m_run_queues.end()) + { + m_priv->m_running_threads.remove(thread); + m_priv->m_avail_threads.insert(thread); + m_priv->m_wait.wakeAll(); + return; + } + + MPoolEntry e = (*it).front(); + if (!thread->SetRunnable(e.first, e.second, false)) + { + m_priv->m_running_threads.remove(thread); + m_priv->m_wait.wakeAll(); + if (!TryStartInternal(e.first, e.second, false)) + { + thread->Shutdown(); + m_priv->m_delete_threads.push_front(thread); + return; + } + thread->Shutdown(); + m_priv->m_delete_threads.push_front(thread); + } + + (*it).pop_front(); + if ((*it).empty()) + m_priv->m_run_queues.erase(it); +} + +void MThreadPool::NotifyDone(MPoolThread *thread) +{ + QMutexLocker locker(&m_priv->m_lock); + m_priv->m_running_threads.remove(thread); + m_priv->m_avail_threads.remove(thread); + if (!m_priv->m_delete_threads.contains(thread)) + m_priv->m_delete_threads.push_front(thread); + m_priv->m_wait.wakeAll(); +} + +int MThreadPool::expiryTimeout(void) const +{ + QMutexLocker locker(&m_priv->m_lock); + return m_priv->m_expiry_timeout; +} + +void MThreadPool::setExpiryTimeout(int expiryTimeout) +{ + QMutexLocker locker(&m_priv->m_lock); + m_priv->m_expiry_timeout = expiryTimeout; +} + +int MThreadPool::maxThreadCount(void) const +{ + QMutexLocker locker(&m_priv->m_lock); + return m_priv->m_max_thread_count; +} + +void MThreadPool::setMaxThreadCount(int maxThreadCount) +{ + QMutexLocker locker(&m_priv->m_lock); + m_priv->m_max_thread_count = maxThreadCount; +} + +int MThreadPool::activeThreadCount(void) const +{ + QMutexLocker locker(&m_priv->m_lock); + return m_priv->m_avail_threads.size() + m_priv->m_running_threads.size(); +} + +/* +void MThreadPool::reserveThread(void) +{ + QMutexLocker locker(&m_priv->m_lock); + m_priv->m_reserve_thread++; +} + +void MThreadPool::releaseThread(void) +{ + QMutexLocker locker(&m_priv->m_lock); + if (m_priv->m_reserve_thread > 0) + m_priv->m_reserve_thread--; +} +*/ + +void MThreadPool::ReleaseThread(void) +{ + QMutexLocker locker(&m_priv->m_lock); + if (m_priv->m_reserve_thread > 0) + m_priv->m_reserve_thread--; +} + +#if 0 +static void print_set(QString title, QSet set) +{ + LOG(VB_GENERAL, LOG_INFO, title); + QSet::iterator it = set.begin(); + for (; it != set.end(); ++it) + { + LOG(VB_GENERAL, LOG_INFO, QString(" : 0x%1") + .arg((quint64)(*it),0,16)); + } + LOG(VB_GENERAL, LOG_INFO, ""); +} +#endif + +void MThreadPool::waitForDone(void) +{ + QMutexLocker locker(&m_priv->m_lock); + while (true) + { + while (!m_priv->m_delete_threads.empty()) + { + m_priv->m_delete_threads.back()->wait(); + delete m_priv->m_delete_threads.back(); + m_priv->m_delete_threads.pop_back(); + } + + if (m_priv->m_running && !m_priv->m_run_queues.empty()) + { + m_priv->m_wait.wait(locker.mutex()); + continue; + } + + QSet working = m_priv->m_running_threads; + working = working.subtract(m_priv->m_avail_threads); + if (working.empty()) + break; + m_priv->m_wait.wait(locker.mutex()); + } +} + +/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythbase/mthreadpool.h b/mythtv/libs/libmythbase/mthreadpool.h new file mode 100644 index 00000000000..f0ad6cae5a6 --- /dev/null +++ b/mythtv/libs/libmythbase/mthreadpool.h @@ -0,0 +1,61 @@ +// -*- Mode: c++ -*- + +#ifndef _MYTH_THREAD_POOL_H_ +#define _MYTH_THREAD_POOL_H_ + +#include + +#include "mythbaseexp.h" + +class MThreadPoolPrivate; +class MPoolThread; +class QRunnable; + +class MBASE_PUBLIC MThreadPool +{ + friend class MPoolThread; + public: + MThreadPool(const QString &name); + ~MThreadPool(); + + void Stop(void); + void DeletePoolThreads(void); + + static MThreadPool *globalInstance(void); + static void StopAllPools(void); + static void ShutdownAllPools(void); + + void start(QRunnable *runnable, int priority = 0) + { start(runnable, "", priority); } + void start(QRunnable *runnable, QString debugName, int priority = 0); + bool tryStart(QRunnable *runnable, QString debugName); + + void startReserved(QRunnable *runnable, QString debugName, + int priority = 0); + + int expiryTimeout(void) const; + void setExpiryTimeout(int expiryTimeout); + + int maxThreadCount(void) const; + void setMaxThreadCount(int maxThreadCount); + + int activeThreadCount(void) const; + + //void reserveThread(void) MDEPRECATED; + //void releaseThread(void) MDEPRECATED; + + void waitForDone(void); + + private: + bool TryStartInternal(QRunnable*, QString, bool); + void NotifyAvailable(MPoolThread*); + void NotifyDone(MPoolThread*); + void ReleaseThread(void); + + + MThreadPoolPrivate *m_priv; +}; + +#endif // _MYTH_THREAD_POOL_H_ + +/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythbase/mythcorecontext.cpp b/mythtv/libs/libmythbase/mythcorecontext.cpp index 3f8cff77f19..c0745cc0a7c 100644 --- a/mythtv/libs/libmythbase/mythcorecontext.cpp +++ b/mythtv/libs/libmythbase/mythcorecontext.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -26,10 +25,11 @@ using namespace std; #include "mythcorecontext.h" #include "mythsocket.h" #include "mythsystem.h" +#include "mthreadpool.h" #include "exitcodes.h" #include "mythlogging.h" - #include "mythversion.h" +#include "mthread.h" #define LOC QString("MythCoreContext: ") @@ -97,6 +97,7 @@ MythCoreContextPrivate::MythCoreContextPrivate(MythCoreContext *lparent, MythCoreContextPrivate::~MythCoreContextPrivate() { + MThreadPool::StopAllPools(); ShutdownRRT(); QMutexLocker locker(&m_sockLock); @@ -113,8 +114,16 @@ MythCoreContextPrivate::~MythCoreContextPrivate() delete m_locale; + MThreadPool::ShutdownAllPools(); + + ShutdownMythSystem(); + logStop(); // need to shutdown db logger before we kill db + MThread::Cleanup(); + + GetMythDB()->GetDBManager()->CloseDatabases(); + if (m_database) { DestroyMythDB(); m_database = NULL; @@ -787,7 +796,7 @@ void MythCoreContext::OverrideSettingForSession(const QString &key, bool MythCoreContext::IsUIThread(void) { - return (QThread::currentThread() == d->m_UIThread); + return is_current_thread(d->m_UIThread); } bool MythCoreContext::SendReceiveStringList(QStringList &strlist, diff --git a/mythtv/libs/libmythbase/mythdb.cpp b/mythtv/libs/libmythbase/mythdb.cpp index 6810304f76c..66d0c9bd7d9 100644 --- a/mythtv/libs/libmythbase/mythdb.cpp +++ b/mythtv/libs/libmythbase/mythdb.cpp @@ -2,13 +2,12 @@ using namespace std; #include +#include #include #include #include #include #include -#include -#include #include "mythdb.h" #include "mythdbcon.h" diff --git a/mythtv/libs/libmythbase/mythdbcon.cpp b/mythtv/libs/libmythbase/mythdbcon.cpp index 77e4db64892..814601ba5ad 100644 --- a/mythtv/libs/libmythbase/mythdbcon.cpp +++ b/mythtv/libs/libmythbase/mythdbcon.cpp @@ -1,3 +1,5 @@ +#include + // ANSI C #include @@ -16,7 +18,7 @@ #include "mythlogging.h" #include "mythsystem.h" #include "exitcodes.h" -#include +#include "mthread.h" #define DEBUG_RECONNECT 0 #if DEBUG_RECONNECT @@ -245,34 +247,36 @@ MDBManager::MDBManager() m_nextConnID = 0; m_connCount = 0; - m_sem = new QSemaphore(20); - m_schedCon = NULL; m_DDCon = NULL; - m_LogCon = NULL; } MDBManager::~MDBManager() { - while (!m_pool.isEmpty()) - delete m_pool.takeFirst(); - delete m_sem; + CloseDatabases(); - closeStaticCon(&m_schedCon); - closeStaticCon(&m_DDCon); - closeStaticCon(&m_LogCon); + if (m_connCount != 0 || m_schedCon || m_DDCon) + { + LOG(VB_GENERAL, LOG_CRIT, + "MDBManager exiting with connections still open"); + } +#if 0 /* some post logStop() debugging... */ + cout<<"m_connCount: "<acquire(); m_lock.lock(); MSqlDatabase *db; - if (m_pool.isEmpty()) + DBList &list = m_pool[QThread::currentThread()]; + if (list.isEmpty()) { db = new MSqlDatabase("DBManager" + QString::number(m_nextConnID++)); ++m_connCount; @@ -280,7 +284,10 @@ MSqlDatabase *MDBManager::popConnection() QString("New DB connection, total: %1").arg(m_connCount)); } else - db = m_pool.takeLast(); + { + db = list.back(); + list.pop_back(); + } m_lock.unlock(); @@ -296,11 +303,10 @@ void MDBManager::pushConnection(MSqlDatabase *db) if (db) { db->m_lastDBKick = QDateTime::currentDateTime(); - m_pool.prepend(db); + m_pool[QThread::currentThread()].push_front(db); } m_lock.unlock(); - m_sem->release(); PurgeIdleConnections(); } @@ -310,11 +316,12 @@ void MDBManager::PurgeIdleConnections(void) QMutexLocker locker(&m_lock); QDateTime now = QDateTime::currentDateTime(); - QList::iterator it = m_pool.begin(); + DBList &list = m_pool[QThread::currentThread()]; + DBList::iterator it = list.begin(); uint purgedConnections = 0, totalConnections = 0; MSqlDatabase *newDb = NULL; - while (it != m_pool.end()) + while (it != list.end()) { totalConnections++; if ((*it)->m_lastDBKick.secsTo(now) <= (int)kPurgeTimeout) @@ -326,7 +333,7 @@ void MDBManager::PurgeIdleConnections(void) // This connection has not been used in the kPurgeTimeout // seconds close it. MSqlDatabase *entry = *it; - it = m_pool.erase(it); + it = list.erase(it); --m_connCount; purgedConnections++; @@ -340,7 +347,7 @@ void MDBManager::PurgeIdleConnections(void) // threads didn't exit". This workaround simply creates an // extra DB connection before all pooled connections are // purged so that my_thread_global_end() won't be called. - if (it == m_pool.end() && + if (it == list.end() && purgedConnections > 0 && totalConnections == purgedConnections) { @@ -357,7 +364,7 @@ void MDBManager::PurgeIdleConnections(void) LOG(VB_DATABASE, LOG_INFO, "Done deleting idle DB connection."); } if (newDb) - m_pool.push_front(newDb); + list.push_front(newDb); if (purgedConnections) { @@ -380,6 +387,9 @@ MSqlDatabase *MDBManager::getStaticCon(MSqlDatabase **dbcon, QString name) (*dbcon)->OpenDatabase(); + if (!m_static_pool[QThread::currentThread()].contains(*dbcon)) + m_static_pool[QThread::currentThread()].push_back(*dbcon); + return *dbcon; } @@ -393,18 +403,20 @@ MSqlDatabase *MDBManager::getDDCon() return getStaticCon(&m_DDCon, "DataDirectCon"); } -MSqlDatabase *MDBManager::getLogCon() -{ - return getStaticCon(&m_LogCon, "LogCon"); -} - void MDBManager::closeStaticCon(MSqlDatabase **dbcon) { - if (dbcon && *dbcon) + DBList &list = m_static_pool[QThread::currentThread()]; + if (dbcon && *dbcon && list.contains(*dbcon)) { + list.removeAll(*dbcon); delete *dbcon; *dbcon = NULL; } + else if (dbcon && *dbcon) + { + LOG(VB_GENERAL, LOG_CRIT, + "Attempted to close static connection in wrong thread."); + } } void MDBManager::closeSchedCon() @@ -417,29 +429,37 @@ void MDBManager::closeDDCon() closeStaticCon(&m_DDCon); } -void MDBManager::closeLogCon() -{ - closeStaticCon(&m_LogCon); -} - -// Dangerous. Should only be used when the database connection has errored? - void MDBManager::CloseDatabases() { m_lock.lock(); + DBList list = m_pool[QThread::currentThread()]; + m_pool[QThread::currentThread()].clear(); + m_lock.unlock(); - QList::const_iterator it = m_pool.begin(); - MSqlDatabase *db; + for (DBList::iterator it = list.begin(); it != list.end(); ++it) + { + LOG(VB_GENERAL, LOG_INFO, + "Closing DB connection named '" + (*it)->m_name + "'"); + (*it)->m_db.close(); + delete (*it); + m_connCount--; + } - while (it != m_pool.end()) + m_lock.lock(); + DBList &slist = m_static_pool[QThread::currentThread()]; + while (!slist.isEmpty()) { - db = *it; + MSqlDatabase *db = slist.takeFirst(); LOG(VB_GENERAL, LOG_INFO, - "Closing DB connection named '" + db->m_name + "'"); + "Closing DB connection named '" + db->m_name + "'"); db->m_db.close(); - ++it; - } + delete db; + if (db == m_schedCon) + m_schedCon = NULL; + if (db == m_DDCon) + m_DDCon = NULL; + } m_lock.unlock(); } @@ -551,25 +571,6 @@ MSqlQueryInfo MSqlQuery::DDCon() return qi; } -MSqlQueryInfo MSqlQuery::LogCon() -{ - MSqlDatabase *db = GetMythDB()->GetDBManager()->getLogCon(); - MSqlQueryInfo qi; - - InitMSqlQueryInfo(qi); - qi.returnConnection = false; - - if (db) - { - qi.db = db; - qi.qsqldb = db->db(); - - db->KickDatabase(); - } - - return qi; -} - void MSqlQuery::CloseSchedCon() { GetMythDB()->GetDBManager()->closeSchedCon(); @@ -580,12 +581,6 @@ void MSqlQuery::CloseDDCon() GetMythDB()->GetDBManager()->closeDDCon(); } -void MSqlQuery::CloseLogCon() -{ - GetMythDB()->GetDBManager()->closeLogCon(); -} - - bool MSqlQuery::exec() { if (!m_db) diff --git a/mythtv/libs/libmythbase/mythdbcon.h b/mythtv/libs/libmythbase/mythdbcon.h index f69c045522d..2b782e7a108 100644 --- a/mythtv/libs/libmythbase/mythdbcon.h +++ b/mythtv/libs/libmythbase/mythdbcon.h @@ -65,24 +65,23 @@ class MBASE_PUBLIC MDBManager MSqlDatabase *getSchedCon(void); MSqlDatabase *getDDCon(void); - MSqlDatabase *getLogCon(void); void closeSchedCon(void); void closeDDCon(void); - void closeLogCon(void); private: MSqlDatabase *getStaticCon(MSqlDatabase **dbcon, QString name); void closeStaticCon(MSqlDatabase **dbcon); - QList m_pool; QMutex m_lock; - QSemaphore *m_sem; + typedef QList DBList; + QHash m_pool; // protected by m_lock + int m_nextConnID; int m_connCount; MSqlDatabase *m_schedCon; MSqlDatabase *m_DDCon; - MSqlDatabase *m_LogCon; + QHash m_static_pool; }; /// \brief MSqlDatabase Info, used by MSqlQuery. Do not use directly. @@ -204,12 +203,8 @@ class MBASE_PUBLIC MSqlQuery : private QSqlQuery /// \brief Returns dedicated connection. (Required for using temporary SQL tables.) static MSqlQueryInfo DDCon(); - /// \brief Returns dedicated connection. - static MSqlQueryInfo LogCon(); - static void CloseSchedCon(); static void CloseDDCon(); - static void CloseLogCon(); private: // Only QSql::In is supported as a param type and only named params... diff --git a/mythtv/libs/libmythbase/mythdownloadmanager.cpp b/mythtv/libs/libmythbase/mythdownloadmanager.cpp index d28750fd773..6f4f5a51626 100644 --- a/mythtv/libs/libmythbase/mythdownloadmanager.cpp +++ b/mythtv/libs/libmythbase/mythdownloadmanager.cpp @@ -1,10 +1,10 @@ // qt #include +#include #include #include #include #include -#include #include #include "stdlib.h" @@ -13,6 +13,7 @@ #include "compat.h" #include "mythcorecontext.h" #include "mythcoreutil.h" +#include "mthreadpool.h" #include "mythdirs.h" #include "mythevent.h" #include "mythversion.h" @@ -97,7 +98,6 @@ class RemoteFileDownloadThread : public QRunnable { bool ok = false; - threadRegister("RemoteFileDownload"); RemoteFile *rf = new RemoteFile(m_dlInfo->m_url, false, false, 0); ok = rf->SaveAs(m_dlInfo->m_privData); delete rf; @@ -109,7 +109,6 @@ class RemoteFileDownloadThread : public QRunnable m_dlInfo->m_bytesTotal = m_dlInfo->m_bytesReceived; m_parent->downloadFinished(m_dlInfo); - threadDeregister(); } private: @@ -159,6 +158,7 @@ MythDownloadManager *GetMythDownloadManager(void) * QNetworkAccessManager and QNetworkDiskCache. */ MythDownloadManager::MythDownloadManager() : + MThread("DownloadManager"), m_manager(NULL), m_diskCache(NULL), m_infoLock(new QMutex(QMutex::Recursive)), @@ -187,13 +187,13 @@ MythDownloadManager::~MythDownloadManager() */ void MythDownloadManager::run(void) { + RunProlog(); + bool downloading = false; bool itemsInQueue = false; bool waitAnyway = false; - threadRegister("DownloadManager"); - - m_queueThread = currentThread(); + m_queueThread = QThread::currentThread(); while (!m_runThread) usleep(50000); @@ -264,7 +264,8 @@ void MythDownloadManager::run(void) m_infoLock->unlock(); } m_isRunning = false; - threadDeregister(); + + RunEpilog(); } /** \fn MythDownloadManager::queueItem(const QString &url, QNetworkRequest *req, @@ -552,7 +553,7 @@ void MythDownloadManager::downloadRemoteFile(MythDownloadInfo *dlInfo) { RemoteFileDownloadThread *dlThread = new RemoteFileDownloadThread(this, dlInfo); - QThreadPool::globalInstance()->start(dlThread); + MThreadPool::globalInstance()->start(dlThread, "RemoteFileDownload"); } /** \fn MythDownloadManager::downloadQNetworkRequest(MythDownloadInfo *dlInfo) diff --git a/mythtv/libs/libmythbase/mythdownloadmanager.h b/mythtv/libs/libmythbase/mythdownloadmanager.h index fdb526da459..b9dbfdf4c04 100644 --- a/mythtv/libs/libmythbase/mythdownloadmanager.h +++ b/mythtv/libs/libmythbase/mythdownloadmanager.h @@ -2,7 +2,6 @@ #define MYTHDOWNLOADMANAGER_H #include -#include #include #include #include @@ -11,11 +10,12 @@ #include #include "mythbaseexp.h" +#include "mthread.h" class MythDownloadInfo; class RemoteFileDownloadThread; -class MBASE_PUBLIC MythDownloadManager : public QThread +class MBASE_PUBLIC MythDownloadManager : public QObject, public MThread { Q_OBJECT diff --git a/mythtv/libs/libmythbase/mythsignalingtimer.cpp b/mythtv/libs/libmythbase/mythsignalingtimer.cpp index f6158bfd030..d1e81aa79cf 100644 --- a/mythtv/libs/libmythbase/mythsignalingtimer.cpp +++ b/mythtv/libs/libmythbase/mythsignalingtimer.cpp @@ -22,7 +22,8 @@ MythSignalingTimer::MythSignalingTimer( QObject *parent, const char *slot) : - QThread(parent), dorun(false), running(false), microsec(0) + QObject(parent), MThread("SignalingTimer"), + dorun(false), running(false), microsec(0) { connect(this, SIGNAL(timeout()), parent, slot, Qt::QueuedConnection); @@ -45,7 +46,7 @@ void MythSignalingTimer::start(int msec) if (!running) { dorun = true; - QThread::start(); + MThread::start(); while (dorun && !running) usleep(10 * 1000); } @@ -53,7 +54,7 @@ void MythSignalingTimer::start(int msec) void MythSignalingTimer::stop(void) { - if (thread() == this) + if (is_current_thread(this)) { dorun = false; return; @@ -69,15 +70,14 @@ void MythSignalingTimer::stop(void) void MythSignalingTimer::run(void) { - threadRegister("SignalingTimer"); - running = true; + RunProlog(); while (dorun) { usleep(microsec); if (dorun) emit timeout(); } + RunEpilog(); running = false; - threadDeregister(); } diff --git a/mythtv/libs/libmythbase/mythsignalingtimer.h b/mythtv/libs/libmythbase/mythsignalingtimer.h index 93f9171c11a..38a884ded29 100644 --- a/mythtv/libs/libmythbase/mythsignalingtimer.h +++ b/mythtv/libs/libmythbase/mythsignalingtimer.h @@ -5,10 +5,10 @@ #include -#include #include #include "mythbaseexp.h" +#include "mthread.h" /** \class MythSignalingTimer * This class is essentially a workaround for a Qt 4.5.2 bug where it @@ -16,7 +16,7 @@ * timer firing. This lost millisecond is not a huge issue for infrequent * timers, but causes 7% lost CPU in the MythUI animate() handling. */ -class MBASE_PUBLIC MythSignalingTimer : private QThread +class MBASE_PUBLIC MythSignalingTimer : private QObject, private MThread { Q_OBJECT diff --git a/mythtv/libs/libmythbase/mythsocketthread.cpp b/mythtv/libs/libmythbase/mythsocketthread.cpp index 3b2fabb2971..d4f5a040145 100644 --- a/mythtv/libs/libmythbase/mythsocketthread.cpp +++ b/mythtv/libs/libmythbase/mythsocketthread.cpp @@ -35,7 +35,7 @@ const uint MythSocketThread::kShortWait = 100; MythSocketThread::MythSocketThread() - : QThread(), m_readyread_run(false) + : MThread("Socket"), m_readyread_run(false) { for (int i = 0; i < 2; i++) { @@ -188,7 +188,7 @@ void MythSocketThread::ProcessAddRemoveQueues(void) void MythSocketThread::run(void) { - threadRegister("Socket"); + RunProlog(); LOG(VB_SOCKET, LOG_DEBUG, LOC + "readyread thread start"); QMutexLocker locker(&m_readyread_lock); @@ -374,5 +374,5 @@ void MythSocketThread::run(void) } LOG(VB_SOCKET, LOG_DEBUG, LOC + "readyread thread exit"); - threadDeregister(); + RunEpilog(); } diff --git a/mythtv/libs/libmythbase/mythsocketthread.h b/mythtv/libs/libmythbase/mythsocketthread.h index 2a901138c6c..5215304067b 100644 --- a/mythtv/libs/libmythbase/mythsocketthread.h +++ b/mythtv/libs/libmythbase/mythsocketthread.h @@ -2,20 +2,19 @@ #define _MYTH_SOCKET_THREAD_H_ #include -#include #include #include #include "mythbaseexp.h" +#include "mthread.h" MBASE_PUBLIC void ShutdownRRT(void); class MythSocket; -class MythSocketThread : public QThread +class MythSocketThread : public MThread { public: MythSocketThread(); - virtual ~MythSocketThread() { wait(); } virtual void run(void); diff --git a/mythtv/libs/libmythbase/mythsystem.cpp b/mythtv/libs/libmythbase/mythsystem.cpp index c799615551d..4719e065d75 100644 --- a/mythtv/libs/libmythbase/mythsystem.cpp +++ b/mythtv/libs/libmythbase/mythsystem.cpp @@ -16,11 +16,6 @@ // QT headers #include -#include -#include -#include -#include -#include // libmythbase headers #include "mythcorecontext.h" diff --git a/mythtv/libs/libmythbase/mythsystem.h b/mythtv/libs/libmythbase/mythsystem.h index aaf0d8b31c2..ed02fc150f4 100644 --- a/mythtv/libs/libmythbase/mythsystem.h +++ b/mythtv/libs/libmythbase/mythsystem.h @@ -30,11 +30,11 @@ typedef enum MythSystemMask { #include #include #include -#include -#include typedef QMap Setting_t; +void ShutdownMythSystem(void); + class MythSystemPrivate; class MBASE_PUBLIC MythSystem : public QObject { diff --git a/mythtv/libs/libmythbase/system-unix.cpp b/mythtv/libs/libmythbase/system-unix.cpp index 04f1312ea55..2de27bd94fa 100644 --- a/mythtv/libs/libmythbase/system-unix.cpp +++ b/mythtv/libs/libmythbase/system-unix.cpp @@ -20,7 +20,6 @@ // QT headers #include -#include #include #include #include @@ -52,6 +51,7 @@ typedef QMap FDMap_t; /********************************** * MythSystemManager method defines *********************************/ +static bool run_system = true; static MythSystemManager *manager = NULL; static MythSystemSignalManager *smanager = NULL; static MythSystemIOHandler *readThread = NULL; @@ -61,16 +61,29 @@ static QMutex listLock; static FDMap_t fdMap; static QMutex fdLock; +void ShutdownMythSystem(void) +{ + run_system = false; + if (manager) + manager->wait(); + if (smanager) + smanager->wait(); + if (readThread) + readThread->wait(); + if (writeThread) + writeThread->wait(); +} MythSystemIOHandler::MythSystemIOHandler(bool read) : - QThread(), m_pWaitLock(), m_pWait(), m_pLock(), m_pMap(PMap_t()), + MThread(QString("SystemIOHandler%1").arg(read ? "R" : "W")), + m_pWaitLock(), m_pWait(), m_pLock(), m_pMap(PMap_t()), m_read(read) { } void MythSystemIOHandler::run(void) { - threadRegister(QString("SystemIOHandler%1").arg(m_read ? "R" : "W")); + RunProlog(); LOG(VB_GENERAL, LOG_INFO, QString("Starting IO manager (%1)") .arg(m_read ? "read" : "write")); @@ -78,14 +91,14 @@ void MythSystemIOHandler::run(void) BuildFDs(); m_pLock.unlock(); - while( gCoreContext ) + while( run_system ) { { QMutexLocker locker(&m_pWaitLock); m_pWait.wait(&m_pWaitLock); } - while( gCoreContext ) + while( run_system ) { usleep(10000); // ~100x per second, for ~3MBps throughput m_pLock.lock(); @@ -130,7 +143,8 @@ void MythSystemIOHandler::run(void) m_pLock.unlock(); } } - threadDeregister(); + + RunEpilog(); } void MythSystemIOHandler::HandleRead(int fd, QBuffer *buff) @@ -233,19 +247,19 @@ void MythSystemIOHandler::BuildFDs() } } -MythSystemManager::MythSystemManager() : QThread() +MythSystemManager::MythSystemManager() : MThread("SystemManager") { m_jumpAbort = false; } void MythSystemManager::run(void) { - threadRegister("SystemManager"); + RunProlog(); LOG(VB_GENERAL, LOG_INFO, "Starting process manager"); - // gCoreContext is set to NULL during shutdown, and we need this thread to + // run_system is set to NULL during shutdown, and we need this thread to // exit during shutdown. - while( gCoreContext ) + while( run_system ) { usleep(100000); // sleep 100ms @@ -382,7 +396,8 @@ void MythSystemManager::run(void) readThread->wake(); if (writeThread) writeThread->wake(); - threadDeregister(); + + RunEpilog(); } void MythSystemManager::append(MythSystemUnix *ms) @@ -424,18 +439,19 @@ void MythSystemManager::jumpAbort(void) // spawn separate thread for signals to prevent manager // thread from blocking in some slot -MythSystemSignalManager::MythSystemSignalManager() : QThread() +MythSystemSignalManager::MythSystemSignalManager() : + MThread("SystemSignalManager") { } void MythSystemSignalManager::run(void) { - threadRegister("SystemSignalManager"); + RunProlog(); LOG(VB_GENERAL, LOG_INFO, "Starting process signal handler"); - while( gCoreContext ) + while( run_system ) { usleep(50000); // sleep 50ms - while( gCoreContext ) + while( run_system ) { // handle cleanup and signalling for closed processes listLock.lock(); @@ -480,7 +496,7 @@ void MythSystemSignalManager::run(void) ms->deleteLater(); } } - threadDeregister(); + RunEpilog(); } /******************************* diff --git a/mythtv/libs/libmythbase/system-unix.h b/mythtv/libs/libmythbase/system-unix.h index baaffc9f284..a71141f520e 100644 --- a/mythtv/libs/libmythbase/system-unix.h +++ b/mythtv/libs/libmythbase/system-unix.h @@ -1,18 +1,20 @@ #ifndef SYSTEM_UNIX_H_ #define SYSTEM_UNIX_H_ -#include "mythbaseexp.h" +#include #include + #include #include #include #include -#include #include #include #include -#include + +#include "mythbaseexp.h" #include "mythsystem.h" +#include "mthread.h" class MythSystemUnix; @@ -20,7 +22,7 @@ typedef QMap > MSMap_t; typedef QMap PMap_t; typedef QList > MSList_t; -class MythSystemIOHandler: public QThread +class MythSystemIOHandler: public MThread { public: MythSystemIOHandler(bool read); @@ -47,7 +49,7 @@ class MythSystemIOHandler: public QThread char m_readbuf[65536]; }; -class MythSystemManager : public QThread +class MythSystemManager : public MThread { public: MythSystemManager(); @@ -62,7 +64,7 @@ class MythSystemManager : public QThread QMutex m_jumpLock; }; -class MythSystemSignalManager : public QThread +class MythSystemSignalManager : public MThread { public: MythSystemSignalManager(); diff --git a/mythtv/libs/libmythbase/system-windows.cpp b/mythtv/libs/libmythbase/system-windows.cpp index bd411a11bb7..a501ae9aa91 100644 --- a/mythtv/libs/libmythbase/system-windows.cpp +++ b/mythtv/libs/libmythbase/system-windows.cpp @@ -17,7 +17,6 @@ // QT headers #include -#include #include #include #include @@ -25,9 +24,9 @@ // libmythbase headers #include "mythcorecontext.h" +#include "mythlogging.h" #include "mythevent.h" #include "exitcodes.h" -#include "mythlogging.h" // Windows headers #include @@ -54,6 +53,7 @@ typedef QMap FDMap_t; /********************************** * MythSystemManager method defines *********************************/ +static bool run_system = true; static MythSystemManager *manager = NULL; static MythSystemSignalManager *smanager = NULL; static MythSystemIOHandler *readThread = NULL; @@ -63,27 +63,41 @@ static QMutex listLock; static FDMap_t fdMap; static QMutex fdLock; +void ShutdownMythSystem(void) +{ + run_system = false; + if (manager) + manager->wait(); + if (smanager) + smanager->wait(); + if (readThread) + readThread->wait(); + if (writeThread) + writeThread->wait(); +} MythSystemIOHandler::MythSystemIOHandler(bool read) : - QThread(), m_pWaitLock(), m_pWait(), m_pLock(), m_pMap(PMap_t()), + MThread(QString("SystemIOHandler%1").arg(read ? "R" : "W")), + m_pWaitLock(), m_pWait(), m_pLock(), m_pMap(PMap_t()), m_read(read) { } void MythSystemIOHandler::run(void) { - threadRegister(QString("SystemIOHandler%1").arg(m_read ? "R" : "W")); + RunProlog(); + LOG(VB_GENERAL, LOG_INFO, QString("Starting IO manager (%1)") .arg(m_read ? "read" : "write")); - while( gCoreContext ) + while( run_system ) { { QMutexLocker locker(&m_pWaitLock); m_pWait.wait(&m_pWaitLock); } - while( gCoreContext ) + while( run_system ) { usleep(10000); // ~100x per second, for ~3MBps throughput m_pLock.lock(); @@ -96,7 +110,7 @@ void MythSystemIOHandler::run(void) bool datafound = true; m_pLock.unlock(); - while ( datafound && gCoreContext ) + while ( datafound && run_system ) { m_pLock.lock(); @@ -115,7 +129,7 @@ void MythSystemIOHandler::run(void) } } } - threadDeregister(); + RunEpilog(); } bool MythSystemIOHandler::HandleRead(HANDLE h, QBuffer *buff) @@ -204,7 +218,8 @@ void MythSystemIOHandler::wake() } -MythSystemManager::MythSystemManager() : QThread() +MythSystemManager::MythSystemManager() : + MThread("SystemManager") { m_jumpAbort = false; m_childCount = 0; @@ -220,12 +235,13 @@ MythSystemManager::~MythSystemManager() void MythSystemManager::run(void) { - threadRegister("SystemManager"); + RunProlog(); + LOG(VB_GENERAL, LOG_INFO, "Starting process manager"); - // gCoreContext is set to NULL during shutdown, and we need this thread to + // run_system is set to NULL during shutdown, and we need this thread to // exit during shutdown. - while( gCoreContext ) + while( run_system ) { // check for any running processes m_mapLock.lock(); @@ -327,7 +343,8 @@ void MythSystemManager::run(void) // kick to allow them to close themselves cleanly readThread->wake(); writeThread->wake(); - threadDeregister(); + + RunEpilog(); } // NOTE: This is only to be run while m_mapLock is locked!!! @@ -393,18 +410,20 @@ void MythSystemManager::jumpAbort(void) // spawn separate thread for signals to prevent manager // thread from blocking in some slot -MythSystemSignalManager::MythSystemSignalManager() : QThread() +MythSystemSignalManager::MythSystemSignalManager() : + MThread("SystemSignalManager") { } void MythSystemSignalManager::run(void) { - threadRegister("SystemSignalManager"); + RunProlog(); + LOG(VB_GENERAL, LOG_INFO, "Starting process signal handler"); - while( gCoreContext ) + while( run_system ) { usleep(50000); // sleep 50ms - while( gCoreContext ) + while( run_system ) { // handle cleanup and signalling for closed processes listLock.lock(); @@ -443,7 +462,8 @@ void MythSystemSignalManager::run(void) delete ms; } } - threadDeregister(); + + RunEpilog(); } /******************************* diff --git a/mythtv/libs/libmythbase/system-windows.h b/mythtv/libs/libmythbase/system-windows.h index 0b3838e33e9..125c6875e37 100644 --- a/mythtv/libs/libmythbase/system-windows.h +++ b/mythtv/libs/libmythbase/system-windows.h @@ -1,16 +1,18 @@ #ifndef SYSTEM_UNIX_H_ #define SYSTEM_UNIX_H_ -#include "mythbaseexp.h" #include -#include -#include -#include -#include -#include + #include +#include +#include #include +#include +#include + +#include "mythbaseexp.h" #include "mythsystem.h" +#include "mthread.h" class MythSystemWindows; @@ -18,7 +20,7 @@ typedef QMap MSMap_t; typedef QMap PMap_t; typedef QList MSList_t; -class MythSystemIOHandler: public QThread +class MythSystemIOHandler: public MThread { public: MythSystemIOHandler(bool read); @@ -42,7 +44,7 @@ class MythSystemIOHandler: public QThread char m_readbuf[65536]; }; -class MythSystemManager : public QThread +class MythSystemManager : public MThread { public: MythSystemManager(); @@ -63,7 +65,7 @@ class MythSystemManager : public QThread QMutex m_jumpLock; }; -class MythSystemSignalManager : public QThread +class MythSystemSignalManager : public MThread { public: MythSystemSignalManager(); diff --git a/mythtv/libs/libmythmetadata/metadatadownload.cpp b/mythtv/libs/libmythmetadata/metadatadownload.cpp index 7e8891e3e66..2230f585c22 100644 --- a/mythtv/libs/libmythmetadata/metadatadownload.cpp +++ b/mythtv/libs/libmythmetadata/metadatadownload.cpp @@ -21,7 +21,8 @@ QEvent::Type MetadataLookupEvent::kEventType = QEvent::Type MetadataLookupFailure::kEventType = (QEvent::Type) QEvent::registerEventType(); -MetadataDownload::MetadataDownload(QObject *parent) +MetadataDownload::MetadataDownload(QObject *parent) : + MThread("MetadataDownload") { m_parent = parent; } @@ -63,8 +64,9 @@ void MetadataDownload::cancel() void MetadataDownload::run() { + RunProlog(); + MetadataLookup* lookup; - threadRegister("MetadataDownload"); while ((lookup = moreWork()) != NULL) { MetadataLookupList list; @@ -146,7 +148,8 @@ void MetadataDownload::run() new MetadataLookupFailure(list)); } } - threadDeregister(); + + RunEpilog(); } MetadataLookup* MetadataDownload::moreWork() diff --git a/mythtv/libs/libmythmetadata/metadatadownload.h b/mythtv/libs/libmythmetadata/metadatadownload.h index 4880277196d..5185e2ac176 100644 --- a/mythtv/libs/libmythmetadata/metadatadownload.h +++ b/mythtv/libs/libmythmetadata/metadatadownload.h @@ -1,11 +1,12 @@ #ifndef METADATADOWNLOAD_H #define METADATADOWNLOAD_H -#include -#include #include +#include +#include #include "metadatacommon.h" +#include "mthread.h" class META_PUBLIC MetadataLookupEvent : public QEvent { @@ -31,7 +32,7 @@ class META_PUBLIC MetadataLookupFailure : public QEvent static Type kEventType; }; -class META_PUBLIC MetadataDownload : public QThread +class META_PUBLIC MetadataDownload : public MThread { public: diff --git a/mythtv/libs/libmythmetadata/metadataimagedownload.cpp b/mythtv/libs/libmythmetadata/metadataimagedownload.cpp index e8cacaba86f..3001deb6364 100644 --- a/mythtv/libs/libmythmetadata/metadataimagedownload.cpp +++ b/mythtv/libs/libmythmetadata/metadataimagedownload.cpp @@ -25,7 +25,8 @@ QEvent::Type ImageDLFailureEvent::kEventType = QEvent::Type ThumbnailDLEvent::kEventType = (QEvent::Type) QEvent::registerEventType(); -MetadataImageDownload::MetadataImageDownload(QObject *parent) +MetadataImageDownload::MetadataImageDownload(QObject *parent) : + MThread("MetadataImageDownload") { m_parent = parent; } @@ -71,9 +72,10 @@ void MetadataImageDownload::cancel() void MetadataImageDownload::run() { + RunProlog(); + // Always handle thumbnails first, they're higher priority. ThumbnailData *thumb; - threadRegister("MetadataImageDownload"); while ((thumb = moreThumbs()) != NULL) { QString sFilename = getDownloadFilename(thumb->title, thumb->url); @@ -300,7 +302,8 @@ void MetadataImageDownload::run() lookup->SetDownloads(downloaded); QCoreApplication::postEvent(m_parent, new ImageDLEvent(lookup)); } - threadDeregister(); + + RunEpilog(); } ThumbnailData* MetadataImageDownload::moreThumbs() diff --git a/mythtv/libs/libmythmetadata/metadataimagedownload.h b/mythtv/libs/libmythmetadata/metadataimagedownload.h index f274578a2e8..86666570cd9 100644 --- a/mythtv/libs/libmythmetadata/metadataimagedownload.h +++ b/mythtv/libs/libmythmetadata/metadataimagedownload.h @@ -1,10 +1,10 @@ #ifndef METADATAIMAGEDOWNLOAD_H #define METADATAIMAGEDOWNLOAD_H -#include #include #include +#include "mthread.h" #include "mythmetaexp.h" #include "metadatacommon.h" @@ -53,7 +53,7 @@ class META_PUBLIC ThumbnailDLEvent : public QEvent static Type kEventType; }; -class META_PUBLIC MetadataImageDownload : public QThread +class META_PUBLIC MetadataImageDownload : public MThread { public: diff --git a/mythtv/libs/libmythmetadata/videoscan.cpp b/mythtv/libs/libmythmetadata/videoscan.cpp index f895f5f3681..b378d2263a2 100644 --- a/mythtv/libs/libmythmetadata/videoscan.cpp +++ b/mythtv/libs/libmythmetadata/videoscan.cpp @@ -1,7 +1,5 @@ #include #include -#include -#include #include #include "mythcontext.h" @@ -75,8 +73,9 @@ class VideoMetadataListManager; class MythUIProgressDialog; VideoScannerThread::VideoScannerThread(QObject *parent) : - m_RemoveAll(false), m_KeepAll(false), - m_DBDataChanged(false) + MThread("VideoScanner"), + m_RemoveAll(false), m_KeepAll(false), + m_DBDataChanged(false) { m_parent = parent; m_dbmetadata = new VideoMetadataListManager; @@ -91,7 +90,7 @@ VideoScannerThread::~VideoScannerThread() void VideoScannerThread::run() { - threadRegister("VideoScanner"); + RunProlog(); VideoMetadataListManager::metadata_list ml; VideoMetadataListManager::loadAllFromDatabase(ml); @@ -113,7 +112,7 @@ void VideoScannerThread::run() if (m_HasGUI) SendProgressEvent(counter, (uint)m_directories.size(), - tr("Searching for video files")); + QObject::tr("Searching for video files")); for (QStringList::const_iterator iter = m_directories.begin(); iter != m_directories.end(); ++iter) { @@ -161,7 +160,8 @@ void VideoScannerThread::run() } else RemoteSendMessage("VIDEO_LIST_NO_CHANGE"); - threadDeregister(); + + RunEpilog(); } @@ -189,7 +189,7 @@ void VideoScannerThread::verifyFiles(FileCheckList &files, if (m_HasGUI) SendProgressEvent(counter, (uint)m_dbmetadata->getList().size(), - tr("Verifying video files")); + QObject::tr("Verifying video files")); // For every file we know about, check to see if it still exists. for (VideoMetadataListManager::metadata_list::const_iterator p = @@ -236,7 +236,7 @@ bool VideoScannerThread::updateDB(const FileCheckList &add, const PurgeList &rem uint counter = 0; if (m_HasGUI) SendProgressEvent(counter, (uint)(add.size() + remove.size()), - tr("Updating video database")); + QObject::tr("Updating video database")); for (FileCheckList::const_iterator p = add.begin(); p != add.end(); ++p) { @@ -363,9 +363,9 @@ void VideoScanner::doScan(const QStringList &dirs) if (progressDlg->Create()) { popupStack->AddScreen(progressDlg, false); - connect(m_scanThread, SIGNAL(finished()), + connect(m_scanThread->qthread(), SIGNAL(finished()), progressDlg, SLOT(Close())); - connect(m_scanThread, SIGNAL(finished()), + connect(m_scanThread->qthread(), SIGNAL(finished()), SLOT(finishedScan())); } else diff --git a/mythtv/libs/libmythmetadata/videoscan.h b/mythtv/libs/libmythmetadata/videoscan.h index da618522c1d..1bb5211bf8b 100644 --- a/mythtv/libs/libmythmetadata/videoscan.h +++ b/mythtv/libs/libmythmetadata/videoscan.h @@ -7,10 +7,10 @@ #include // for moc #include -#include #include #include "mythmetaexp.h" +#include "mthread.h" class QStringList; @@ -56,10 +56,8 @@ class META_PUBLIC VideoScanChanges : public QEvent static Type kEventType; }; -class META_PUBLIC VideoScannerThread : public QThread +class META_PUBLIC VideoScannerThread : public MThread { - Q_OBJECT - public: VideoScannerThread(QObject *parent); ~VideoScannerThread(); diff --git a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp index 0cf7ed83a8e..9918db41649 100644 --- a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp +++ b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp @@ -7,7 +7,6 @@ using namespace std; #include #include #include -#include #include #include #include @@ -21,6 +20,7 @@ using namespace std; #include "mythconfig.h" #include "mythversion.h" #include "mythlogging.h" +#include "mthread.h" #define LOC QString("MythSocketManager: ") @@ -29,10 +29,11 @@ using namespace std; uint socket_id = 1; -class ProcessRequestThread : public QThread +class ProcessRequestThread : public MThread { public: ProcessRequestThread(MythSocketManager *ms): + MThread("ProcessRequestThread"), m_parent(ms), m_socket(NULL), m_threadlives(false) {} void setup(MythSocket *sock) @@ -52,7 +53,8 @@ class ProcessRequestThread : public QThread virtual void run(void) { - threadRegister("ProcessRequest"); + RunProlog(); + QMutexLocker locker(&m_lock); m_threadlives = true; m_waitCond.wakeAll(); // Signal to creating thread @@ -76,7 +78,8 @@ class ProcessRequestThread : public QThread m_socket = NULL; m_parent->MarkUnused(this); } - threadDeregister(); + + RunEpilog(); } QMutex m_lock; diff --git a/mythtv/libs/libmythprotoserver/requesthandler/deletethread.cpp b/mythtv/libs/libmythprotoserver/requesthandler/deletethread.cpp index 26e4ea87581..221c9b1f9f6 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/deletethread.cpp +++ b/mythtv/libs/libmythprotoserver/requesthandler/deletethread.cpp @@ -27,7 +27,7 @@ using namespace std; */ DeleteThread::DeleteThread(void) : - m_increment(9961472), m_run(true), m_timeout(20000) + MThread("Delete"), m_increment(9961472), m_run(true), m_timeout(20000) { m_slow = (bool) gCoreContext->GetNumSetting("TruncateDeletesSlowly", 0); m_link = (bool) gCoreContext->GetNumSetting("DeletesFollowLinks", 0); @@ -38,7 +38,7 @@ DeleteThread::DeleteThread(void) : void DeleteThread::run(void) { - threadRegister("Delete"); + RunProlog(); LOG(VB_FILE, LOG_DEBUG, "Spawning new delete thread."); @@ -64,7 +64,7 @@ void DeleteThread::run(void) else LOG(VB_FILE, LOG_DEBUG, "Delete thread self-terminating due to idle."); - threadDeregister(); + RunEpilog(); } bool DeleteThread::AddFile(QString path) diff --git a/mythtv/libs/libmythprotoserver/requesthandler/deletethread.h b/mythtv/libs/libmythprotoserver/requesthandler/deletethread.h index 2bb090d8bc2..5cdd065aa90 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/deletethread.h +++ b/mythtv/libs/libmythprotoserver/requesthandler/deletethread.h @@ -14,11 +14,13 @@ using namespace std; // Qt headers #include #include -#include #include #include #include +// MythTV headers +#include "mthread.h" + typedef struct deletestruct { QString path; @@ -27,7 +29,7 @@ typedef struct deletestruct QDateTime wait; } DeleteStruct; -class DeleteThread : public QThread +class DeleteThread : public QObject, public MThread { Q_OBJECT public: diff --git a/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp b/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp index 07ba95a5127..aba37f6c473 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp +++ b/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp @@ -163,7 +163,7 @@ void FileServerHandler::RunDeleteThread(void) this, SIGNAL(unlinkFailed(QString))); connect(deletethread, SIGNAL(fileUnlinked(QString)), this, SIGNAL(fileUnlinked(QString))); - connect(deletethread, SIGNAL(finished()), + connect(deletethread->qthread(), SIGNAL(finished()), this, SLOT(deleteThreadTerminated())); deletethread->start(); } diff --git a/mythtv/libs/libmythtv/DeviceReadBuffer.cpp b/mythtv/libs/libmythtv/DeviceReadBuffer.cpp index 68de6e0e1a3..13f0e39d5d4 100644 --- a/mythtv/libs/libmythtv/DeviceReadBuffer.cpp +++ b/mythtv/libs/libmythtv/DeviceReadBuffer.cpp @@ -1,13 +1,13 @@ #include using namespace std; -#include #include "DeviceReadBuffer.h" #include "mythcorecontext.h" #include "mythbaseutil.h" +#include "mythlogging.h" #include "tspacket.h" +#include "mthread.h" #include "compat.h" -#include "mythlogging.h" #ifndef USING_MINGW #include @@ -19,7 +19,8 @@ using namespace std; #define LOC QString("DevRdB(%1): ").arg(videodevice) DeviceReadBuffer::DeviceReadBuffer(DeviceReaderCB *cb, bool use_poll) - : videodevice(""), _stream_fd(-1), + : MThread("DeviceReadBuffer"), + videodevice(""), _stream_fd(-1), readerCB(cb), // Data for managing the device ringbuffer @@ -319,9 +320,10 @@ void DeviceReadBuffer::IncrReadPointer(uint len) void DeviceReadBuffer::run(void) { + RunProlog(); + uint errcnt = 0; - threadRegister("DeviceReadBuffer"); lock.lock(); runWait.wakeAll(); lock.unlock(); @@ -385,7 +387,7 @@ void DeviceReadBuffer::run(void) unpauseWait.wakeAll(); lock.unlock(); - threadDeregister(); + RunEpilog(); } bool DeviceReadBuffer::HandlePausing(void) diff --git a/mythtv/libs/libmythtv/DeviceReadBuffer.h b/mythtv/libs/libmythtv/DeviceReadBuffer.h index 3779d54ab69..225478e4b24 100644 --- a/mythtv/libs/libmythtv/DeviceReadBuffer.h +++ b/mythtv/libs/libmythtv/DeviceReadBuffer.h @@ -9,9 +9,9 @@ #include #include #include -#include #include "tspacket.h" +#include "mthread.h" #include "util.h" class DeviceReaderCB @@ -30,7 +30,7 @@ class DeviceReaderCB * of long blocking conditions on writing to disk or accessing the * database. */ -class DeviceReadBuffer : protected QThread +class DeviceReadBuffer : protected MThread { public: DeviceReadBuffer(DeviceReaderCB *callback, @@ -58,7 +58,7 @@ class DeviceReadBuffer : protected QThread uint Read(unsigned char *buf, uint count); private: - virtual void run(void); // QThread + virtual void run(void); // MThread void SetPaused(bool); void IncrWritePointer(uint len); diff --git a/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp b/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp index 4f35146233d..0d2b734f565 100644 --- a/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp +++ b/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp @@ -69,16 +69,16 @@ extern "C" { void NVRWriteThread::run(void) { - threadRegister("NVRWrite"); + RunProlog(); m_parent->doWriteThread(); - threadDeregister(); + RunEpilog(); } void NVRAudioThread::run(void) { - threadRegister("NVRAudio"); + RunProlog(); m_parent->doAudioThread(); - threadDeregister(); + RunEpilog(); } NuppelVideoRecorder::NuppelVideoRecorder(TVRec *rec, ChannelBase *channel) : diff --git a/mythtv/libs/libmythtv/NuppelVideoRecorder.h b/mythtv/libs/libmythtv/NuppelVideoRecorder.h index d44492655ea..7cff4217197 100644 --- a/mythtv/libs/libmythtv/NuppelVideoRecorder.h +++ b/mythtv/libs/libmythtv/NuppelVideoRecorder.h @@ -6,7 +6,6 @@ #include #include -#include #ifdef MMX #undef MMX #define MMXBLAH @@ -27,7 +26,6 @@ using namespace std; // Qt headers #include -#include // MythTV headers #include "v4lrecorder.h" @@ -35,6 +33,7 @@ using namespace std; #include "cc608decoder.h" #include "filter.h" #include "minilzo.h" +#include "mthread.h" #include "mythtvexp.h" @@ -47,22 +46,22 @@ class FilterChain; class AudioInput; class NuppelVideoRecorder; -class NVRWriteThread : public QThread +class NVRWriteThread : public MThread { - Q_OBJECT public: - NVRWriteThread(NuppelVideoRecorder *parent) : m_parent(parent) {} + NVRWriteThread(NuppelVideoRecorder *parent) : + MThread("NVRWrite"), m_parent(parent) {} virtual ~NVRWriteThread() { wait(); m_parent = NULL; } virtual void run(void); private: NuppelVideoRecorder *m_parent; }; -class NVRAudioThread : public QThread +class NVRAudioThread : public MThread { - Q_OBJECT public: - NVRAudioThread(NuppelVideoRecorder *parent) : m_parent(parent) {} + NVRAudioThread(NuppelVideoRecorder *parent) : + MThread("NVRAudio"), m_parent(parent) {} virtual ~NVRAudioThread() { wait(); m_parent = NULL; } virtual void run(void); private: diff --git a/mythtv/libs/libmythtv/ThreadedFileWriter.cpp b/mythtv/libs/libmythtv/ThreadedFileWriter.cpp index 934b5120663..191f4c1a166 100644 --- a/mythtv/libs/libmythtv/ThreadedFileWriter.cpp +++ b/mythtv/libs/libmythtv/ThreadedFileWriter.cpp @@ -13,7 +13,6 @@ // Qt headers #include -#include // MythTV headers #include "ThreadedFileWriter.h" @@ -27,21 +26,17 @@ /// \brief Runs ThreadedFileWriter::DiskLoop(void) void TFWWriteThread::run(void) { - threadRegister("TFWWrite"); -#ifndef USING_MINGW - // don't exit program if file gets larger than quota limit.. - signal(SIGXFSZ, SIG_IGN); -#endif + RunProlog(); m_parent->DiskLoop(); - threadDeregister(); + RunEpilog(); } /// \brief Runs ThreadedFileWriter::SyncLoop(void) void TFWSyncThread::run(void) { - threadRegister("TFWSync"); + RunProlog(); m_parent->SyncLoop(); - threadDeregister(); + RunEpilog(); } const uint ThreadedFileWriter::kMaxBufferSize = 128 * 1024 * 1024; @@ -345,6 +340,11 @@ void ThreadedFileWriter::SyncLoop(void) */ void ThreadedFileWriter::DiskLoop(void) { +#ifndef USING_MINGW + // don't exit program if file gets larger than quota limit.. + signal(SIGXFSZ, SIG_IGN); +#endif + QMutexLocker locker(&buflock); // Even if the bytes buffered is less than the minimum write diff --git a/mythtv/libs/libmythtv/ThreadedFileWriter.h b/mythtv/libs/libmythtv/ThreadedFileWriter.h index 260a5a36561..8038f771dfe 100644 --- a/mythtv/libs/libmythtv/ThreadedFileWriter.h +++ b/mythtv/libs/libmythtv/ThreadedFileWriter.h @@ -9,29 +9,28 @@ using namespace std; #include #include #include -#include #include #include +#include "mthread.h" + class ThreadedFileWriter; -class TFWWriteThread : public QThread +class TFWWriteThread : public MThread { - Q_OBJECT public: - TFWWriteThread(ThreadedFileWriter *p) : m_parent(p) {} + TFWWriteThread(ThreadedFileWriter *p) : MThread("TFWWrite"), m_parent(p) {} virtual ~TFWWriteThread() { wait(); m_parent = NULL; } virtual void run(void); private: ThreadedFileWriter *m_parent; }; -class TFWSyncThread : public QThread +class TFWSyncThread : public MThread { - Q_OBJECT public: - TFWSyncThread(ThreadedFileWriter *p) : m_parent(p) {} + TFWSyncThread(ThreadedFileWriter *p) : MThread("TFWSync"), m_parent(p) {} virtual ~TFWSyncThread() { wait(); m_parent = NULL; } virtual void run(void); private: diff --git a/mythtv/libs/libmythtv/asisignalmonitor.cpp b/mythtv/libs/libmythtv/asisignalmonitor.cpp index b43fde74de3..319abe72960 100644 --- a/mythtv/libs/libmythtv/asisignalmonitor.cpp +++ b/mythtv/libs/libmythtv/asisignalmonitor.cpp @@ -78,7 +78,7 @@ ASIChannel *ASISignalMonitor::GetASIChannel(void) /** \fn ASISignalMonitor::UpdateValues(void) * \brief Fills in frontend stats and emits status Qt signals. * - * This is automatically called by MonitorLoop(), after Start() + * This is automatically called by run(), after Start() * has been used to start the signal monitoring thread. */ void ASISignalMonitor::UpdateValues(void) diff --git a/mythtv/libs/libmythtv/asistreamhandler.cpp b/mythtv/libs/libmythtv/asistreamhandler.cpp index c9762f9a6ba..4c5afce038f 100644 --- a/mythtv/libs/libmythtv/asistreamhandler.cpp +++ b/mythtv/libs/libmythtv/asistreamhandler.cpp @@ -106,6 +106,7 @@ ASIStreamHandler::ASIStreamHandler(const QString &device) : _packet_size(TSPacket::kSize), _clock_source(kASIInternalClock), _rx_mode(kASIRXSyncOnActualConvertTo188), _drb(NULL), _mpts(NULL) { + setObjectName("ASISH"); } void ASIStreamHandler::SetClockSource(ASIClockSource cs) @@ -131,6 +132,8 @@ void ASIStreamHandler::SetRunningDesired(bool desired) void ASIStreamHandler::run(void) { + RunProlog(); + LOG(VB_RECORD, LOG_INFO, LOC + "run(): begin"); if (!Open()) @@ -150,6 +153,7 @@ void ASIStreamHandler::run(void) drb = NULL; Close(); _error = true; + RunEpilog(); return; } @@ -162,6 +166,7 @@ void ASIStreamHandler::run(void) drb = NULL; Close(); _error = true; + RunEpilog(); return; } memset(buffer, 0, buffer_size); @@ -258,6 +263,7 @@ void ASIStreamHandler::run(void) LOG(VB_RECORD, LOG_INFO, LOC + "run(): " + "end"); SetRunning(false, true, false); + RunEpilog(); } bool ASIStreamHandler::Open(void) diff --git a/mythtv/libs/libmythtv/asistreamhandler.h b/mythtv/libs/libmythtv/asistreamhandler.h index c0bf1e21fa7..14be6fe8f45 100644 --- a/mythtv/libs/libmythtv/asistreamhandler.h +++ b/mythtv/libs/libmythtv/asistreamhandler.h @@ -67,7 +67,7 @@ class ASIStreamHandler : public StreamHandler bool Open(void); void Close(void); - virtual void run(void); // QThread + virtual void run(void); // MThread virtual void PriorityEvent(int fd); // DeviceReaderCB diff --git a/mythtv/libs/libmythtv/bdringbuffer.cpp b/mythtv/libs/libmythtv/bdringbuffer.cpp index 7ee5b9c3cfd..8028527f4da 100644 --- a/mythtv/libs/libmythtv/bdringbuffer.cpp +++ b/mythtv/libs/libmythtv/bdringbuffer.cpp @@ -262,7 +262,7 @@ void BDRingBuffer::ProgressUpdate(void) { // This thread check is probably unnecessary as processEvents should // only handle events in the calling thread - and not all threads - if (QThread::currentThread() != m_mainThread) + if (!is_current_thread(m_mainThread)) return; qApp->postEvent(GetMythMainWindow(), diff --git a/mythtv/libs/libmythtv/channelbase.h b/mythtv/libs/libmythtv/channelbase.h index 357c80c1512..b633659bfbf 100644 --- a/mythtv/libs/libmythtv/channelbase.h +++ b/mythtv/libs/libmythtv/channelbase.h @@ -6,7 +6,6 @@ // Qt headers #include #include -#include #include // MythTV headers diff --git a/mythtv/libs/libmythtv/channelscan/channelscan_sm.cpp b/mythtv/libs/libmythtv/channelscan/channelscan_sm.cpp index 61e6faf537d..7d74042ef6c 100644 --- a/mythtv/libs/libmythtv/channelscan/channelscan_sm.cpp +++ b/mythtv/libs/libmythtv/channelscan/channelscan_sm.cpp @@ -44,6 +44,7 @@ using namespace std; #include "channelutil.h" #include "cardutil.h" #include "sourceutil.h" +#include "mthread.h" #include "mythdb.h" #include "mythlogging.h" @@ -62,17 +63,6 @@ using namespace std; #include "hdhrchannel.h" #include "v4lchannel.h" -/** \fn ScannerThread::run(void) - * \brief Thunk that allows scannerThread thread to - * call ChannelScanSM::RunScanner(). - */ -void ScannerThread::run(void) -{ - threadRegister("Scanner"); - m_parent->RunScanner(); - threadDeregister(); -} - /// SDT's should be sent every 2 seconds and NIT's every /// 10 seconds, so lets wait at least 30 seconds, in /// case of bad transmitter or lost packets. @@ -1438,16 +1428,16 @@ void ChannelScanSM::StartScanner(void) } } threadExit = false; - scannerThread = new ScannerThread(this); + scannerThread = new MThread("Scanner", this); scannerThread->start(); } -/** \fn ChannelScanSM::RunScanner(void) +/** \fn ChannelScanSM::run(void) * \brief This runs the event loop for ChannelScanSM until 'threadExit' is true. */ -void ChannelScanSM::RunScanner(void) +void ChannelScanSM::run(void) { - LOG(VB_CHANSCAN, LOG_INFO, LOC + "RunScanner -- begin"); + LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin"); while (!threadExit) { @@ -1457,7 +1447,7 @@ void ChannelScanSM::RunScanner(void) usleep(10 * 1000); } - LOG(VB_CHANSCAN, LOG_INFO, LOC + "RunScanner -- end"); + LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end"); } // See if we have timed out diff --git a/mythtv/libs/libmythtv/channelscan/channelscan_sm.h b/mythtv/libs/libmythtv/channelscan/channelscan_sm.h index 5ef69bcc637..62c3ee5b7b0 100644 --- a/mythtv/libs/libmythtv/channelscan/channelscan_sm.h +++ b/mythtv/libs/libmythtv/channelscan/channelscan_sm.h @@ -31,8 +31,8 @@ #define SISCAN_H // Qt includes +#include #include -#include #include #include #include @@ -45,6 +45,7 @@ #include "signalmonitorlistener.h" #include "dtvconfparserhelpers.h" // for DTVTunerType +class MThread; class MSqlQuery; class ChannelBase; @@ -79,24 +80,13 @@ class AnalogSignalHandler : public SignalMonitorListener ChannelScanSM *siscan; }; -class ScannerThread : public QThread -{ - Q_OBJECT - public: - ScannerThread(ChannelScanSM *parent) : m_parent(parent) {} - ~ScannerThread() { wait(); m_parent = NULL; } - void run(void); - private: - ChannelScanSM *m_parent; -}; - class ChannelScanSM : public MPEGStreamListener, public ATSCMainStreamListener, public DVBMainStreamListener, - public DVBOtherStreamListener + public DVBOtherStreamListener, + public QRunnable { friend class AnalogSignalHandler; - friend class ScannerThread; public: ChannelScanSM( @@ -172,8 +162,7 @@ class ChannelScanSM : public MPEGStreamListener, DVBChannel *GetDVBChannel(void); const DVBChannel *GetDVBChannel(void) const; - /// \brief Called by SpawnScanner to run scanning thread - void RunScanner(void); + void run(void); // QRunnable bool HasTimedOut(void); void HandleActiveScan(void); @@ -254,8 +243,8 @@ class ChannelScanSM : public MPEGStreamListener, // Analog Info AnalogSignalHandler *analogSignalHandler; - /// Scanner thread, runs ChannelScanSM::StartScanner() - ScannerThread *scannerThread; + /// Scanner thread, runs ChannelScanSM::run() + MThread *scannerThread; }; inline void ChannelScanSM::UpdateScanPercentCompleted(void) diff --git a/mythtv/libs/libmythtv/dvbcam.cpp b/mythtv/libs/libmythtv/dvbcam.cpp index 815b233f1cb..74a2e96be59 100644 --- a/mythtv/libs/libmythtv/dvbcam.cpp +++ b/mythtv/libs/libmythtv/dvbcam.cpp @@ -52,19 +52,13 @@ using namespace std; #include "cardutil.h" #include "dvbcam.h" +#include "mthread.h" #include "dvbchannel.h" #include "dvbrecorder.h" #include "mythlogging.h" #define LOC QString("DVB#%1 CA: ").arg(device) -void DVBCamThread::run(void) -{ - threadRegister("DVBCam"); - m_parent->CiHandlerLoop(); - threadDeregister(); -} - DVBCam::DVBCam(const QString &aDevice) : device(aDevice), numslots(0), ciHandlerDoRun(false), ciHandlerRunning(false), @@ -110,7 +104,7 @@ bool DVBCam::Start(void) QMutexLocker locker(&ciHandlerLock); ciHandlerDoRun = true; - ciHandlerThread = new DVBCamThread(this); + ciHandlerThread = new MThread("DVBCam", this); ciHandlerThread->start(); while (ciHandlerDoRun && !ciHandlerRunning) ciHandlerWait.wait(locker.mutex(), 1000); @@ -257,7 +251,7 @@ void DVBCam::HandlePMT(void) pmt_added = false; } -void DVBCam::CiHandlerLoop() +void DVBCam::run(void) { LOG(VB_DVBCAM, LOG_INFO, LOC + "CI handler thread running"); diff --git a/mythtv/libs/libmythtv/dvbcam.h b/mythtv/libs/libmythtv/dvbcam.h index e17f1c25551..03a5a5e3636 100644 --- a/mythtv/libs/libmythtv/dvbcam.h +++ b/mythtv/libs/libmythtv/dvbcam.h @@ -5,8 +5,8 @@ using namespace std; #include +#include #include -#include #include #include "mpegtables.h" @@ -15,25 +15,13 @@ using namespace std; class ChannelBase; class cCiHandler; +class MThread; class DVBCam; typedef QMap pmt_list_t; -class DVBCamThread : public QThread +class DVBCam : public QRunnable { - Q_OBJECT - public: - DVBCamThread(DVBCam *p) : m_parent(p) {} - virtual ~DVBCamThread() { wait(); m_parent = NULL; } - virtual void run(void); - private: - DVBCam *m_parent; -}; - -class DVBCam -{ - friend class DVBCamThread; - public: DVBCam(const QString &device); ~DVBCam(); @@ -50,7 +38,7 @@ class DVBCam void SetTimeOffset(double offset_in_seconds); private: - void CiHandlerLoop(void); + void run(void); // QRunnable void HandleUserIO(void); void HandlePMT(void); @@ -64,7 +52,7 @@ class DVBCam bool ciHandlerDoRun; bool ciHandlerRunning; cCiHandler *ciHandler; - DVBCamThread *ciHandlerThread; + MThread *ciHandlerThread; QMutex pmt_lock; pmt_list_t PMTList; diff --git a/mythtv/libs/libmythtv/dvbsignalmonitor.cpp b/mythtv/libs/libmythtv/dvbsignalmonitor.cpp index d91948b5b75..1fa010e23ef 100644 --- a/mythtv/libs/libmythtv/dvbsignalmonitor.cpp +++ b/mythtv/libs/libmythtv/dvbsignalmonitor.cpp @@ -203,7 +203,7 @@ DVBChannel *DVBSignalMonitor::GetDVBChannel(void) /** \fn DVBSignalMonitor::UpdateValues() * \brief Fills in frontend stats and emits status Qt signals. * - * This is automatically called by MonitorLoop(), after Start() + * This is automatically called by run(), after Start() * has been used to start the signal monitoring thread. */ void DVBSignalMonitor::UpdateValues(void) diff --git a/mythtv/libs/libmythtv/dvbstreamhandler.cpp b/mythtv/libs/libmythtv/dvbstreamhandler.cpp index 7c30d71c021..33c05172fe1 100644 --- a/mythtv/libs/libmythtv/dvbstreamhandler.cpp +++ b/mythtv/libs/libmythtv/dvbstreamhandler.cpp @@ -91,6 +91,7 @@ DVBStreamHandler::DVBStreamHandler(const QString &dvb_device) : _dvbchannel(NULL), _drb(NULL) { + setObjectName("DVBRead"); } void DVBStreamHandler::SetRunningDesired(bool desired) @@ -102,7 +103,7 @@ void DVBStreamHandler::SetRunningDesired(bool desired) void DVBStreamHandler::run(void) { - threadRegister("DVBRead"); + RunProlog(); LOG(VB_RECORD, LOG_INFO, LOC + "run(): begin"); if (!SupportsTSMonitoring() && _allow_section_reader) @@ -111,7 +112,7 @@ void DVBStreamHandler::run(void) RunTS(); LOG(VB_RECORD, LOG_INFO, LOC + "run(): end"); - threadDeregister(); + RunEpilog(); } /** \fn DVBStreamHandler::RunTS(void) diff --git a/mythtv/libs/libmythtv/dvbstreamhandler.h b/mythtv/libs/libmythtv/dvbstreamhandler.h index bef6b8083a9..a3bfc1c2595 100644 --- a/mythtv/libs/libmythtv/dvbstreamhandler.h +++ b/mythtv/libs/libmythtv/dvbstreamhandler.h @@ -51,7 +51,7 @@ class DVBStreamHandler : public StreamHandler private: DVBStreamHandler(const QString &); - virtual void run(void); // QThread + virtual void run(void); // MThread void RunTS(void); void RunSR(void); diff --git a/mythtv/libs/libmythtv/eitscanner.cpp b/mythtv/libs/libmythtv/eitscanner.cpp index 77f867d27b5..36a97c5943a 100644 --- a/mythtv/libs/libmythtv/eitscanner.cpp +++ b/mythtv/libs/libmythtv/eitscanner.cpp @@ -16,22 +16,11 @@ #include "util.h" #include "mythdb.h" #include "mythlogging.h" +#include "mthread.h" #define LOC QString("EITScanner: ") #define LOC_ID QString("EITScanner (%1): ").arg(cardnum) - -/** \fn EITThread::run(void) - * \brief Thunk that allows scanner Qthread to - * call EITScanner::RunEventLoop(). - */ -void EITThread::run(void) -{ - threadRegister("EIT"); - scanner->RunEventLoop(); - threadDeregister(); -} - /** \class EITScanner * \brief Acts as glue between ChannelBase, EITSource, and EITHelper. * @@ -45,16 +34,15 @@ const uint EITScanner::kMinRescheduleInterval = 150; EITScanner::EITScanner(uint _cardnum) : channel(NULL), eitSource(NULL), - eitHelper(new EITHelper()), exitThread(false), + eitHelper(new EITHelper()), eventThread(new MThread("EIT", this)), + exitThread(false), rec(NULL), activeScan(false), activeScanTrigTime(0), cardnum(_cardnum) { QStringList langPref = iso639_get_language_list(); eitHelper->SetLanguagePreferences(langPref); - // Start scanner with Idle scheduling priority, to avoid problems with recordings. - eventThread.scanner = this; - eventThread.start(QThread::IdlePriority); + eventThread->start(QThread::IdlePriority); } void EITScanner::TeardownAll(void) @@ -66,8 +54,10 @@ void EITScanner::TeardownAll(void) exitThread = true; exitThreadCond.wakeAll(); lock.unlock(); - eventThread.wait(); } + eventThread->wait(); + delete eventThread; + eventThread = NULL; if (eitHelper) { @@ -76,10 +66,10 @@ void EITScanner::TeardownAll(void) } } -/** \fn EITScanner::RunEventLoop(void) +/** * \brief This runs the event loop for EITScanner until 'exitThread' is true. */ -void EITScanner::RunEventLoop(void) +void EITScanner::run(void) { static const uint sz[] = { 2000, 1800, 1600, 1400, 1200, }; static const float rt[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, }; diff --git a/mythtv/libs/libmythtv/eitscanner.h b/mythtv/libs/libmythtv/eitscanner.h index 47fc40ba4c0..36dd4d93582 100644 --- a/mythtv/libs/libmythtv/eitscanner.h +++ b/mythtv/libs/libmythtv/eitscanner.h @@ -6,10 +6,11 @@ #include #include #include -#include +#include #include class TVRec; +class MThread; class ChannelBase; class DVBSIParser; class EITHelper; @@ -26,17 +27,8 @@ class EITSource class EITScanner; -class EITThread : public QThread +class EITScanner : public QRunnable { - public: - virtual void run(); - EITScanner *scanner; -}; - -class EITScanner -{ - friend class EITThread; - public: EITScanner(uint cardnum); ~EITScanner() { TeardownAll(); } @@ -49,7 +41,7 @@ class EITScanner void StopActiveScan(void); protected: - void RunEventLoop(void); + void run(void); private: void TeardownAll(void); @@ -61,7 +53,7 @@ class EITScanner EITSource *eitSource; EITHelper *eitHelper; - EITThread eventThread; + MThread *eventThread; bool exitThread; QWaitCondition exitThreadCond; diff --git a/mythtv/libs/libmythtv/fifowriter.cpp b/mythtv/libs/libmythtv/fifowriter.cpp index 2f8a460cdde..0565f0c10a8 100644 --- a/mythtv/libs/libmythtv/fifowriter.cpp +++ b/mythtv/libs/libmythtv/fifowriter.cpp @@ -135,12 +135,10 @@ int FIFOWriter::FIFOInit(int id, QString desc, QString name, long size, void FIFOThread::run(void) { - if (!m_parent || m_id == -1) - return; - - threadRegister(QString("FIFOWrite%1").arg(m_id)); - m_parent->FIFOWriteThread(m_id); - threadDeregister(); + RunProlog(); + if (m_parent && m_id != -1) + m_parent->FIFOWriteThread(m_id); + RunEpilog(); } void FIFOWriter::FIFOWriteThread(int id) diff --git a/mythtv/libs/libmythtv/fifowriter.h b/mythtv/libs/libmythtv/fifowriter.h index 32a03677848..96e7f5ac18d 100644 --- a/mythtv/libs/libmythtv/fifowriter.h +++ b/mythtv/libs/libmythtv/fifowriter.h @@ -3,22 +3,21 @@ // Qt headers #include -#include #include #include // MythTV headers #include "mythtvexp.h" +#include "mthread.h" using namespace std; class FIFOWriter; -class FIFOThread : public QThread +class FIFOThread : public MThread { - Q_OBJECT public: - FIFOThread() : m_parent(NULL), m_id(-1) {} + FIFOThread() : MThread("FIFOThread"), m_parent(NULL), m_id(-1) {} virtual ~FIFOThread() { wait(); m_parent = NULL; m_id = -1; } void SetId(int id) { m_id = id; } void SetParent(FIFOWriter *parent) { m_parent = parent; } diff --git a/mythtv/libs/libmythtv/firewiresignalmonitor.cpp b/mythtv/libs/libmythtv/firewiresignalmonitor.cpp index 4f8522674ba..6c0a05d41b9 100644 --- a/mythtv/libs/libmythtv/firewiresignalmonitor.cpp +++ b/mythtv/libs/libmythtv/firewiresignalmonitor.cpp @@ -17,9 +17,9 @@ void FirewireTableMonitorThread::run(void) { - threadRegister("FirewireTableMonitor"); + RunProlog(); m_parent->RunTableMonitor(); - threadDeregister(); + RunEpilog(); } const uint FirewireSignalMonitor::kPowerTimeout = 3000; /* ms */ @@ -185,7 +185,7 @@ void FirewireSignalMonitor::AddData(const unsigned char *data, uint len) * FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain * statistics from the frontend. * - * This is automatically called by MonitorLoop(), after Start() + * This is automatically called by run(), after Start() * has been used to start the signal monitoring thread. */ void FirewireSignalMonitor::UpdateValues(void) diff --git a/mythtv/libs/libmythtv/firewiresignalmonitor.h b/mythtv/libs/libmythtv/firewiresignalmonitor.h index b10e78aa42c..60b61aa5d75 100644 --- a/mythtv/libs/libmythtv/firewiresignalmonitor.h +++ b/mythtv/libs/libmythtv/firewiresignalmonitor.h @@ -8,26 +8,25 @@ using namespace std; // Qt headers -#include #include #include // MythTV headers #include "dtvsignalmonitor.h" #include "firewiredevice.h" +#include "mthread.h" #include "util.h" class FirewireChannel; class FirewireSignalMonitor; -class FirewireTableMonitorThread : public QThread +class FirewireTableMonitorThread : public MThread { - Q_OBJECT public: FirewireTableMonitorThread(FirewireSignalMonitor *p) : - m_parent(p) { start(); } - virtual ~FirewireTableMonitorThread() { wait(); } + MThread("FirewireTableMonitor"), m_parent(p) { start(); } + virtual ~FirewireTableMonitorThread() { wait(); m_parent = NULL; } virtual void run(void); private: FirewireSignalMonitor *m_parent; diff --git a/mythtv/libs/libmythtv/hdhrstreamhandler.cpp b/mythtv/libs/libmythtv/hdhrstreamhandler.cpp index 06b922a879b..dee7de4a00b 100644 --- a/mythtv/libs/libmythtv/hdhrstreamhandler.cpp +++ b/mythtv/libs/libmythtv/hdhrstreamhandler.cpp @@ -99,6 +99,7 @@ HDHRStreamHandler::HDHRStreamHandler(const QString &device) : _hdhr_lock(QMutex::Recursive) { + setObjectName("HDHRStreamHandler"); } /** \fn HDHRStreamHandler::run(void) @@ -106,14 +107,14 @@ HDHRStreamHandler::HDHRStreamHandler(const QString &device) : */ void HDHRStreamHandler::run(void) { - threadRegister("HDHRStreamHandler"); + RunProlog(); /* Create TS socket. */ if (!hdhomerun_device_stream_start(_hdhomerun_device)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Starting recording (set target failed). Aborting."); _error = true; - threadDeregister(); + RunEpilog(); return; } hdhomerun_device_stream_flush(_hdhomerun_device); @@ -179,7 +180,7 @@ void HDHRStreamHandler::run(void) LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "end"); SetRunning(false, false, false); - threadDeregister(); + RunEpilog(); } static QString filt_str(uint pid) diff --git a/mythtv/libs/libmythtv/hdhrstreamhandler.h b/mythtv/libs/libmythtv/hdhrstreamhandler.h index af75f0fbde7..db1343c51a6 100644 --- a/mythtv/libs/libmythtv/hdhrstreamhandler.h +++ b/mythtv/libs/libmythtv/hdhrstreamhandler.h @@ -83,7 +83,7 @@ class HDHRStreamHandler : public StreamHandler bool Open(void); void Close(void); - virtual void run(void); // QThread + virtual void run(void); // MThread virtual bool UpdateFilters(void); diff --git a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.cpp b/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.cpp index 590b3f28a44..57ba817b0dd 100644 --- a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.cpp +++ b/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.cpp @@ -28,17 +28,6 @@ static bool parse_extinf(const QString &data, QString &channum, QString &name); -/** \fn IPTVChannelFetcherThread::run(void) -* \brief Thunk that allows iptvfetcher Qthread to -* call IPTVChannelFetcher::RunScan(). -*/ -void IPTVChannelFetcherThread::run(void) -{ - threadRegister("IPTVChannelFetcher"); - iptvfetcher->RunScan(); - threadDeregister(); -} - IPTVChannelFetcher::IPTVChannelFetcher( uint cardid, const QString &inputname, uint sourceid, ScanMonitor *monitor) : @@ -46,19 +35,17 @@ IPTVChannelFetcher::IPTVChannelFetcher( _cardid(cardid), _inputname(inputname), _sourceid(sourceid), _chan_cnt(1), _thread_running(false), - _stop_now(false), _lock() + _stop_now(false), _thread(new MThread("IPTVChannelFetcher", this)), + _lock() { _inputname.detach(); } IPTVChannelFetcher::~IPTVChannelFetcher() { - do - { - Stop(); - usleep(5000); - } - while (_thread_running); + Stop(); + delete _thread; + _thread = NULL; } /** \fn IPTVChannelFetcher::Stop(void) @@ -68,16 +55,17 @@ void IPTVChannelFetcher::Stop(void) { _lock.lock(); - if (_thread_running) + while (_thread_running) { _stop_now = true; _lock.unlock(); - - _thread.wait(); - return; + _thread->wait(5); + _lock.lock(); } _lock.unlock(); + + _thread->wait(); } /** \fn IPTVChannelFetcher::Scan(void) @@ -92,8 +80,7 @@ bool IPTVChannelFetcher::Scan(void) _stop_now = false; - _thread.iptvfetcher = this; - _thread.start(QThread::NormalPriority); + _thread->start(); while (!_thread_running && !_stop_now) usleep(5000); @@ -103,7 +90,7 @@ bool IPTVChannelFetcher::Scan(void) return _thread_running; } -void IPTVChannelFetcher::RunScan(void) +void IPTVChannelFetcher::run(void) { _thread_running = true; @@ -113,6 +100,7 @@ void IPTVChannelFetcher::RunScan(void) if (_stop_now || url.isEmpty()) { _thread_running = false; + _stop_now = true; return; } @@ -130,6 +118,7 @@ void IPTVChannelFetcher::RunScan(void) if (_stop_now || playlist.isEmpty()) { _thread_running = false; + _stop_now = true; return; } @@ -193,6 +182,7 @@ void IPTVChannelFetcher::RunScan(void) } _thread_running = false; + _stop_now = true; } void IPTVChannelFetcher::SetNumChannelsParsed(uint val) diff --git a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.h b/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.h index da7a3800fbf..d5b7a9fad7d 100644 --- a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.h +++ b/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.h @@ -2,27 +2,19 @@ #define _IPTVCHANNELFETCHER_H_ // Qt headers +#include #include #include -#include // MythTV headers #include "iptvchannelinfo.h" +#include "mthread.h" class ScanMonitor; class IPTVChannelFetcher; -class IPTVChannelFetcherThread : public QThread +class IPTVChannelFetcher : public QRunnable { - public: - virtual void run(); - IPTVChannelFetcher *iptvfetcher; -}; - -class IPTVChannelFetcher -{ - friend class IPTVChannelFetcherThread; - public: IPTVChannelFetcher(uint cardid, const QString &inputname, uint sourceid, ScanMonitor *monitor = NULL); @@ -42,7 +34,7 @@ class IPTVChannelFetcher void SetMessage(const QString &status); protected: - void RunScan(void); + virtual void run(void); // QRunnable private: ScanMonitor *_scan_monitor; @@ -52,7 +44,7 @@ class IPTVChannelFetcher uint _chan_cnt; bool _thread_running; bool _stop_now; - IPTVChannelFetcherThread _thread; + MThread *_thread; QMutex _lock; }; diff --git a/mythtv/libs/libmythtv/iptvsignalmonitor.cpp b/mythtv/libs/libmythtv/iptvsignalmonitor.cpp index 3a81b571d39..04871d56096 100644 --- a/mythtv/libs/libmythtv/iptvsignalmonitor.cpp +++ b/mythtv/libs/libmythtv/iptvsignalmonitor.cpp @@ -17,9 +17,9 @@ void IPTVTableMonitorThread::run(void) { - threadRegister("IPTVTableMonitor"); + RunProlog(); m_parent->RunTableMonitor(); - threadDeregister(); + RunEpilog(); } /** \fn IPTVSignalMonitor::IPTVSignalMonitor(int,IPTVChannel*,uint64_t) @@ -115,7 +115,7 @@ void IPTVSignalMonitor::AddData( /** \fn IPTVSignalMonitor::UpdateValues(void) * \brief Fills in frontend stats and emits status Qt signals. * - * This is automatically called by MonitorLoop(), after Start() + * This is automatically called by run(), after Start() * has been used to start the signal monitoring thread. */ void IPTVSignalMonitor::UpdateValues(void) diff --git a/mythtv/libs/libmythtv/iptvsignalmonitor.h b/mythtv/libs/libmythtv/iptvsignalmonitor.h index 72dcc430a20..eae3d1db2a3 100644 --- a/mythtv/libs/libmythtv/iptvsignalmonitor.h +++ b/mythtv/libs/libmythtv/iptvsignalmonitor.h @@ -4,19 +4,17 @@ #define _IPTVSIGNALMONITOR_H_ #include "dtvsignalmonitor.h" - -#include -#include +#include "mthread.h" class IPTVChannel; class IPTVSignalMonitor; -class IPTVTableMonitorThread : public QThread +class IPTVTableMonitorThread : public MThread { - Q_OBJECT public: - IPTVTableMonitorThread(IPTVSignalMonitor *p) : m_parent(p) { start(); } - virtual ~IPTVTableMonitorThread() { wait(); } + IPTVTableMonitorThread(IPTVSignalMonitor *p) : + MThread("IPTVTableMonitor"), m_parent(p) { start(); } + virtual ~IPTVTableMonitorThread() { wait(); m_parent = NULL; } virtual void run(void); private: IPTVSignalMonitor *m_parent; @@ -24,8 +22,6 @@ class IPTVTableMonitorThread : public QThread class IPTVSignalMonitor : public DTVSignalMonitor, public TSDataListener { - Q_OBJECT - friend class IPTVTableMonitorThread; public: IPTVSignalMonitor(int db_cardnum, IPTVChannel *_channel, diff --git a/mythtv/libs/libmythtv/jobqueue.cpp b/mythtv/libs/libmythtv/jobqueue.cpp index e8977b8967b..e2f89c20989 100644 --- a/mythtv/libs/libmythtv/jobqueue.cpp +++ b/mythtv/libs/libmythtv/jobqueue.cpp @@ -23,6 +23,7 @@ using namespace std; #include "compat.h" #include "recordingprofile.h" #include "recordinginfo.h" +#include "mthread.h" #include "mythdb.h" #include "mythdirs.h" @@ -36,13 +37,6 @@ using namespace std; #define O_LARGEFILE 0 #endif -void QueueProcessorThread::run(void) -{ - threadRegister("QueueProcessor"); - m_parent->RunQueueProcessor(); - threadDeregister(); -} - #define LOC QString("JobQueue: ") JobQueue::JobQueue(bool master) : @@ -52,7 +46,7 @@ JobQueue::JobQueue(bool master) : m_pginfo(NULL), runningJobsLock(new QMutex(QMutex::Recursive)), isMaster(master), - queueThread(new QueueProcessorThread(this)), + queueThread(new MThread("JobQueue", this)), processQueue(false) { jobQueueCPU = gCoreContext->GetNumSetting("JobQueueCPU", 0); @@ -150,7 +144,7 @@ void JobQueue::customEvent(QEvent *e) } } -void JobQueue::RunQueueProcessor(void) +void JobQueue::run(void) { queueThreadCondLock.lock(); queueThreadCond.wakeAll(); diff --git a/mythtv/libs/libmythtv/jobqueue.h b/mythtv/libs/libmythtv/jobqueue.h index 3bcd91620d6..348abcbac10 100644 --- a/mythtv/libs/libmythtv/jobqueue.h +++ b/mythtv/libs/libmythtv/jobqueue.h @@ -1,19 +1,19 @@ #ifndef JOBQUEUE_H_ #define JOBQUEUE_H_ -#include #include #include #include +#include #include -#include #include #include #include #include "mythtvexp.h" +class MThread; class ProgramInfo; class RecordingInfo; @@ -113,18 +113,7 @@ typedef struct runningjobinfo { class JobQueue; -class QueueProcessorThread : public QThread -{ - Q_OBJECT - public: - QueueProcessorThread(JobQueue *parent) : m_parent(parent) {} - ~QueueProcessorThread() { wait(); m_parent = NULL; } - virtual void run(void); - private: - JobQueue *m_parent; -}; - -class MTV_PUBLIC JobQueue : public QObject +class MTV_PUBLIC JobQueue : public QObject, public QRunnable { Q_OBJECT @@ -215,7 +204,7 @@ class MTV_PUBLIC JobQueue : public QObject int jobID; } JobThreadStruct; - void RunQueueProcessor(void); + void run(void); // QRunnable void ProcessQueue(void); void ProcessJob(JobQueueEntry job); @@ -259,7 +248,7 @@ class MTV_PUBLIC JobQueue : public QObject bool isMaster; - QueueProcessorThread *queueThread; + MThread *queueThread; QWaitCondition queueThreadCond; QMutex queueThreadCondLock; bool processQueue; diff --git a/mythtv/libs/libmythtv/linuxfirewiredevice.cpp b/mythtv/libs/libmythtv/linuxfirewiredevice.cpp index 7ef8dd1a391..74c0d827158 100644 --- a/mythtv/libs/libmythtv/linuxfirewiredevice.cpp +++ b/mythtv/libs/libmythtv/linuxfirewiredevice.cpp @@ -43,13 +43,6 @@ using namespace std; typedef QMap handle_to_lfd_t; -void LinuxControllerThread::run(void) -{ - threadRegister("LinuxController"); - m_parent->RunPortHandler(); - threadDeregister(); -} - class LFDPriv { public: @@ -97,8 +90,8 @@ class LFDPriv bool is_bcast_node_open; bool is_streaming; - QDateTime stop_streaming_timer; - LinuxControllerThread *port_handler_thread; + QDateTime stop_streaming_timer; + MThread *port_handler_thread; avcinfo_list_t devices; @@ -289,7 +282,7 @@ bool LinuxFirewireDevice::OpenPort(void) m_priv->run_port_handler = true; LOG(VB_RECORD, LOG_INFO, LOC + "Starting port handler thread"); - m_priv->port_handler_thread = new LinuxControllerThread(this); + m_priv->port_handler_thread = new MThread("LinuxController", this); m_priv->port_handler_thread->start(); while (!m_priv->is_port_handler_running) @@ -593,7 +586,7 @@ bool LinuxFirewireDevice::CloseAVStream(void) return true; } -void LinuxFirewireDevice::RunPortHandler(void) +void LinuxFirewireDevice::run(void) { LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- start"); m_lock.lock(); diff --git a/mythtv/libs/libmythtv/linuxfirewiredevice.h b/mythtv/libs/libmythtv/linuxfirewiredevice.h index adb71aa83cd..ee1ca0fa602 100644 --- a/mythtv/libs/libmythtv/linuxfirewiredevice.h +++ b/mythtv/libs/libmythtv/linuxfirewiredevice.h @@ -7,27 +7,17 @@ #ifndef _LINUX_FIREWIRE_DEVICE_H_ #define _LINUX_FIREWIRE_DEVICE_H_ +#include + #include "firewiredevice.h" -#include +#include "mthread.h" class LFDPriv; class LinuxAVCInfo; class LinuxFirewireDevice; -class LinuxControllerThread : public QThread -{ - Q_OBJECT - public: - LinuxControllerThread(LinuxFirewireDevice *parent) : m_parent(parent) {} - virtual ~LinuxControllerThread() { wait(); m_parent = NULL; } - virtual void run(void); - private: - LinuxFirewireDevice *m_parent; -}; - -class LinuxFirewireDevice : public FirewireDevice +class LinuxFirewireDevice : public FirewireDevice, public QRunnable { - friend class LinuxControllerThread; friend int linux_firewire_device_tspacket_handler( unsigned char *tspacket, int len, uint dropped, void *callback_data); @@ -76,7 +66,7 @@ class LinuxFirewireDevice : public FirewireDevice bool StartStreaming(void); bool StopStreaming(void); - void RunPortHandler(void); + void run(void); // QRunnable void PrintDropped(uint dropped_packets); bool SetAVStreamBufferSize(uint size_in_bytes); diff --git a/mythtv/libs/libmythtv/mhi.cpp b/mythtv/libs/libmythtv/mhi.cpp index dd54b0608f0..f4777c7c9e3 100644 --- a/mythtv/libs/libmythtv/mhi.cpp +++ b/mythtv/libs/libmythtv/mhi.cpp @@ -49,13 +49,6 @@ class MHIImageData // Special value for the NetworkBootInfo version. Real values are a byte. #define NBI_VERSION_UNSET 257 -void MHEGEngineThread::run(void) -{ - threadRegister("MHEGEngine"); - m_parent->RunMHEGEngine(); - threadDeregister(); -} - MHIContext::MHIContext(InteractiveTV *parent) : m_parent(parent), m_dsmcc(NULL), m_keyProfile(0), @@ -224,12 +217,12 @@ void MHIContext::Restart(uint chanid, uint cardid, bool isLive) m_isLive = isLive; // Don't set the NBI version here. Restart is called // after the PMT is processed. - m_engineThread = new MHEGEngineThread(this); + m_engineThread = new MThread("MHEG", this); m_engineThread->start(); } } -void MHIContext::RunMHEGEngine(void) +void MHIContext::run(void) { QMutexLocker locker(&m_runLock); diff --git a/mythtv/libs/libmythtv/mhi.h b/mythtv/libs/libmythtv/mhi.h index 44ac1606537..0071c4cba50 100644 --- a/mythtv/libs/libmythtv/mhi.h +++ b/mythtv/libs/libmythtv/mhi.h @@ -11,11 +11,11 @@ using namespace std; // Qt headers -#include -#include #include +#include +#include +#include #include -#include // MythTV headers #include "../libmythfreemheg/freemheg.h" @@ -24,6 +24,7 @@ using namespace std; #include "mythcontext.h" #include "mythdbcon.h" #include "mythdeque.h" +#include "mthread.h" extern "C" { #include "libavcodec/avcodec.h" // to decode single MPEG I-frames @@ -35,23 +36,11 @@ class DSMCCPacket; class MHIImageData; class MHIContext; -class MHEGEngineThread : public QThread -{ - Q_OBJECT - public: - MHEGEngineThread(MHIContext *parent) : m_parent(parent) {} - virtual ~MHEGEngineThread() { wait(); m_parent = NULL; } - virtual void run(void); - private: - MHIContext *m_parent; -}; - /** \class MHIContext * \brief Contains various utility functions for interactive television. */ -class MHIContext : public MHContext +class MHIContext : public MHContext, public QRunnable { - friend class MHEGEngineThread; public: MHIContext(InteractiveTV *parent); virtual ~MHIContext(); @@ -149,8 +138,7 @@ class MHIContext : public MHContext int GetHeight(void) { return m_displayHeight; } protected: - static void *StartMHEGEngine(void *param); - void RunMHEGEngine(void); + void run(void); // QRunnable void ProcessDSMCCQueue(void); void NetworkBootRequested(void); void ClearDisplay(void); @@ -183,7 +171,7 @@ class MHIContext : public MHContext FT_Face m_face; bool m_face_loaded; - MHEGEngineThread *m_engineThread; + MThread *m_engineThread; int m_currentChannel; int m_currentStream; diff --git a/mythtv/libs/libmythtv/mythcommflagplayer.cpp b/mythtv/libs/libmythtv/mythcommflagplayer.cpp index 3917e496adc..4f104b41353 100644 --- a/mythtv/libs/libmythtv/mythcommflagplayer.cpp +++ b/mythtv/libs/libmythtv/mythcommflagplayer.cpp @@ -1,9 +1,10 @@ #include using namespace std; -#include +#include #include "mythcommflagplayer.h" +#include "mthreadpool.h" #include "mythlogging.h" class RebuildSaver : public QRunnable @@ -18,14 +19,12 @@ class RebuildSaver : public QRunnable virtual void run(void) { - threadRegister("RebuildSaver"); m_decoder->SavePositionMapDelta(m_first, m_last); QMutexLocker locker(&s_lock); s_cnt[m_decoder]--; if (!s_cnt[m_decoder]) s_wait.wakeAll(); - threadDeregister(); } static uint GetCount(DecoderBase *d) @@ -128,8 +127,9 @@ bool MythCommFlagPlayer::RebuildSeekTable( if (RebuildSaver::GetCount(decoder) < 1) { pmap_last = myFramesPlayed; - QThreadPool::globalInstance()->start( - new RebuildSaver(decoder, pmap_first, pmap_last)); + MThreadPool::globalInstance()->start( + new RebuildSaver(decoder, pmap_first, pmap_last), + "RebuildSaver"); pmap_first = pmap_last + 1; } @@ -190,8 +190,9 @@ bool MythCommFlagPlayer::RebuildSeekTable( SetPlaying(false); killdecoder = true; - QThreadPool::globalInstance()->start( - new RebuildSaver(decoder, pmap_first, myFramesPlayed)); + MThreadPool::globalInstance()->start( + new RebuildSaver(decoder, pmap_first, myFramesPlayed), + "RebuildSaver"); RebuildSaver::Wait(decoder); return true; diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp index 6de1684f3e1..814e5d798fb 100644 --- a/mythtv/libs/libmythtv/mythplayer.cpp +++ b/mythtv/libs/libmythtv/mythplayer.cpp @@ -24,11 +24,11 @@ using namespace std; // Qt headers #include -#include #include #include // MythTV headers +#include "mthread.h" #include "mythconfig.h" #include "mythdbcon.h" #include "dialogbox.h" @@ -88,14 +88,12 @@ static unsigned dbg_ident(const MythPlayer*); void DecoderThread::run(void) { - if (!m_mp) - return; - - threadRegister("Decoder"); - LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + QString("Decoder thread starting.")); - m_mp->DecoderLoop(m_start_paused); - LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + QString("Decoder thread exiting.")); - threadDeregister(); + RunProlog(); + LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + "Decoder thread starting."); + if (m_mp) + m_mp->DecoderLoop(m_start_paused); + LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + "Decoder thread exiting."); + RunEpilog(); } static const int toCaptionType(int type) @@ -550,7 +548,7 @@ void MythPlayer::ReinitOSD(void) if (videoOutput && !using_null_videoout) { osdLock.lock(); - if (QThread::currentThread() != (QThread*)playerThread) + if (!is_current_thread(playerThread)) { reinit_osd = true; osdLock.unlock(); @@ -746,7 +744,7 @@ void MythPlayer::SetScanType(FrameScanType scan) { QMutexLocker locker(&videofiltersLock); - if (QThread::currentThread() != (QThread*)playerThread) + if (!is_current_thread(playerThread)) { resetScan = scan; return; @@ -2773,7 +2771,7 @@ void MythPlayer::AudioEnd(void) bool MythPlayer::PauseDecoder(void) { decoderPauseLock.lock(); - if (QThread::currentThread() == (QThread*)decoderThread) + if (is_current_thread(decoderThread)) { decoderPaused = true; decoderThreadPause.wakeAll(); @@ -2797,7 +2795,7 @@ void MythPlayer::UnpauseDecoder(void) { decoderPauseLock.lock(); - if (QThread::currentThread() == (QThread*)decoderThread) + if (is_current_thread(decoderThread)) { decoderPaused = false; decoderThreadUnpause.wakeAll(); @@ -2851,18 +2849,19 @@ void MythPlayer::DecoderEnd(void) void MythPlayer::DecoderPauseCheck(void) { - if (QThread::currentThread() != (QThread*)decoderThread) - return; - if (pauseDecoder) - PauseDecoder(); - if (unpauseDecoder) - UnpauseDecoder(); + if (is_current_thread(decoderThread)) + { + if (pauseDecoder) + PauseDecoder(); + if (unpauseDecoder) + UnpauseDecoder(); + } } //// FIXME - move the eof ownership back into MythPlayer bool MythPlayer::GetEof(void) { - if (QThread::currentThread() == (QThread*)playerThread) + if (is_current_thread(playerThread)) return decoder ? decoder->GetEof() : true; decoder_change_lock.lock(); @@ -2873,7 +2872,7 @@ bool MythPlayer::GetEof(void) void MythPlayer::SetEof(bool eof) { - if (QThread::currentThread() == (QThread*)playerThread) + if (is_current_thread(playerThread)) { if (decoder) decoder->SetEof(eof); @@ -3037,7 +3036,7 @@ void MythPlayer::SetTranscoding(bool value) bool MythPlayer::AddPIPPlayer(MythPlayer *pip, PIPLocation loc, uint timeout) { - if (QThread::currentThread() != playerThread) + if (!is_current_thread(playerThread)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot add PiP from another thread"); return false; @@ -3062,7 +3061,7 @@ bool MythPlayer::AddPIPPlayer(MythPlayer *pip, PIPLocation loc, uint timeout) bool MythPlayer::RemovePIPPlayer(MythPlayer *pip, uint timeout) { - if (QThread::currentThread() != playerThread) + if (!is_current_thread(playerThread)) return false; if (!pip_players.contains(pip)) @@ -3076,7 +3075,7 @@ bool MythPlayer::RemovePIPPlayer(MythPlayer *pip, uint timeout) PIPLocation MythPlayer::GetNextPIPLocation(void) const { - if (QThread::currentThread() != playerThread) + if (!is_current_thread(playerThread)) return kPIP_END; if (pip_players.isEmpty()) diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h index 35c03e9de06..20fcad8eda4 100644 --- a/mythtv/libs/libmythtv/mythplayer.h +++ b/mythtv/libs/libmythtv/mythplayer.h @@ -80,13 +80,11 @@ enum kDisplayTeletextMenu = 0x200, }; -class DecoderThread : public QThread +class DecoderThread : public MThread { - Q_OBJECT - public: DecoderThread(MythPlayer *mp, bool start_paused) - : QThread(NULL), m_mp(mp), m_start_paused(start_paused) { } + : MThread("Decoder"), m_mp(mp), m_start_paused(start_paused) { } ~DecoderThread() { wait(); } protected: diff --git a/mythtv/libs/libmythtv/mythsystemevent.cpp b/mythtv/libs/libmythtv/mythsystemevent.cpp index cb3189d544d..6f0e824d146 100644 --- a/mythtv/libs/libmythtv/mythsystemevent.cpp +++ b/mythtv/libs/libmythtv/mythsystemevent.cpp @@ -2,9 +2,9 @@ #include #include #include -#include #include "mythcorecontext.h" +#include "mthreadpool.h" #include "mythsystem.h" #include "mythsystemevent.h" #include "programinfo.h" @@ -18,10 +18,10 @@ * \brief QRunnable class for running MythSystemEvent handler commands * * The SystemEventThread class runs a system event handler command in - * non-blocking mode. The commands are run in the QThreadPool::globalInstance, + * non-blocking mode. The commands are run in the MThreadPool::globalInstance, * but we release and reserve the thread inside ::run() so that long-running * commands to not block other short-running commands from executing if we - * hit QThreadPool::maxThreadCount(). + * hit MThreadPool::maxThreadCount(). */ class SystemEventThread : public QRunnable { @@ -40,35 +40,26 @@ class SystemEventThread : public QRunnable * * Overrides QRunnable::run() */ - void run() + void run(void) { - threadRegister("SystemEvent"); uint flags = kMSDontBlockInputDevs; m_event.detach(); m_command.detach(); - QThreadPool::globalInstance()->releaseThread(); - uint result = myth_system(m_command, flags); - QThreadPool::globalInstance()->reserveThread(); - if (result != GENERIC_EXIT_OK) LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Command '%1' returned %2") .arg(m_command).arg(result)); - if (m_event.isEmpty()) - { - threadDeregister(); + if (m_event.isEmpty()) return; - } RemoteSendMessage(QString("SYSTEM_EVENT_RESULT %1 SENDER %2 RESULT %3") .arg(m_event).arg(gCoreContext->GetHostName()) .arg(result)); - threadDeregister(); } private: @@ -300,7 +291,8 @@ void MythSystemEventHandler::customEvent(QEvent *e) SubstituteMatches(tokens, cmd); SystemEventThread *eventThread = new SystemEventThread(cmd); - QThreadPool::globalInstance()->start(eventThread); + MThreadPool::globalInstance()->startReserved( + eventThread, "SystemEvent"); } // Check for an EventCmd for this particular event @@ -311,7 +303,8 @@ void MythSystemEventHandler::customEvent(QEvent *e) SystemEventThread *eventThread = new SystemEventThread(cmd, tokens[1]); - QThreadPool::globalInstance()->start(eventThread); + MThreadPool::globalInstance()->startReserved( + eventThread, "SystemEvent"); } } } diff --git a/mythtv/libs/libmythtv/previewgenerator.cpp b/mythtv/libs/libmythtv/previewgenerator.cpp index cd10b0b6976..76f7b8bd80a 100644 --- a/mythtv/libs/libmythtv/previewgenerator.cpp +++ b/mythtv/libs/libmythtv/previewgenerator.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -68,7 +67,8 @@ PreviewGenerator::PreviewGenerator(const ProgramInfo *pginfo, const QString &_token, PreviewGenerator::Mode _mode) - : programInfo(*pginfo), mode(_mode), listener(NULL), + : MThread("PreviewGenerator"), + programInfo(*pginfo), mode(_mode), listener(NULL), pathname(pginfo->GetPathname()), timeInSeconds(true), captureTime(-1), outFileName(QString::null), outSize(0,0), token(_token), gotReply(false), pixmapOk(false) @@ -116,14 +116,16 @@ bool PreviewGenerator::RunReal(void) if (!is_local && !!(mode & kRemote)) { - LOG(VB_GENERAL, LOG_ERR, LOC + QString("Run() file not local: '%1'") - .arg(pathname)); + LOG(VB_GENERAL, LOG_ERR, LOC + + QString("RunReal() file not local: '%1'") + .arg(pathname)); } else if (!(mode & kLocal) && !(mode & kRemote)) { - LOG(VB_GENERAL, LOG_ERR, LOC + QString("Run() Preview of '%1' failed " - "because mode was invalid 0x%2") - .arg(pathname).arg((int)mode,0,16)); + LOG(VB_GENERAL, LOG_ERR, LOC + + QString("RunReal() Preview of '%1' failed " + "because mode was invalid 0x%2") + .arg(pathname).arg((int)mode,0,16)); } else if (is_local && !!(mode & kLocal) && LocalPreviewRun()) { @@ -323,12 +325,11 @@ bool PreviewGenerator::Run(void) void PreviewGenerator::run(void) { - threadRegister("PreviewGenerator"); - setPriority(QThread::LowPriority); + RunProlog(); Run(); - connect(this, SIGNAL(finished()), + connect(qthread(), SIGNAL(finished()), this, SLOT(deleteLater())); - threadDeregister(); + RunEpilog(); } bool PreviewGenerator::RemotePreviewRun(void) diff --git a/mythtv/libs/libmythtv/previewgenerator.h b/mythtv/libs/libmythtv/previewgenerator.h index 72a8c88d8e7..57579b5daa7 100644 --- a/mythtv/libs/libmythtv/previewgenerator.h +++ b/mythtv/libs/libmythtv/previewgenerator.h @@ -5,14 +5,14 @@ #include #include #include -#include #include #include #include #include -#include "mythtvexp.h" #include "programinfo.h" +#include "mythtvexp.h" +#include "mthread.h" #include "util.h" class PreviewGenerator; @@ -23,7 +23,7 @@ class QEvent; typedef QMap FileTimeStampMap; -class MTV_PUBLIC PreviewGenerator : public QThread +class MTV_PUBLIC PreviewGenerator : public QObject, public MThread { friend int preview_helper(uint chanid, QDateTime starttime, @@ -62,7 +62,7 @@ class MTV_PUBLIC PreviewGenerator : public QThread QString GetToken(void) const { return token; } - void run(void); // QThread + void run(void); // MThread bool Run(void); void AttachSignals(QObject*); diff --git a/mythtv/libs/libmythtv/previewgeneratorqueue.cpp b/mythtv/libs/libmythtv/previewgeneratorqueue.cpp index 99460dfdbb2..3dc0d9da557 100644 --- a/mythtv/libs/libmythtv/previewgeneratorqueue.cpp +++ b/mythtv/libs/libmythtv/previewgeneratorqueue.cpp @@ -1,14 +1,14 @@ #include #include -#include #include "previewgeneratorqueue.h" #include "previewgenerator.h" #include "mythcorecontext.h" #include "mythcontext.h" +#include "mythlogging.h" #include "remoteutil.h" #include "mythdirs.h" -#include "mythlogging.h" +#include "mthread.h" #define LOC QString("PreviewQueue: ") @@ -31,6 +31,7 @@ void PreviewGeneratorQueue::TeardownPreviewGeneratorQueue() PreviewGeneratorQueue::PreviewGeneratorQueue( PreviewGenerator::Mode mode, uint maxAttempts, uint minBlockSeconds) : + MThread("PreviewGeneratorQueue"), m_mode(mode), m_running(0), m_maxThreads(2), m_maxAttempts(maxAttempts), m_minBlockSeconds(minBlockSeconds) @@ -41,7 +42,7 @@ PreviewGeneratorQueue::PreviewGeneratorQueue( m_maxThreads = (idealThreads >= 1) ? idealThreads * 2 : 2; } - moveToThread(this); + moveToThread(qthread()); start(); } @@ -59,13 +60,6 @@ PreviewGeneratorQueue::~PreviewGeneratorQueue() wait(); } -void PreviewGeneratorQueue::run(void) -{ - threadRegister("PreviewGeneratorQueue"); - exec(); - threadDeregister(); -} - void PreviewGeneratorQueue::GetPreviewImage( const ProgramInfo &pginfo, const QSize &outputsize, diff --git a/mythtv/libs/libmythtv/previewgeneratorqueue.h b/mythtv/libs/libmythtv/previewgeneratorqueue.h index 6744dee1a09..3db1ba6903f 100644 --- a/mythtv/libs/libmythtv/previewgeneratorqueue.h +++ b/mythtv/libs/libmythtv/previewgeneratorqueue.h @@ -4,14 +4,13 @@ #include #include -#include #include #include #include -#include "mythtvexp.h" #include "previewgenerator.h" #include "mythtvexp.h" +#include "mthread.h" class ProgramInfo; class QSize; @@ -31,7 +30,7 @@ class PreviewGenState }; typedef QMap PreviewMap; -class MTV_PUBLIC PreviewGeneratorQueue : public QThread +class MTV_PUBLIC PreviewGeneratorQueue : public QObject, public MThread { Q_OBJECT @@ -56,7 +55,6 @@ class MTV_PUBLIC PreviewGeneratorQueue : public QThread PreviewGeneratorQueue(PreviewGenerator::Mode mode, uint maxAttempts, uint minBlockSeconds); ~PreviewGeneratorQueue(); - void run(void); QString GeneratePreviewImage(ProgramInfo &pginfo, const QSize&, const QString &outputfile, diff --git a/mythtv/libs/libmythtv/privatedecoder_crystalhd.cpp b/mythtv/libs/libmythtv/privatedecoder_crystalhd.cpp index 9c91c73fe68..f73dbc357af 100644 --- a/mythtv/libs/libmythtv/privatedecoder_crystalhd.cpp +++ b/mythtv/libs/libmythtv/privatedecoder_crystalhd.cpp @@ -8,14 +8,12 @@ void FetcherThread::run(void) { - if (!m_dec) - return; - - threadRegister("Fetcher"); + RunProlog() LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Starting Fetcher thread.")); - m_dec->FetchFrames(); + if (m_dec) + m_dec->FetchFrames(); LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Stopping Fetcher thread.")); - threadDeregister(); + RunEpilog(); } PixelFormat bcmpixfmt_to_pixfmt(BC_OUTPUT_FORMAT fmt); diff --git a/mythtv/libs/libmythtv/privatedecoder_crystalhd.h b/mythtv/libs/libmythtv/privatedecoder_crystalhd.h index f85eebe0c1b..969124d53fe 100644 --- a/mythtv/libs/libmythtv/privatedecoder_crystalhd.h +++ b/mythtv/libs/libmythtv/privatedecoder_crystalhd.h @@ -1,7 +1,7 @@ #ifndef PRIVATEDECODER_CRYSTALHD_H #define PRIVATEDECODER_CRYSTALHD_H -#include +#include "mthread.h" #if defined(WIN32) typedef void *HANDLE; @@ -18,13 +18,11 @@ typedef void *HANDLE; #include "privatedecoder.h" class PrivateDecoderCrystalHD; -class FetcherThread : public QThread +class FetcherThread : public MThread { - Q_OBJECT - public: FetcherThread(PrivateDecoderCrystalHD *dec) - : QThread(NULL), m_dec(dec) { } + : MThread("Fetcher"), m_dec(dec) { } protected: virtual void run(void); diff --git a/mythtv/libs/libmythtv/recorderbase.h b/mythtv/libs/libmythtv/recorderbase.h index 7e2646d302e..ea2cd4c6816 100644 --- a/mythtv/libs/libmythtv/recorderbase.h +++ b/mythtv/libs/libmythtv/recorderbase.h @@ -5,8 +5,8 @@ #include #include +#include #include -#include #include #include @@ -24,17 +24,6 @@ class ProgramInfo; class RingBuffer; class TVRec; -class MTV_PUBLIC RecorderThread : public QThread -{ - Q_OBJECT - public: - RecorderThread(RecorderBase *p) : m_parent(p) {} - virtual ~RecorderThread() { wait(); m_parent = NULL; } - virtual inline void run(void); - private: - RecorderBase *m_parent; -}; - /** \class RecorderBase * \brief This is the abstract base class for supporting * recorder hardware. @@ -47,7 +36,7 @@ class MTV_PUBLIC RecorderThread : public QThread * * \sa TVRec */ -class MTV_PUBLIC RecorderBase +class MTV_PUBLIC RecorderBase : public QRunnable { friend class Transcode; // for access to SetIntOption(), SetStrOption() @@ -136,6 +125,7 @@ class MTV_PUBLIC RecorderBase * \sa StopRecording() */ virtual void StartRecording(void) = 0; + virtual void run(void) { StartRecording(); } // QRunnable /** \brief Reset the recorder to the startup state. * @@ -304,11 +294,6 @@ class MTV_PUBLIC RecorderBase MythTimer positionMapTimer; }; -inline void RecorderThread::run(void) -{ - m_parent->StartRecording(); -} - #endif /* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/ringbuffer.cpp b/mythtv/libs/libmythtv/ringbuffer.cpp index 30c7f729956..a9dfa291431 100644 --- a/mythtv/libs/libmythtv/ringbuffer.cpp +++ b/mythtv/libs/libmythtv/ringbuffer.cpp @@ -172,6 +172,7 @@ RingBuffer *RingBuffer::Create( } RingBuffer::RingBuffer(RingBufferType rbtype) : + MThread("RingBuffer"), type(rbtype), readpos(0), writepos(0), internalreadpos(0), ignorereadpos(-1), @@ -504,7 +505,7 @@ void RingBuffer::Start(void) StartReads(); - QThread::start(); + MThread::start(); while (readaheadrunning && !reallyrunning) generalWait.wait(&rwlock); @@ -524,7 +525,7 @@ void RingBuffer::KillReadAheadThread(void) StopReads(); generalWait.wakeAll(); rwlock.unlock(); - QThread::wait(5000); + MThread::wait(5000); } } @@ -699,7 +700,8 @@ void RingBuffer::CreateReadAheadBuffer(void) void RingBuffer::run(void) { - threadRegister("RingBuffer"); + RunProlog(); + // These variables are used to adjust the read block size struct timeval lastread, now; int readtimeavg = 300; @@ -958,7 +960,8 @@ void RingBuffer::run(void) rbwlock.unlock(); rbrlock.unlock(); rwlock.unlock(); - threadDeregister(); + + RunEpilog(); } long long RingBuffer::SetAdjustFilesize(void) diff --git a/mythtv/libs/libmythtv/ringbuffer.h b/mythtv/libs/libmythtv/ringbuffer.h index 2b0cd9272ee..2ada4992479 100644 --- a/mythtv/libs/libmythtv/ringbuffer.h +++ b/mythtv/libs/libmythtv/ringbuffer.h @@ -6,11 +6,11 @@ #include #include #include -#include #include #include #include "mythconfig.h" +#include "mthread.h" extern "C" { #include "libavcodec/avcodec.h" @@ -40,7 +40,7 @@ enum RingBufferType kRingBuffer_HTTP, }; -class MTV_PUBLIC RingBuffer : protected QThread +class MTV_PUBLIC RingBuffer : protected MThread { public: static RingBuffer *Create(const QString &lfilename, bool write, @@ -153,7 +153,7 @@ class MTV_PUBLIC RingBuffer : protected QThread protected: RingBuffer(RingBufferType rbtype); - void run(void); // QThread + void run(void); // MThread void CreateReadAheadBuffer(void); void CalcReadAheadThresh(void); bool PauseAndWait(void); diff --git a/mythtv/libs/libmythtv/signalmonitor.cpp b/mythtv/libs/libmythtv/signalmonitor.cpp index ea2b2d459c6..c2d69872e35 100644 --- a/mythtv/libs/libmythtv/signalmonitor.cpp +++ b/mythtv/libs/libmythtv/signalmonitor.cpp @@ -174,7 +174,8 @@ SignalMonitor *SignalMonitor::Init(QString cardtype, int db_cardnum, */ SignalMonitor::SignalMonitor(int _capturecardnum, ChannelBase *_channel, uint64_t wait_for_mask) - : channel(_channel), + : MThread("SignalMonitor"), + channel(_channel), capturecardnum(_capturecardnum), flags(wait_for_mask), update_rate(25), minimum_update_rate(5), update_done(false), notify_frontend(true), @@ -282,9 +283,9 @@ QStringList SignalMonitor::GetStatusList(void) const } /// \brief Basic signal monitoring loop -void SignalMonitor::MonitorLoop(void) +void SignalMonitor::run(void) { - threadRegister("SignalMonitor"); + RunProlog(); QMutexLocker locker(&startStopLock); running = true; @@ -322,7 +323,7 @@ void SignalMonitor::MonitorLoop(void) running = false; startStopWait.wakeAll(); - threadDeregister(); + RunEpilog(); } void SignalMonitor::AddListener(SignalMonitorListener *listener) diff --git a/mythtv/libs/libmythtv/signalmonitor.h b/mythtv/libs/libmythtv/signalmonitor.h index 4b519c2ba9e..c876c65c01a 100644 --- a/mythtv/libs/libmythtv/signalmonitor.h +++ b/mythtv/libs/libmythtv/signalmonitor.h @@ -11,15 +11,15 @@ using namespace std; // Qt headers #include -#include #include // MythTV headers -#include "signalmonitorvalue.h" #include "signalmonitorlistener.h" +#include "signalmonitorvalue.h" #include "channelbase.h" -#include "cardutil.h" #include "mythtimer.h" +#include "cardutil.h" +#include "mthread.h" #define DBG_SM(FUNC, MSG) LOG(VB_CHANNEL, LOG_DEBUG, \ QString("SM(%1)::%2: %3") .arg(channel->GetDevice()).arg(FUNC).arg( #include -#include #include #include #include "DeviceReadBuffer.h" // for ReaderPausedCB #include "mpegstreamdata.h" // for PIDPriority +#include "mthread.h" #include "util.h" //#define DEBUG_PID_FILTERS @@ -47,7 +47,7 @@ typedef QMap PIDInfoMap; // locking order // _pid_lock -> _listener_lock -> _start_stop_lock -class StreamHandler : protected QThread, public DeviceReaderCB +class StreamHandler : protected MThread, public DeviceReaderCB { public: virtual void AddListener(MPEGStreamData *data, diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp index ce94b157a87..4b06ac5f74b 100644 --- a/mythtv/libs/libmythtv/tv_play.cpp +++ b/mythtv/libs/libmythtv/tv_play.cpp @@ -9089,6 +9089,7 @@ void *TV::load_dd_map_thunk(void *param) load_dd_map *x = (load_dd_map*) param; threadRegister("LoadDDMap"); x->tv->RunLoadDDMap(x->sourceid); + GetMythDB()->GetDBManager()->CloseDatabases(); threadDeregister(); delete x; return NULL; @@ -9099,6 +9100,7 @@ void *TV::load_dd_map_post_thunk(void *param) uint *sourceid = (uint*) param; threadRegister("LoadDDMapPost"); SourceUtil::UpdateChannelsFromListings(*sourceid); + GetMythDB()->GetDBManager()->CloseDatabases(); threadDeregister(); delete sourceid; return NULL; diff --git a/mythtv/libs/libmythtv/tv_play.h b/mythtv/libs/libmythtv/tv_play.h index af91a65c91d..d25e2ad1d25 100644 --- a/mythtv/libs/libmythtv/tv_play.h +++ b/mythtv/libs/libmythtv/tv_play.h @@ -22,13 +22,11 @@ using namespace std; #include #include #include -#include #include #include #include #include #include -#include // MythTV #include "mythdeque.h" diff --git a/mythtv/libs/libmythtv/tv_rec.cpp b/mythtv/libs/libmythtv/tv_rec.cpp index f0daa86af2b..032aab4ae18 100644 --- a/mythtv/libs/libmythtv/tv_rec.cpp +++ b/mythtv/libs/libmythtv/tv_rec.cpp @@ -83,7 +83,7 @@ TVRec::TVRec(int capturecardnum) : recorder(NULL), channel(NULL), signalMonitor(NULL), scanner(NULL), // Various threads - eventThread(new TVRecEventThread(this)), + eventThread(new MThread("TVRecEvent", this)), recorderThread(NULL), // Configuration variables from database transcodeFirst(false), @@ -1102,16 +1102,6 @@ V4LChannel *TVRec::GetV4LChannel(void) #endif // USING_V4L2 } -/** \fn TVRecEventThread::run(void) - * \brief Thunk that allows event thread to call RunTV(). - */ -void TVRecEventThread::run(void) -{ - threadRegister("TVRecEvent"); - m_parent->RunTV(); - threadDeregister(); -} - static bool get_use_eit(uint cardid) { MSqlQuery query(MSqlQuery::InitCon()); @@ -1178,10 +1168,8 @@ static int no_capturecards(uint cardid) return -1; } -/** \fn TVRec::RunTV(void) - * \brief Event handling method, contains event loop. - */ -void TVRec::RunTV(void) +/// \brief Event handling method, contains event loop. +void TVRec::run(void) { QMutexLocker lock(&stateChangeLock); SetFlags(kFlagRunMainLoop); @@ -4050,7 +4038,7 @@ void TVRec::TuningNewRecorder(MPEGStreamData *streamData) } #endif - recorderThread = new RecorderThread(recorder); + recorderThread = new MThread("RecThread", recorder); recorderThread->start(); // Wait for recorder to start. diff --git a/mythtv/libs/libmythtv/tv_rec.h b/mythtv/libs/libmythtv/tv_rec.h index 77f06bddf6d..e867271b52a 100644 --- a/mythtv/libs/libmythtv/tv_rec.h +++ b/mythtv/libs/libmythtv/tv_rec.h @@ -5,11 +5,12 @@ #include #include #include +#include #include #include -#include // MythTV headers +#include "mthread.h" #include "inputinfo.h" #include "inputgroupmap.h" #include "mythdeque.h" @@ -28,7 +29,6 @@ class EITScanner; class RecordingProfile; class LiveTVChain; -class RecorderThread; class RecorderBase; class DTVRecorder; class DVBRecorder; @@ -134,22 +134,9 @@ class PendingInfo }; typedef QMap PendingMap; -class TVRec; -class TVRecEventThread : public QThread -{ - Q_OBJECT - public: - TVRecEventThread(TVRec *p) : m_parent(p) {} - virtual ~TVRecEventThread() { wait(); m_parent = NULL; } - virtual void run(void); - private: - TVRec *m_parent; -}; - -class MTV_PUBLIC TVRec : public SignalMonitorListener +class MTV_PUBLIC TVRec : public SignalMonitorListener, public QRunnable { friend class TuningRequest; - friend class TVRecEventThread; friend class TVRecRecordThread; public: @@ -251,7 +238,7 @@ class MTV_PUBLIC TVRec : public SignalMonitorListener virtual void StatusSignalStrength(const SignalMonitorValue&) { } protected: - void RunTV(void); + virtual void run(void); // QRunnable bool WaitForEventThreadSleep(bool wake = true, ulong time = ULONG_MAX); private: @@ -331,10 +318,10 @@ class MTV_PUBLIC TVRec : public SignalMonitorListener EITScanner *scanner; // Various threads - /// Event processing thread, runs RunTV(). - TVRecEventThread *eventThread; - /// Recorder thread, runs RecorderBase::StartRecording() - RecorderThread *recorderThread; + /// Event processing thread, runs TVRec::run(). + MThread *eventThread; + /// Recorder thread, runs RecorderBase::run(). + MThread *recorderThread; // Configuration variables from database bool transcodeFirst; diff --git a/mythtv/libs/libmythtv/tvbrowsehelper.cpp b/mythtv/libs/libmythtv/tvbrowsehelper.cpp index fb07c9bb379..a76547c42c4 100644 --- a/mythtv/libs/libmythtv/tvbrowsehelper.cpp +++ b/mythtv/libs/libmythtv/tvbrowsehelper.cpp @@ -37,6 +37,7 @@ TVBrowseHelper::TVBrowseHelper( bool browse_all_tuners, bool use_channel_groups, QString db_channel_ordering) : + MThread("TVBrowseHelper"), m_tv(tv), db_time_format(time_format), db_short_date_format(short_date_format), @@ -417,7 +418,7 @@ inline static QString toString(const InfoMap &infoMap, const QString sep="\n") void TVBrowseHelper::run() { - threadRegister("TVBrowseHelper"); + RunProlog(); QMutexLocker locker(&m_lock); while (true) { @@ -587,5 +588,5 @@ void TVBrowseHelper::run() m_tv, new UpdateBrowseInfoEvent(infoMap)); } } - threadDeregister(); + RunEpilog(); } diff --git a/mythtv/libs/libmythtv/tvbrowsehelper.h b/mythtv/libs/libmythtv/tvbrowsehelper.h index 9e2b561d311..9b14501bc1e 100644 --- a/mythtv/libs/libmythtv/tvbrowsehelper.h +++ b/mythtv/libs/libmythtv/tvbrowsehelper.h @@ -5,12 +5,12 @@ #include #include -#include #include #include #include "dbchannelinfo.h" // for DBChanList #include "programtypes.h" // for InfoMap +#include "mthread.h" #include "tv.h" // for BrowseDirection class PlayerContext; @@ -61,7 +61,7 @@ class BrowseInfo }; -class TVBrowseHelper : public QThread +class TVBrowseHelper : public MThread { public: TVBrowseHelper(TV *tv, @@ -78,12 +78,6 @@ class TVBrowseHelper : public QThread Wait(); } - virtual void deleteLater() - { - Stop(); - QThread::deleteLater(); - } - void Stop() { QMutexLocker locker(&m_lock); @@ -92,7 +86,7 @@ class TVBrowseHelper : public QThread m_wait.wakeAll(); } - void Wait() { QThread::wait(); } + void Wait() { MThread::wait(); } bool BrowseStart(PlayerContext *ctx, bool skip_browse = false); void BrowseEnd(PlayerContext *ctx, bool change_channel); diff --git a/mythtv/libs/libmythtv/v4lrecorder.h b/mythtv/libs/libmythtv/v4lrecorder.h index eff84b5047d..1eb6c06bdc5 100644 --- a/mythtv/libs/libmythtv/v4lrecorder.h +++ b/mythtv/libs/libmythtv/v4lrecorder.h @@ -2,11 +2,10 @@ #ifndef _V4L_RECORDER_H_ #define _V4L_RECORDER_H_ -#include - #include "dtvrecorder.h" #include "cc608decoder.h" #include "vbitext/vt.h" +#include "mthread.h" class VBI608Extractor; class VBIThread; @@ -57,11 +56,14 @@ class MPUBLIC V4LRecorder : public DTVRecorder int vbi_fd; }; -class VBIThread : public QThread +class VBIThread : public MThread { public: - VBIThread(V4LRecorder *_parent) : parent(_parent) - { start(); } + VBIThread(V4LRecorder *_parent) : + MThread("VBIThread"), parent(_parent) + { + start(); + } virtual ~VBIThread() { @@ -72,9 +74,12 @@ class VBIThread : public QThread } } - virtual void run(void) { parent->RunVBIDevice(); } - - virtual void deleteLater(void) { parent->StopRecording(); } + virtual void run(void) + { + RunProlog(); + parent->RunVBIDevice(); + RunEpilog(); + } private: V4LRecorder *parent; diff --git a/mythtv/libs/libmythtv/videosource.h b/mythtv/libs/libmythtv/videosource.h index bdd26575367..32c799f2255 100644 --- a/mythtv/libs/libmythtv/videosource.h +++ b/mythtv/libs/libmythtv/videosource.h @@ -4,8 +4,7 @@ #include using namespace std; -#include - +#include "mthread.h" #include "settings.h" #include "datadirect.h" diff --git a/mythtv/libs/libmythui/AppleRemote.cpp b/mythtv/libs/libmythui/AppleRemote.cpp index 97ef7826a32..b8f03df449b 100644 --- a/mythtv/libs/libmythui/AppleRemote.cpp +++ b/mythtv/libs/libmythui/AppleRemote.cpp @@ -98,15 +98,16 @@ void AppleRemote::stopListening() void AppleRemote::run() { - threadRegister("AppleRemote"); + RunProlog(); CFRunLoopRun(); exec(); // prevent QThread exiting, by entering its run loop CFRunLoopStop(CFRunLoopGetCurrent()); - threadDeregister(); + RunEpilog(); } // protected -AppleRemote::AppleRemote() : openInExclusiveMode(true), +AppleRemote::AppleRemote() : MThread("AppleRemote"), + openInExclusiveMode(true), hidDeviceInterface(0), queue(0), remoteId(0), diff --git a/mythtv/libs/libmythui/AppleRemote.h b/mythtv/libs/libmythui/AppleRemote.h index 23b43a35199..64f5a7bd819 100644 --- a/mythtv/libs/libmythui/AppleRemote.h +++ b/mythtv/libs/libmythui/AppleRemote.h @@ -1,10 +1,13 @@ #ifndef APPLEREMOTE #define APPLEREMOTE +// C++ headers #include #include #include -#include + +// MythTV headers +#include "mthread.h" #include #include @@ -12,7 +15,7 @@ #include #include -class AppleRemote : public QThread +class AppleRemote : public MThread { public: enum Event diff --git a/mythtv/libs/libmythui/jsmenu.cpp b/mythtv/libs/libmythui/jsmenu.cpp index 2d5281220ae..67b00d6f1a1 100644 --- a/mythtv/libs/libmythui/jsmenu.cpp +++ b/mythtv/libs/libmythui/jsmenu.cpp @@ -51,7 +51,7 @@ #define LOC QString("JoystickMenuThread: ") JoystickMenuThread::JoystickMenuThread(QObject *main_window) - : QThread(), + : MThread("JoystickMenu"), m_mainWindow(main_window), m_devicename(""), m_fd(-1), m_buttonCount(0), m_axesCount(0), m_buttons(NULL), @@ -196,13 +196,14 @@ int JoystickMenuThread::ReadConfig(QString config_file) */ void JoystickMenuThread::run(void) { + RunProlog(); + int rc; fd_set readfds; struct js_event js; struct timeval timeout; - threadRegister("JoystickMenu"); while (!m_bStop) { @@ -286,7 +287,7 @@ void JoystickMenuThread::run(void) } - threadDeregister(); + RunEpilog(); } /** diff --git a/mythtv/libs/libmythui/jsmenu.h b/mythtv/libs/libmythui/jsmenu.h index c1138a89b9b..6c046939982 100644 --- a/mythtv/libs/libmythui/jsmenu.h +++ b/mythtv/libs/libmythui/jsmenu.h @@ -11,7 +11,9 @@ // QT headers #include -#include + +// MythTV headers +#include "mthread.h" typedef struct { @@ -76,7 +78,7 @@ class JoystickMap * * \ingroup MythUI_Input */ -class JoystickMenuThread : public QThread +class JoystickMenuThread : public MThread { public: JoystickMenuThread(QObject *main_window); diff --git a/mythtv/libs/libmythui/lirc.cpp b/mythtv/libs/libmythui/lirc.cpp index b4b2bc6665b..f575fd3cdb5 100644 --- a/mythtv/libs/libmythui/lirc.cpp +++ b/mythtv/libs/libmythui/lirc.cpp @@ -73,7 +73,7 @@ LIRC::LIRC(QObject *main_window, const QString &lircd_device, const QString &our_program, const QString &config_file) - : QThread(), + : MThread("LIRC"), lock(QMutex::Recursive), m_mainWindow(main_window), lircdDevice(lircd_device), @@ -99,7 +99,7 @@ LIRC::~LIRC() void LIRC::deleteLater(void) { TeardownAll(); - QThread::deleteLater(); + QObject::deleteLater(); } void LIRC::TeardownAll(void) @@ -321,7 +321,7 @@ void LIRC::start(void) } doRun = true; - QThread::start(); + MThread::start(); } bool LIRC::IsDoRunSet(void) const @@ -397,7 +397,7 @@ void LIRC::Process(const QByteArray &data) void LIRC::run(void) { - threadRegister("LIRC"); + RunProlog(); #if 0 LOG(VB_GENERAL, LOG_DEBUG, LOC + "run -- start"); #endif @@ -461,7 +461,7 @@ void LIRC::run(void) #if 0 LOG(VB_GENERAL, LOG_DEBUG, LOC + "run -- end"); #endif - threadDeregister(); + RunEpilog(); } QList LIRC::GetCodes(void) diff --git a/mythtv/libs/libmythui/lirc.h b/mythtv/libs/libmythui/lirc.h index 5f78cc0de1b..a75d1a4ec20 100644 --- a/mythtv/libs/libmythui/lirc.h +++ b/mythtv/libs/libmythui/lirc.h @@ -4,12 +4,13 @@ #include #include #include -#include #include #include #include // for uint +#include "mthread.h" + class LIRCPriv; /** @@ -20,7 +21,7 @@ class LIRCPriv; * * \ingroup MythUI_Input */ -class LIRC : public QThread +class LIRC : public QObject, public MThread { Q_OBJECT public: diff --git a/mythtv/libs/libmythui/mythrender_vdpau.cpp b/mythtv/libs/libmythui/mythrender_vdpau.cpp index 3c83eeeb764..483f997e3f4 100644 --- a/mythtv/libs/libmythui/mythrender_vdpau.cpp +++ b/mythtv/libs/libmythui/mythrender_vdpau.cpp @@ -1,8 +1,8 @@ #include "math.h" #include -#include +#include "mthread.h" #include "mythlogging.h" #include "mythmainwindow.h" #include "mythrender_vdpau.h" diff --git a/mythtv/libs/libmythui/mythscreentype.cpp b/mythtv/libs/libmythui/mythscreentype.cpp index 850837788d4..54f02741cc6 100644 --- a/mythtv/libs/libmythui/mythscreentype.cpp +++ b/mythtv/libs/libmythui/mythscreentype.cpp @@ -4,9 +4,9 @@ #include #include #include -#include #include "mythobservable.h" +#include "mthreadpool.h" #include "mythscreenstack.h" #include "mythmainwindow.h" @@ -27,11 +27,7 @@ class ScreenLoadTask : public QRunnable void run() { if (m_parent) - { - threadRegister("ScreenLoad"); m_parent->LoadInForeground(); - threadDeregister(); - } } MythScreenType *m_parent; @@ -278,7 +274,7 @@ void MythScreenType::LoadInBackground(QString message) OpenBusyPopup(message); ScreenLoadTask *loadTask = new ScreenLoadTask(this); - QThreadPool::globalInstance()->start(loadTask); + MThreadPool::globalInstance()->start(loadTask, "ScreenLoad"); } void MythScreenType::LoadInForeground(void) diff --git a/mythtv/libs/libmythui/mythuihelper.cpp b/mythtv/libs/libmythui/mythuihelper.cpp index dc82cab7904..c870d17bb26 100644 --- a/mythtv/libs/libmythui/mythuihelper.cpp +++ b/mythtv/libs/libmythui/mythuihelper.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -32,6 +31,7 @@ #include "mythimage.h" #include "remotefile.h" #include "mythcorecontext.h" +#include "mthreadpool.h" #define LOC QString("MythUIHelper: ") @@ -130,7 +130,7 @@ class MythUIHelperPrivate DisplayRes *display_res; bool screenSetup; - QThreadPool *m_imageThreadPool; + MThreadPool *m_imageThreadPool; MythUIMenuCallbacks callbacks; @@ -154,8 +154,8 @@ MythUIHelperPrivate::MythUIHelperPrivate(MythUIHelper *p) m_cacheSizeLock(new QMutex(QMutex::Recursive)), m_screenxbase(0), m_screenybase(0), m_screenwidth(0), m_screenheight(0), screensaver(NULL), screensaverEnabled(false), display_res(NULL), - screenSetup(false), m_imageThreadPool(new QThreadPool()), parent(p), - m_fontStretch(100) + screenSetup(false), m_imageThreadPool(new MThreadPool("MythUIHelper")), + parent(p), m_fontStretch(100) { } @@ -1691,7 +1691,7 @@ QString MythUIHelper::GetCurrentLocation(bool fullPath, bool mainStackOnly) return result; } -QThreadPool *MythUIHelper::GetImageThreadPool(void) +MThreadPool *MythUIHelper::GetImageThreadPool(void) { return d->m_imageThreadPool; } diff --git a/mythtv/libs/libmythui/mythuihelper.h b/mythtv/libs/libmythui/mythuihelper.h index b830f2d7631..6a310c0c02e 100644 --- a/mythtv/libs/libmythui/mythuihelper.h +++ b/mythtv/libs/libmythui/mythuihelper.h @@ -5,8 +5,8 @@ #include #include #include -#include +#include "mthreadpool.h" #include "mythuiexp.h" #include "themeinfo.h" @@ -129,7 +129,7 @@ class MUI_PUBLIC MythUIHelper QString RemoveCurrentLocation(void); QString GetCurrentLocation(bool fullPath = false, bool mainStackOnly = true); - QThreadPool *GetImageThreadPool(void); + MThreadPool *GetImageThreadPool(void); double GetPixelAspectRatio(void) const; QSize GetBaseSize(void) const; diff --git a/mythtv/libs/libmythupnp/ssdp.cpp b/mythtv/libs/libmythupnp/ssdp.cpp index d966f5e5781..104e945784c 100644 --- a/mythtv/libs/libmythupnp/ssdp.cpp +++ b/mythtv/libs/libmythupnp/ssdp.cpp @@ -65,6 +65,7 @@ SSDP* SSDP::Instance() ///////////////////////////////////////////////////////////////////////////// SSDP::SSDP() : + MThread ("SSDP" ), m_procReqLineExp ("[ \r\n][ \r\n]*"), m_nPort ( SSDP_PORT ), m_nSearchPort ( SSDP_SEARCHPORT ), @@ -255,10 +256,11 @@ void SSDP::PerformSearch(const QString &sST, uint timeout_secs) void SSDP::run() { + RunProlog(); + fd_set read_set; struct timeval timeout; - threadRegister("SSDP"); LOG(VB_UPNP, LOG_INFO, "SSDP::Run - SSDP Thread Started." ); // ---------------------------------------------------------------------- @@ -308,7 +310,8 @@ void SSDP::run() } } } - threadDeregister(); + + RunEpilog(); } ///////////////////////////////////////////////////////////////////////////// diff --git a/mythtv/libs/libmythupnp/ssdp.h b/mythtv/libs/libmythupnp/ssdp.h index 5da502475f2..43f32e93f2a 100644 --- a/mythtv/libs/libmythupnp/ssdp.h +++ b/mythtv/libs/libmythupnp/ssdp.h @@ -24,10 +24,10 @@ #ifndef __SSDP_H__ #define __SSDP_H__ -#include #include #include "upnpexp.h" +#include "mthread.h" #include "httpserver.h" #include "taskqueue.h" #include "msocketdevice.h" @@ -69,7 +69,7 @@ typedef enum #define NumberOfSockets (sizeof( m_Sockets ) / sizeof( MSocketDevice * )) -class UPNP_PUBLIC SSDP : public QThread +class UPNP_PUBLIC SSDP : public MThread { private: // Singleton instance used by all. diff --git a/mythtv/libs/libmythupnp/taskqueue.cpp b/mythtv/libs/libmythupnp/taskqueue.cpp index c3acbd823c0..56ef6229f24 100644 --- a/mythtv/libs/libmythupnp/taskqueue.cpp +++ b/mythtv/libs/libmythupnp/taskqueue.cpp @@ -83,7 +83,7 @@ TaskQueue* TaskQueue::Instance() // ///////////////////////////////////////////////////////////////////////////// -TaskQueue::TaskQueue() : m_bTermRequested( false ) +TaskQueue::TaskQueue() : MThread("TaskQueue"), m_bTermRequested( false ) { LOG(VB_UPNP, LOG_INFO, "Starting TaskQueue Thread..."); @@ -116,9 +116,10 @@ void TaskQueue::RequestTerminate() void TaskQueue::run( ) { + RunProlog(); + Task *pTask; - threadRegister("TaskQueue"); LOG(VB_UPNP, LOG_INFO, "TaskQueue Thread Running."); while ( !m_bTermRequested ) @@ -147,7 +148,8 @@ void TaskQueue::run( ) msleep( 100 ); } - threadDeregister(); + + RunEpilog(); } ///////////////////////////////////////////////////////////////////////////// diff --git a/mythtv/libs/libmythupnp/taskqueue.h b/mythtv/libs/libmythupnp/taskqueue.h index 0a13333bc44..8ae3ec77bc9 100644 --- a/mythtv/libs/libmythupnp/taskqueue.h +++ b/mythtv/libs/libmythupnp/taskqueue.h @@ -35,12 +35,10 @@ // C++ headers #include -// Qt headers -#include - // MythTV headers -#include "upnputil.h" #include "refcounted.h" +#include "upnputil.h" +#include "mthread.h" #include "upnpexp.h" class Task; @@ -89,7 +87,7 @@ class Task : public RefCounted // TaskQueue Singleton ///////////////////////////////////////////////////////////////////////////// -class UPNP_PUBLIC TaskQueue : public QThread +class UPNP_PUBLIC TaskQueue : public MThread { private: diff --git a/mythtv/libs/libmythupnp/threadpool.cpp b/mythtv/libs/libmythupnp/threadpool.cpp index a818c53b79b..55803c2e288 100644 --- a/mythtv/libs/libmythupnp/threadpool.cpp +++ b/mythtv/libs/libmythupnp/threadpool.cpp @@ -158,7 +158,8 @@ void WorkerEvent::TimeOut() // ///////////////////////////////////////////////////////////////////////////// -WorkerThread::WorkerThread( ThreadPool *pThreadPool, const QString &sName ) +WorkerThread::WorkerThread( ThreadPool *pThreadPool, const QString &sName ) : + MThread("WorkerThread") { m_bInitialized = false; m_bTermRequested = false; @@ -261,7 +262,7 @@ void WorkerThread::RequestTerminate( void ) void WorkerThread::run( void ) { - threadRegister("WorkerThread"); + RunProlog(); m_timer = new QTimer(); m_timer->setSingleShot(true); @@ -291,7 +292,7 @@ void WorkerThread::run( void ) LOG(VB_UPNP, LOG_INFO, QString("WorkerThread:Run - Exiting: %1") .arg( m_sName )); - threadDeregister(); + RunEpilog(); } ///////////////////////////////////////////////////////////////////////////// diff --git a/mythtv/libs/libmythupnp/threadpool.h b/mythtv/libs/libmythupnp/threadpool.h index 94a603ac5f6..1eaad205715 100644 --- a/mythtv/libs/libmythupnp/threadpool.h +++ b/mythtv/libs/libmythupnp/threadpool.h @@ -30,11 +30,11 @@ using namespace std; #include #include #include -#include #include #include #include +#include "mthread.h" #include "upnpexp.h" class ThreadPool; @@ -99,7 +99,7 @@ class UPNP_PUBLIC WorkerEvent : public QObject ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -class UPNP_PUBLIC WorkerThread : public QThread +class UPNP_PUBLIC WorkerThread : public QObject, public MThread { Q_OBJECT diff --git a/mythtv/programs/mythbackend/autoexpire.cpp b/mythtv/programs/mythbackend/autoexpire.cpp index fd886c4e3be..759087314b9 100644 --- a/mythtv/programs/mythbackend/autoexpire.cpp +++ b/mythtv/programs/mythbackend/autoexpire.cpp @@ -53,17 +53,17 @@ extern AutoExpire *expirer; /// \brief This calls AutoExpire::RunExpirer() from within a new thread. void ExpireThread::run(void) { - threadRegister("Expire"); + RunProlog(); m_parent->RunExpirer(); - threadDeregister(); + RunEpilog(); } /// \brief This calls AutoExpire::RunUpdate() from within a new thread. void UpdateThread::run(void) { - threadRegister("Update"); + RunProlog(); m_parent->RunUpdate(); - threadDeregister(); + RunEpilog(); } /** \class AutoExpire diff --git a/mythtv/programs/mythbackend/autoexpire.h b/mythtv/programs/mythbackend/autoexpire.h index ff47f13d4c2..d1a59ac9096 100644 --- a/mythtv/programs/mythbackend/autoexpire.h +++ b/mythtv/programs/mythbackend/autoexpire.h @@ -7,14 +7,15 @@ using namespace std; #include +#include +#include #include #include #include #include #include -#include -#include -#include + +#include "mthread.h" class ProgramInfo; class EncoderLink; @@ -36,22 +37,21 @@ enum ExpireMethodType { class AutoExpire; -class ExpireThread : public QThread +class ExpireThread : public MThread { - Q_OBJECT public: - ExpireThread(AutoExpire *p) : m_parent(p) {} + ExpireThread(AutoExpire *p) : MThread("Expire"), m_parent(p) {} virtual ~ExpireThread() { wait(); } virtual void run(void); private: QPointer m_parent; }; -class UpdateThread : public QThread +class UpdateThread : public QObject, public MThread { Q_OBJECT public: - UpdateThread(AutoExpire *p) : m_parent(p) {} + UpdateThread(AutoExpire *p) : MThread("Update"), m_parent(p) {} virtual ~UpdateThread() { wait(); } virtual void run(void); private: diff --git a/mythtv/programs/mythbackend/housekeeper.cpp b/mythtv/programs/mythbackend/housekeeper.cpp index f9931239ad0..9e6978b778a 100644 --- a/mythtv/programs/mythbackend/housekeeper.cpp +++ b/mythtv/programs/mythbackend/housekeeper.cpp @@ -35,16 +35,16 @@ using namespace std; void HouseKeepingThread::run(void) { - threadRegister("HouseKeeping"); + RunProlog(); m_parent->RunHouseKeeping(); - threadDeregister(); + RunEpilog(); } void MythFillDatabaseThread::run(void) { - threadRegister("MythFillDB"); + RunProlog(); m_parent->RunMFD(); - threadDeregister(); + RunEpilog(); } HouseKeeper::HouseKeeper(bool runthread, bool master, Scheduler *lsched) : @@ -416,8 +416,6 @@ void HouseKeeper::flushDBLogs() void HouseKeeper::RunMFD(void) { - fillDBThread->setTerminationEnabled(false); - { QMutexLocker locker(&fillDBLock); fillDBStarted = true; @@ -474,11 +472,11 @@ void HouseKeeper::RunMFD(void) fillDBWait.wakeAll(); } - fillDBThread->setTerminationEnabled(true); + MythFillDatabaseThread::setTerminationEnabled(true); uint result = fillDBMythSystem->Wait(0); - fillDBThread->setTerminationEnabled(false); + MythFillDatabaseThread::setTerminationEnabled(false); { QMutexLocker locker(&fillDBLock); diff --git a/mythtv/programs/mythbackend/housekeeper.h b/mythtv/programs/mythbackend/housekeeper.h index 417301b3119..bbcbeaed607 100644 --- a/mythtv/programs/mythbackend/housekeeper.h +++ b/mythtv/programs/mythbackend/housekeeper.h @@ -3,33 +3,34 @@ #include #include -#include #include +#include "mthread.h" + class Scheduler; class QString; class HouseKeeper; class MythSystem; -class HouseKeepingThread : public QThread +class HouseKeepingThread : public MThread { - Q_OBJECT public: - HouseKeepingThread(HouseKeeper *p) : m_parent(p) {} + HouseKeepingThread(HouseKeeper *p) : + MThread("HouseKeeping"), m_parent(p) {} ~HouseKeepingThread() { wait(); } virtual void run(void); private: HouseKeeper *m_parent; }; -class MythFillDatabaseThread : public QThread +class MythFillDatabaseThread : public MThread { - Q_OBJECT public: - MythFillDatabaseThread(HouseKeeper *p) : m_parent(p) {} + MythFillDatabaseThread(HouseKeeper *p) : + MThread("MythFillDB"), m_parent(p) {} ~MythFillDatabaseThread() { wait(); } - virtual void setTerminationEnabled(bool v) - { QThread::setTerminationEnabled(v); } + static void setTerminationEnabled(bool v) + { MThread::setTerminationEnabled(v); } virtual void run(void); private: HouseKeeper *m_parent; diff --git a/mythtv/programs/mythbackend/main.cpp b/mythtv/programs/mythbackend/main.cpp index c723eb3fe5c..77d879bb1d2 100644 --- a/mythtv/programs/mythbackend/main.cpp +++ b/mythtv/programs/mythbackend/main.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp index b4ce3a38c3a..72d291bf0ac 100644 --- a/mythtv/programs/mythbackend/mainserver.cpp +++ b/mythtv/programs/mythbackend/mainserver.cpp @@ -29,7 +29,6 @@ using namespace std; #include #include #include -#include #include #include #include @@ -46,6 +45,7 @@ using namespace std; #include "mythdb.h" #include "mainserver.h" #include "server.h" +#include "mthread.h" #include "scheduler.h" #include "backendutil.h" #include "programinfo.h" @@ -121,10 +121,11 @@ int delete_file_immediately(const QString &filename, QMutex MainServer::truncate_and_close_lock; const uint MainServer::kMasterServerReconnectTimeout = 1000; //ms -class ProcessRequestThread : public QThread +class ProcessRequestThread : public MThread { public: ProcessRequestThread(MainServer *ms) : + MThread("ProcessRequestThread"), parent(ms), socket(NULL), threadlives(false) {} ~ProcessRequestThread() { killit(); wait(); } @@ -145,7 +146,7 @@ class ProcessRequestThread : public QThread virtual void run(void) { - threadRegister("ProcessRequest"); + RunProlog(); QMutexLocker locker(&lock); threadlives = true; waitCond.wakeAll(); // Signal to creating thread @@ -165,7 +166,7 @@ class ProcessRequestThread : public QThread socket = NULL; parent->MarkUnused(this); } - threadDeregister(); + RunEpilog(); } QMutex lock; @@ -1858,12 +1859,8 @@ void MainServer::HandleFillProgramInfo(QStringList &slist, PlaybackSock *pbs) void DeleteThread::run(void) { - if (!m_ms) - return; - - threadRegister("Delete"); - m_ms->DoDeleteThread(this); - threadDeregister(); + if (m_ms) + m_ms->DoDeleteThread(this); } void MainServer::DoDeleteThread(DeleteStruct *ds) @@ -4560,21 +4557,15 @@ void MainServer::GetFilesystemInfos(QList &fsInfos) void TruncateThread::run(void) { - if (!m_ms) - return; - - threadRegister("Truncate"); - m_ms->DoTruncateThread(this); - threadDeregister(); + if (m_ms) + m_ms->DoTruncateThread(this); } void MainServer::DoTruncateThread(DeleteStruct *ds) { if (gCoreContext->GetNumSetting("TruncateDeletesSlowly", 0)) { - QThreadPool::globalInstance()->releaseThread(); TruncateAndClose(NULL, ds->m_fd, ds->m_filename, ds->m_size); - QThreadPool::globalInstance()->reserveThread(); } else { diff --git a/mythtv/programs/mythbackend/mainserver.h b/mythtv/programs/mythbackend/mainserver.h index 193533822ed..ff3d372dac0 100644 --- a/mythtv/programs/mythbackend/mainserver.h +++ b/mythtv/programs/mythbackend/mainserver.h @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -15,6 +14,7 @@ using namespace std; #include "tv.h" #include "playbacksock.h" +#include "mthreadpool.h" #include "encoderlink.h" #include "filetransfer.h" #include "scheduler.h" @@ -69,7 +69,8 @@ class DeleteThread : public QRunnable, public DeleteStruct bool forceMetadataDelete) : DeleteStruct(ms, filename, title, chanid, recstartts, recendts, forceMetadataDelete) {} - void start(void) { QThreadPool::globalInstance()->start(this); } + void start(void) + { MThreadPool::globalInstance()->startReserved(this, "DeleteThread"); } void run(void); }; @@ -78,7 +79,8 @@ class TruncateThread : public QRunnable, public DeleteStruct public: TruncateThread(MainServer *ms, QString filename, int fd, off_t size) : DeleteStruct(ms, filename, fd, size) {} - void start(void) { QThreadPool::globalInstance()->start(this); } + void start(void) + { MThreadPool::globalInstance()->start(this, "Truncate"); } void run(void); }; diff --git a/mythtv/programs/mythbackend/scheduler.cpp b/mythtv/programs/mythbackend/scheduler.cpp index a7494d6f327..195aea57d40 100644 --- a/mythtv/programs/mythbackend/scheduler.cpp +++ b/mythtv/programs/mythbackend/scheduler.cpp @@ -53,6 +53,7 @@ bool debugConflicts = false; Scheduler::Scheduler(bool runthread, QMap *tvList, QString tmptable, Scheduler *master_sched) : + MThread("Scheduler"), recordTable(tmptable), priorityTable("powerpriority"), schedLock(), @@ -77,10 +78,7 @@ Scheduler::Scheduler(bool runthread, QMap *tvList, if (master_sched) master_sched->GetAllPending(reclist); - // Only the master scheduler should use SchedCon() - if (doRun) - dbConn = MSqlQuery::SchedCon(); - else + if (!doRun) dbConn = MSqlQuery::DDCon(); if (tmptable == "powerpriority_tmp") @@ -160,7 +158,7 @@ void Scheduler::ResetIdleTime(void) bool Scheduler::VerifyCards(void) { - MSqlQuery query(dbConn); + MSqlQuery query(MSqlQuery::InitCon()); if (!query.exec("SELECT count(*) FROM capturecard") || !query.next()) { MythDB::DBError("verifyCards() -- main query 1", query); @@ -188,7 +186,7 @@ bool Scheduler::VerifyCards(void) } uint numsources = 0; - MSqlQuery subquery(dbConn); + MSqlQuery subquery(MSqlQuery::InitCon()); while (query.next()) { subquery.prepare( @@ -1765,7 +1763,10 @@ void Scheduler::OldRecordedFixups(void) void Scheduler::run(void) { - threadRegister("Scheduler"); + RunProlog(); + + dbConn = MSqlQuery::SchedCon(); + // Notify constructor that we're actually running { QMutexLocker lockit(&schedLock); @@ -1929,8 +1930,7 @@ void Scheduler::run(void) } } - MSqlQuery::CloseSchedCon(); - threadDeregister(); + RunEpilog(); } int Scheduler::CalcTimeToNextHandleRecordingEvent( diff --git a/mythtv/programs/mythbackend/scheduler.h b/mythtv/programs/mythbackend/scheduler.h index 9acab3c8f64..b7121bfaee9 100644 --- a/mythtv/programs/mythbackend/scheduler.h +++ b/mythtv/programs/mythbackend/scheduler.h @@ -10,7 +10,6 @@ using namespace std; #include #include #include -#include #include #include #include @@ -21,6 +20,7 @@ using namespace std; #include "inputgroupmap.h" #include "mythdeque.h" #include "mythscheduler.h" +#include "mthread.h" class EncoderLink; class MainServer; @@ -28,17 +28,15 @@ class AutoExpire; class Scheduler; -class Scheduler : public QThread, public MythScheduler +class Scheduler : public MThread, public MythScheduler { - Q_OBJECT - public: Scheduler(bool runthread, QMap *tvList, QString recordTbl = "record", Scheduler *master_sched = NULL); ~Scheduler(); void Stop(void); - void Wait(void) { QThread::wait(); } + void Wait(void) { MThread::wait(); } void SetExpirer(AutoExpire *autoExpirer) { m_expirer = autoExpirer; } @@ -84,7 +82,7 @@ class Scheduler : public QThread, public MythScheduler int GetError(void) const { return error; } protected: - virtual void run(void); // QThread + virtual void run(void); // MThread private: QString recordTable; diff --git a/mythtv/programs/mythfrontend/audiogeneralsettings.cpp b/mythtv/programs/mythfrontend/audiogeneralsettings.cpp index 57745741db5..d2595352c60 100644 --- a/mythtv/programs/mythfrontend/audiogeneralsettings.cpp +++ b/mythtv/programs/mythfrontend/audiogeneralsettings.cpp @@ -529,6 +529,7 @@ AudioTestThread::AudioTestThread(QObject *parent, int channels, AudioOutputSettings settings, bool hd) : + MThread("AudioTest"), m_parent(parent), m_channels(channels), m_device(main), m_passthrough(passthrough), m_interrupted(false), m_channel(-1), m_hd(hd) { @@ -579,7 +580,7 @@ void AudioTestThread::setChannel(int channel) void AudioTestThread::run() { - threadRegister("AudioTest"); + RunProlog(); m_interrupted = false; int smptelayout[7][8] = { { 0, 1 }, //stereo @@ -682,7 +683,7 @@ void AudioTestThread::run() delete[] frames_in; } - threadDeregister(); + RunEpilog(); } AudioTest::AudioTest(QString main, QString passthrough, diff --git a/mythtv/programs/mythfrontend/audiogeneralsettings.h b/mythtv/programs/mythfrontend/audiogeneralsettings.h index 1b19462151d..fe31bd8555d 100644 --- a/mythtv/programs/mythfrontend/audiogeneralsettings.h +++ b/mythtv/programs/mythfrontend/audiogeneralsettings.h @@ -2,21 +2,17 @@ #define MYTHAUDIOSETTINGS_H #include - #include #include -#include - -#include "settings.h" -#include "mythcontext.h" - -// libmythui -#include -#include -#include -#include +#include "mythuistatetype.h" +#include "mythscreentype.h" +#include "mythdialogbox.h" +#include "mythuibutton.h" #include "audiooutput.h" +#include "mythcontext.h" +#include "settings.h" +#include "mthread.h" class AudioDeviceComboBox; @@ -146,7 +142,7 @@ class ChannelChangedEvent : public QEvent static Type kEventType; }; -class AudioTestThread : public QThread +class AudioTestThread : public MThread { public: diff --git a/mythtv/programs/mythfrontend/backendconnectionmanager.cpp b/mythtv/programs/mythfrontend/backendconnectionmanager.cpp index 3e2b6412165..046e108b192 100644 --- a/mythtv/programs/mythfrontend/backendconnectionmanager.cpp +++ b/mythtv/programs/mythfrontend/backendconnectionmanager.cpp @@ -1,18 +1,18 @@ #include -#include #include #include #include #include +#include "backendconnectionmanager.h" #include "mythcorecontext.h" #include "mythdialogbox.h" #include "mythscreenstack.h" #include "mythmainwindow.h" +#include "mthreadpool.h" +#include "mythlogging.h" #include "exitcodes.h" #include "util.h" // for checkTimeZone() -#include "backendconnectionmanager.h" -#include "mythlogging.h" class Reconnect : public QRunnable { @@ -24,12 +24,10 @@ class Reconnect : public QRunnable virtual void run(void) { - threadRegister("Reconnect"); if (gCoreContext->GetMasterHostPrefix().isEmpty()) gCoreContext->dispatch(MythEvent(QString("RECONNECT_FAILURE"))); else gCoreContext->dispatch(MythEvent(QString("RECONNECT_SUCCESS"))); - threadDeregister(); } }; @@ -133,5 +131,5 @@ void BackendConnectionManager::customEvent(QEvent *event) void BackendConnectionManager::ReconnectToBackend(void) { m_reconnecting = new Reconnect(); - QThreadPool::globalInstance()->start(m_reconnecting); + MThreadPool::globalInstance()->start(m_reconnecting, "Reconnect"); } diff --git a/mythtv/programs/mythfrontend/networkcontrol.cpp b/mythtv/programs/mythfrontend/networkcontrol.cpp index 7d8c3e7dea9..d5353108820 100644 --- a/mythtv/programs/mythfrontend/networkcontrol.cpp +++ b/mythtv/programs/mythfrontend/networkcontrol.cpp @@ -51,19 +51,12 @@ static bool is_abbrev(QString const& command, return test.toLower() == command.left(test.length()).toLower(); } -void NetworkCommandThread::run(void) -{ - threadRegister("NetworkCommand"); - m_parent->RunCommandThread(); - threadDeregister(); -} - NetworkControl::NetworkControl() : QTcpServer(), prompt("# "), gotAnswer(false), answer(""), clientLock(QMutex::Recursive), - commandThread(new NetworkCommandThread(this)), + commandThread(new MThread("NetworkControl", this)), stopCommandThread(false) { // Eventually this map should be in the jumppoints table @@ -272,7 +265,7 @@ bool NetworkControl::listen(const QHostAddress & address, quint16 port) return false; } -void NetworkControl::RunCommandThread(void) +void NetworkControl::run(void) { QMutexLocker locker(&ncLock); while (!stopCommandThread) diff --git a/mythtv/programs/mythfrontend/networkcontrol.h b/mythtv/programs/mythfrontend/networkcontrol.h index ee1742d31bf..d1a23c63152 100644 --- a/mythtv/programs/mythfrontend/networkcontrol.h +++ b/mythtv/programs/mythfrontend/networkcontrol.h @@ -4,13 +4,15 @@ #include using namespace std; -#include #include +#include #include #include +#include #include -#include -#include +#include + +#include "mthread.h" class MainServer; class QTextStream; @@ -87,22 +89,10 @@ class NetworkControlCloseEvent : public QEvent class NetworkControl; -class NetworkCommandThread : public QThread -{ - Q_OBJECT - public: - NetworkCommandThread(NetworkControl *parent) : m_parent(parent) {} - virtual ~NetworkCommandThread() { wait(); m_parent = NULL; } - virtual void run(void); - private: - NetworkControl *m_parent; -}; - -class NetworkControl : public QTcpServer +class NetworkControl : public QTcpServer, public QRunnable { Q_OBJECT - friend class NetworkCommandThread; public: NetworkControl(); ~NetworkControl(); @@ -115,7 +105,7 @@ class NetworkControl : public QTcpServer void deleteClient(void); protected: - void RunCommandThread(void); + void run(void); // QRunnable private: QString processJump(NetworkCommand *nc); @@ -157,7 +147,7 @@ class NetworkControl : public QTcpServer QList networkControlReplies; QMutex nrLock; - NetworkCommandThread *commandThread; + MThread *commandThread; bool stopCommandThread; // protected by ncLock }; diff --git a/mythtv/programs/mythfrontend/playbackboxhelper.cpp b/mythtv/programs/mythfrontend/playbackboxhelper.cpp index fd5e1cf3369..aa6f71aca88 100644 --- a/mythtv/programs/mythfrontend/playbackboxhelper.cpp +++ b/mythtv/programs/mythfrontend/playbackboxhelper.cpp @@ -316,11 +316,15 @@ void PBHEventHandler::UpdateFreeSpaceEvent(void) ////////////////////////////////////////////////////////////////////// PlaybackBoxHelper::PlaybackBoxHelper(QObject *listener) : - m_listener(listener), m_eventHandler(NULL), + MThread("PlaybackBoxHelper"), + m_listener(listener), m_eventHandler(new PBHEventHandler(*this)), // Free Space Tracking Variables m_freeSpaceTotalMB(0ULL), m_freeSpaceUsedMB(0ULL) { start(); + m_eventHandler->moveToThread(qthread()); + // Prime the pump so the disk free display starts updating + ForceFreeSpaceUpdate(); } PlaybackBoxHelper::~PlaybackBoxHelper() @@ -375,16 +379,6 @@ void PlaybackBoxHelper::UndeleteRecording( QCoreApplication::postEvent(m_eventHandler, e); } -void PlaybackBoxHelper::run(void) -{ - threadRegister("PlaybackBoxHelper"); - m_eventHandler = new PBHEventHandler(*this); - // Prime the pump so the disk free display starts updating - ForceFreeSpaceUpdate(); - exec(); - threadDeregister(); -} - void PlaybackBoxHelper::UpdateFreeSpace(void) { QVector fsInfos = RemoteGetFreeSpace(); diff --git a/mythtv/programs/mythfrontend/playbackboxhelper.h b/mythtv/programs/mythfrontend/playbackboxhelper.h index ba9e0c73d48..a288b8b3077 100644 --- a/mythtv/programs/mythfrontend/playbackboxhelper.h +++ b/mythtv/programs/mythfrontend/playbackboxhelper.h @@ -5,13 +5,13 @@ #include #include -#include #include #include #include #include "mythcorecontext.h" #include "metadatacommon.h" +#include "mthread.h" class PreviewGenerator; class PBHEventHandler; @@ -27,12 +27,10 @@ typedef enum CheckAvailabilityType { kCheckForPlaylistAction, } CheckAvailabilityType; -class PlaybackBoxHelper : public QThread +class PlaybackBoxHelper : public MThread { friend class PBHEventHandler; - Q_OBJECT - public: PlaybackBoxHelper(QObject *listener); ~PlaybackBoxHelper(void); @@ -52,8 +50,6 @@ class PlaybackBoxHelper : public QThread VideoArtworkType type, const ProgramInfo *pginfo, const QString &groupname = NULL); - virtual void run(void); // QThread - uint64_t GetFreeSpaceTotalMB(void) const; uint64_t GetFreeSpaceUsedMB(void) const; diff --git a/mythtv/programs/mythfrontend/programinfocache.cpp b/mythtv/programs/mythfrontend/programinfocache.cpp index 6934940866c..02fff67bae7 100644 --- a/mythtv/programs/mythfrontend/programinfocache.cpp +++ b/mythtv/programs/mythfrontend/programinfocache.cpp @@ -5,13 +5,14 @@ // (or at your option a later version) #include -#include +#include #include "programinfocache.h" +#include "mthreadpool.h" +#include "mythlogging.h" #include "programinfo.h" #include "remoteutil.h" #include "mythevent.h" -#include "mythlogging.h" typedef vector *VPI_ptr; static void free_vec(VPI_ptr &v) @@ -34,9 +35,7 @@ class ProgramInfoLoader : public QRunnable void run(void) { - threadRegister("ProgramInfoLoader"); m_cache.Load(m_updateUI); - threadDeregister(); } ProgramInfoCache &m_cache; @@ -67,8 +66,8 @@ void ProgramInfoCache::ScheduleLoad(const bool updateUI) { m_load_is_queued = true; m_loads_in_progress++; - QThreadPool::globalInstance()->start( - new ProgramInfoLoader(*this, updateUI)); + MThreadPool::globalInstance()->start( + new ProgramInfoLoader(*this, updateUI), "ProgramInfoLoader"); } } diff --git a/mythtv/programs/mythfrontend/themechooser.cpp b/mythtv/programs/mythfrontend/themechooser.cpp index 540c03f8b0a..c5ca8ae3bc7 100644 --- a/mythtv/programs/mythfrontend/themechooser.cpp +++ b/mythtv/programs/mythfrontend/themechooser.cpp @@ -4,12 +4,13 @@ // Qt headers #include -#include +#include #include // MythTV headers #include "mythcorecontext.h" #include "mythcoreutil.h" +#include "mthreadpool.h" #include "remotefile.h" #include "mythdownloadmanager.h" #include "programtypes.h" @@ -49,13 +50,11 @@ class ThemeExtractThread : public QRunnable void run() { - threadRegister("ThemeExtract"); extractZIP(m_srcFile, m_destDir); MythEvent *me = new MythEvent("THEME_INSTALLED", QStringList(m_srcFile)); QCoreApplication::postEvent(m_parent, me); - threadDeregister(); } private: @@ -766,7 +765,8 @@ void ThemeChooser::customEvent(QEvent *e) ThemeExtractThread *extractThread = new ThemeExtractThread(this, m_downloadFile, GetConfDir() + "/themes"); - QThreadPool::globalInstance()->start(extractThread); + MThreadPool::globalInstance()->start( + extractThread, "ThemeExtract"); if (!remoteFileIsLocal) RemoteFile::DeleteFile(args[0]); diff --git a/mythtv/programs/mythfrontend/upnpscanner.cpp b/mythtv/programs/mythfrontend/upnpscanner.cpp index c35b1581645..e9ff0f3a67b 100644 --- a/mythtv/programs/mythfrontend/upnpscanner.cpp +++ b/mythtv/programs/mythfrontend/upnpscanner.cpp @@ -105,7 +105,7 @@ class MediaServer : public MediaServerItem UPNPScanner* UPNPScanner::gUPNPScanner = NULL; bool UPNPScanner::gUPNPScannerEnabled = false; -QThread* UPNPScanner::gUPNPScannerThread = NULL; +MThread* UPNPScanner::gUPNPScannerThread = NULL; QMutex* UPNPScanner::gUPNPScannerLock = new QMutex(QMutex::Recursive); /** @@ -164,15 +164,16 @@ UPNPScanner* UPNPScanner::Instance(UPNPSubscription *sub) } if (!gUPNPScannerThread) - gUPNPScannerThread = new QThread(); + gUPNPScannerThread = new MThread("UPnPScanner"); if (!gUPNPScanner) gUPNPScanner = new UPNPScanner(sub); if (!gUPNPScannerThread->isRunning()) { - gUPNPScanner->moveToThread(gUPNPScannerThread); - gUPNPScannerThread->connect(gUPNPScannerThread, SIGNAL(started()), - gUPNPScanner, SLOT(Start())); + gUPNPScanner->moveToThread(gUPNPScannerThread->qthread()); + QObject::connect( + gUPNPScannerThread->qthread(), SIGNAL(started()), + gUPNPScanner, SLOT(Start())); gUPNPScannerThread->start(QThread::LowestPriority); } diff --git a/mythtv/programs/mythfrontend/upnpscanner.h b/mythtv/programs/mythfrontend/upnpscanner.h index a289fc6cc40..db60d852293 100644 --- a/mythtv/programs/mythfrontend/upnpscanner.h +++ b/mythtv/programs/mythfrontend/upnpscanner.h @@ -1,16 +1,16 @@ #ifndef UPNPSCANNER_H #define UPNPSCANNER_H -#include #include #include #include +#include #include #include -#include -#include "upnpexp.h" #include "upnpsubscription.h" +#include "mthread.h" +#include "upnpexp.h" #include "videometadatalistmanager.h" @@ -97,7 +97,7 @@ class UPNPScanner : public QObject private: static UPNPScanner* gUPNPScanner; static bool gUPNPScannerEnabled; - static QThread* gUPNPScannerThread; + static MThread* gUPNPScannerThread; static QMutex* gUPNPScannerLock; UPNPSubscription *m_subscription; diff --git a/mythtv/programs/mythtranscode/mpeg2fix.cpp b/mythtv/programs/mythtranscode/mpeg2fix.cpp index a4b30f4e789..7ac8e533eea 100644 --- a/mythtv/programs/mythtranscode/mpeg2fix.cpp +++ b/mythtv/programs/mythtranscode/mpeg2fix.cpp @@ -502,6 +502,7 @@ void *MPEG2fixup::ReplexStart(void *data) threadRegister("MPEG2Replex"); MPEG2fixup *m2f = (MPEG2fixup *) data; m2f->rx.Start(); + GetMythDB()->GetDBManager()->CloseDatabases(); threadDeregister(); return NULL; } From f3a67b348964fa3582e08cfdd0dcdcf4747b3e46 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Thu, 4 Aug 2011 10:30:08 -0400 Subject: [PATCH 34/49] Renames recorder's StartRecorder() method to run(). StartRecorder is actually the loop that runs the entire time that a recording is in progress. Unlike in the TV class where it is a signal for the event loop to start a recording. --- mythtv/libs/libmythtv/NuppelVideoRecorder.cpp | 2 +- mythtv/libs/libmythtv/NuppelVideoRecorder.h | 2 +- mythtv/libs/libmythtv/asirecorder.cpp | 2 +- mythtv/libs/libmythtv/asirecorder.h | 2 +- mythtv/libs/libmythtv/dvbrecorder.cpp | 2 +- mythtv/libs/libmythtv/dvbrecorder.h | 2 +- mythtv/libs/libmythtv/firewirerecorder.cpp | 4 ++-- mythtv/libs/libmythtv/firewirerecorder.h | 2 +- mythtv/libs/libmythtv/hdhrrecorder.cpp | 8 ++++---- mythtv/libs/libmythtv/hdhrrecorder.h | 2 +- mythtv/libs/libmythtv/importrecorder.cpp | 10 +++++----- mythtv/libs/libmythtv/importrecorder.h | 2 +- mythtv/libs/libmythtv/iptvrecorder.cpp | 6 +++--- mythtv/libs/libmythtv/iptvrecorder.h | 2 +- mythtv/libs/libmythtv/mpegrecorder.cpp | 4 ++-- mythtv/libs/libmythtv/mpegrecorder.h | 2 +- mythtv/libs/libmythtv/recorderbase.cpp | 12 ++++++------ mythtv/libs/libmythtv/recorderbase.h | 7 +++---- 18 files changed, 36 insertions(+), 37 deletions(-) diff --git a/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp b/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp index 0d2b734f565..1c634b99a7e 100644 --- a/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp +++ b/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp @@ -1062,7 +1062,7 @@ void NuppelVideoRecorder::ProbeV4L2(void) #endif // USING_V4L2 } -void NuppelVideoRecorder::StartRecording(void) +void NuppelVideoRecorder::run(void) { if (lzo_init() != LZO_E_OK) { diff --git a/mythtv/libs/libmythtv/NuppelVideoRecorder.h b/mythtv/libs/libmythtv/NuppelVideoRecorder.h index 7cff4217197..e30a7819e23 100644 --- a/mythtv/libs/libmythtv/NuppelVideoRecorder.h +++ b/mythtv/libs/libmythtv/NuppelVideoRecorder.h @@ -86,7 +86,7 @@ class MTV_PUBLIC NuppelVideoRecorder : public V4LRecorder, public CC608Input const QString &vbidev); void Initialize(void); - void StartRecording(void); + void run(void); void StopRecording(void); virtual void Pause(bool clear = true); diff --git a/mythtv/libs/libmythtv/asirecorder.cpp b/mythtv/libs/libmythtv/asirecorder.cpp index d4c00345728..07eee43e5b1 100644 --- a/mythtv/libs/libmythtv/asirecorder.cpp +++ b/mythtv/libs/libmythtv/asirecorder.cpp @@ -61,7 +61,7 @@ void ASIRecorder::SetOption(const QString &name, int value) DTVRecorder::SetOption(name, value); } -void ASIRecorder::StartRecording(void) +void ASIRecorder::run(void) { if (!Open()) { diff --git a/mythtv/libs/libmythtv/asirecorder.h b/mythtv/libs/libmythtv/asirecorder.h index 73437ec59ff..f29ccc5ee03 100644 --- a/mythtv/libs/libmythtv/asirecorder.h +++ b/mythtv/libs/libmythtv/asirecorder.h @@ -63,7 +63,7 @@ class ASIRecorder : public DTVRecorder const QString &vbidev); void SetOption(const QString &name, int value); - void StartRecording(void); + void run(void); bool Open(void); bool IsOpen(void) const; diff --git a/mythtv/libs/libmythtv/dvbrecorder.cpp b/mythtv/libs/libmythtv/dvbrecorder.cpp index 38889ef6069..e842e326510 100644 --- a/mythtv/libs/libmythtv/dvbrecorder.cpp +++ b/mythtv/libs/libmythtv/dvbrecorder.cpp @@ -74,7 +74,7 @@ void DVBRecorder::Close(void) LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); } -void DVBRecorder::StartRecording(void) +void DVBRecorder::run(void) { if (!Open()) { diff --git a/mythtv/libs/libmythtv/dvbrecorder.h b/mythtv/libs/libmythtv/dvbrecorder.h index de0a3dfdb5e..eb0b5f80ddb 100644 --- a/mythtv/libs/libmythtv/dvbrecorder.h +++ b/mythtv/libs/libmythtv/dvbrecorder.h @@ -23,7 +23,7 @@ class DVBRecorder : public DTVRecorder public: DVBRecorder(TVRec*, DVBChannel*); - void StartRecording(void); + void run(void); bool Open(void); bool IsOpen(void) const; diff --git a/mythtv/libs/libmythtv/firewirerecorder.cpp b/mythtv/libs/libmythtv/firewirerecorder.cpp index a68501de66b..372fefea6ff 100644 --- a/mythtv/libs/libmythtv/firewirerecorder.cpp +++ b/mythtv/libs/libmythtv/firewirerecorder.cpp @@ -52,9 +52,9 @@ void FirewireRecorder::StopStreaming(void) channel->GetFirewireDevice()->RemoveListener(this); } -void FirewireRecorder::StartRecording(void) +void FirewireRecorder::run(void) { - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording"); + LOG(VB_RECORD, LOG_INFO, LOC + "run"); if (!Open()) { diff --git a/mythtv/libs/libmythtv/firewirerecorder.h b/mythtv/libs/libmythtv/firewirerecorder.h index 725cbc35007..1d6a766809a 100644 --- a/mythtv/libs/libmythtv/firewirerecorder.h +++ b/mythtv/libs/libmythtv/firewirerecorder.h @@ -39,7 +39,7 @@ class FirewireRecorder : void StartStreaming(void); void StopStreaming(void); - void StartRecording(void); + void run(void); bool PauseAndWait(int timeout = 100); // Implements TSDataListener diff --git a/mythtv/libs/libmythtv/hdhrrecorder.cpp b/mythtv/libs/libmythtv/hdhrrecorder.cpp index 4cbd1b9ea09..88ea59f9790 100644 --- a/mythtv/libs/libmythtv/hdhrrecorder.cpp +++ b/mythtv/libs/libmythtv/hdhrrecorder.cpp @@ -49,9 +49,9 @@ void HDHRRecorder::Close(void) LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); } -void HDHRRecorder::StartRecording(void) +void HDHRRecorder::run(void) { - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording -- begin"); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); /* Create video socket. */ if (!Open()) @@ -112,7 +112,7 @@ void HDHRRecorder::StartRecording(void) } } - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording -- ending..."); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- ending..."); _stream_handler->RemoveListener(_stream_data); _stream_data->RemoveWritingListener(this); @@ -126,7 +126,7 @@ void HDHRRecorder::StartRecording(void) recording = false; recordingWait.wakeAll(); - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording -- end"); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- end"); } bool HDHRRecorder::PauseAndWait(int timeout) diff --git a/mythtv/libs/libmythtv/hdhrrecorder.h b/mythtv/libs/libmythtv/hdhrrecorder.h index 839cb8fc615..44b3fc18305 100644 --- a/mythtv/libs/libmythtv/hdhrrecorder.h +++ b/mythtv/libs/libmythtv/hdhrrecorder.h @@ -21,7 +21,7 @@ class HDHRRecorder : public DTVRecorder public: HDHRRecorder(TVRec *rec, HDHRChannel *channel); - void StartRecording(void); + void run(void); bool Open(void); bool IsOpen(void) const { return _stream_handler; } diff --git a/mythtv/libs/libmythtv/importrecorder.cpp b/mythtv/libs/libmythtv/importrecorder.cpp index 63f17930a96..9a58ddb891f 100644 --- a/mythtv/libs/libmythtv/importrecorder.cpp +++ b/mythtv/libs/libmythtv/importrecorder.cpp @@ -75,9 +75,9 @@ void ImportRecorder::SetOptionsFromProfile(RecordingProfile *profile, SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat")); } -void ImportRecorder::StartRecording(void) +void ImportRecorder::run(void) { - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording -- begin"); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); _continuity_error_count = 0; @@ -88,7 +88,7 @@ void ImportRecorder::StartRecording(void) recordingWait.wakeAll(); } - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording -- " + + LOG(VB_RECORD, LOG_INFO, LOC + "run -- " + QString("attempting to open '%1'") .arg(curRecording->GetPathname())); @@ -132,7 +132,7 @@ void ImportRecorder::StartRecording(void) recording = false; recordingWait.wakeAll(); - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording -- end"); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- end"); } bool ImportRecorder::Open(void) @@ -182,7 +182,7 @@ bool ImportRecorder::Open(void) LOG(VB_RECORD, LOG_INFO, LOC + QString("'%1' does not exist yet").arg(fn)); - // Slow down StartRecording open loop when debugging -v record. + // Slow down run open loop when debugging -v record. // This is just to make the debugging output less spammy. if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_ANY)) usleep(250 * 1000); diff --git a/mythtv/libs/libmythtv/importrecorder.h b/mythtv/libs/libmythtv/importrecorder.h index cf5b3b3f539..67af18eb34b 100644 --- a/mythtv/libs/libmythtv/importrecorder.h +++ b/mythtv/libs/libmythtv/importrecorder.h @@ -31,7 +31,7 @@ class ImportRecorder : public DTVRecorder const QString &audiodev, const QString &vbidev); - void StartRecording(void); + void run(void); bool Open(void); void Close(void); diff --git a/mythtv/libs/libmythtv/iptvrecorder.cpp b/mythtv/libs/libmythtv/iptvrecorder.cpp index 219808e195e..8ff60e4d9cc 100644 --- a/mythtv/libs/libmythtv/iptvrecorder.cpp +++ b/mythtv/libs/libmythtv/iptvrecorder.cpp @@ -98,9 +98,9 @@ bool IPTVRecorder::PauseAndWait(int timeout) return IsPaused(true); } -void IPTVRecorder::StartRecording(void) +void IPTVRecorder::run(void) { - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording() -- begin"); + LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin"); if (!Open()) { _error = "Failed to open IPTV stream"; @@ -141,7 +141,7 @@ void IPTVRecorder::StartRecording(void) recording = false; recordingWait.wakeAll(); - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording() -- end"); + LOG(VB_RECORD, LOG_INFO, LOC + "run() -- end"); } // =================================================== diff --git a/mythtv/libs/libmythtv/iptvrecorder.h b/mythtv/libs/libmythtv/iptvrecorder.h index db533822b65..5b6c667b724 100644 --- a/mythtv/libs/libmythtv/iptvrecorder.h +++ b/mythtv/libs/libmythtv/iptvrecorder.h @@ -29,7 +29,7 @@ class IPTVRecorder : public DTVRecorder, public TSDataListener bool Open(void); void Close(void); - virtual void StartRecording(void); + virtual void run(void); virtual void SetOptionsFromProfile(RecordingProfile*, const QString&, const QString&, const QString&) {} diff --git a/mythtv/libs/libmythtv/mpegrecorder.cpp b/mythtv/libs/libmythtv/mpegrecorder.cpp index eee83dbd946..107f53a229d 100644 --- a/mythtv/libs/libmythtv/mpegrecorder.cpp +++ b/mythtv/libs/libmythtv/mpegrecorder.cpp @@ -900,7 +900,7 @@ bool MpegRecorder::Open(void) return (deviceIsMpegFile) ? OpenMpegFileAsInput() : OpenV4L2DeviceAsInput(); } -void MpegRecorder::StartRecording(void) +void MpegRecorder::run(void) { if (!Open()) { @@ -1137,7 +1137,7 @@ void MpegRecorder::StartRecording(void) } } - LOG(VB_RECORD, LOG_INFO, LOC + "StartRecording finishing up"); + LOG(VB_RECORD, LOG_INFO, LOC + "run finishing up"); pauseLock.lock(); if (_device_read_buffer) diff --git a/mythtv/libs/libmythtv/mpegrecorder.h b/mythtv/libs/libmythtv/mpegrecorder.h index eb56712ce3e..da1b7fc65e6 100644 --- a/mythtv/libs/libmythtv/mpegrecorder.h +++ b/mythtv/libs/libmythtv/mpegrecorder.h @@ -29,7 +29,7 @@ class MpegRecorder : public V4LRecorder, const QString &vbidev); void Initialize(void) {} - void StartRecording(void); + void run(void); void StopRecording(void); void Reset(void); diff --git a/mythtv/libs/libmythtv/recorderbase.cpp b/mythtv/libs/libmythtv/recorderbase.cpp index 7d6e469bf8c..ed7c0e0cacc 100644 --- a/mythtv/libs/libmythtv/recorderbase.cpp +++ b/mythtv/libs/libmythtv/recorderbase.cpp @@ -159,10 +159,10 @@ void RecorderBase::SetStrOption(RecordingProfile *profile, const QString &name) QString("SetStrOption(...%1): Option not in profile.").arg(name)); } -/** \brief StopRecording() signals to the StartRecording() function that +/** \brief StopRecording() signals to the recorder that * it should stop recording and exit cleanly. * - * This function should block until StartRecording() has finished up. + * This function should block until recorder has finished up. */ void RecorderBase::StopRecording(void) { @@ -175,7 +175,7 @@ void RecorderBase::StopRecording(void) if (request_recording) { LOG(VB_GENERAL, LOG_ERR, LOC + - "Programmer Error: StartRecording called while we were in " + "Programmer Error: Recorder started while we were in " "StopRecording"); request_recording = false; } @@ -196,7 +196,7 @@ bool RecorderBase::IsRecordingRequested(void) return request_recording; } -/** \brief Pause tells StartRecording() to pause, it should not block. +/** \brief Pause tells recorder to pause, it should not block. * * Once paused the recorder calls tvrec->RecorderPaused(). * @@ -210,7 +210,7 @@ void RecorderBase::Pause(bool clear) request_pause = true; } -/** \brief Unpause tells StartRecording() to unpause. +/** \brief Unpause tells recorder to unpause. * This is an asynchronous call it should not wait block waiting * for the command to be processed. */ @@ -233,7 +233,7 @@ bool RecorderBase::IsPaused(bool holding_lock) const } /** \fn RecorderBase::WaitForPause(int) - * \brief WaitForPause blocks until StartRecording() is actually paused, + * \brief WaitForPause blocks until recorder is actually paused, * or timeout milliseconds elapse. * \param timeout number of milliseconds to wait defaults to 1000. * \return true iff pause happened within timeout period. diff --git a/mythtv/libs/libmythtv/recorderbase.h b/mythtv/libs/libmythtv/recorderbase.h index ea2cd4c6816..34a444da3ea 100644 --- a/mythtv/libs/libmythtv/recorderbase.h +++ b/mythtv/libs/libmythtv/recorderbase.h @@ -116,16 +116,15 @@ class MTV_PUBLIC RecorderBase : public QRunnable virtual void SetNextRecording(const ProgramInfo*, RingBuffer*) = 0; /** \brief This is called between SetOptionsFromProfile() and - * StartRecording() to initialize any devices, etc. + * run() to initialize any devices, etc. */ virtual void Initialize(void) = 0; - /** \brief StartRecording() starts the recording process, and does not + /** \brief run() starts the recording process, and does not * exit until the recording is complete. * \sa StopRecording() */ - virtual void StartRecording(void) = 0; - virtual void run(void) { StartRecording(); } // QRunnable + virtual void run(void) = 0; /** \brief Reset the recorder to the startup state. * From b008d612257538936bfcf0f3a26e854044a1d3fa Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sat, 6 Aug 2011 17:29:47 -0400 Subject: [PATCH 35/49] Share DB connection per thread & PurgeIdleThreads when possible --- mythtv/libs/libmythbase/mthread.cpp | 24 +++++++++++++++-- mythtv/libs/libmythbase/mythdbcon.cpp | 39 ++++++++++++++++++++++++--- mythtv/libs/libmythbase/mythdbcon.h | 8 ++++-- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/mythtv/libs/libmythbase/mthread.cpp b/mythtv/libs/libmythbase/mthread.cpp index da54bc113fc..025635fa379 100644 --- a/mythtv/libs/libmythbase/mthread.cpp +++ b/mythtv/libs/libmythbase/mthread.cpp @@ -24,6 +24,7 @@ using namespace std; // Qt headers #include +#include #include #include @@ -53,6 +54,21 @@ bool is_current_thread(MThread &thread) return QThread::currentThread() == thread.qthread(); } +class DBPurgeHandler : public QObject +{ + public: + DBPurgeHandler() + { + purgeTimer = startTimer(5 * 60000); + } + void timerEvent(QTimerEvent *event) + { + if (event->timerId() == purgeTimer) + GetMythDB()->GetDBManager()->PurgeIdleConnections(false); + } + int purgeTimer; +}; + class MThreadInternal : public QThread { public: @@ -60,7 +76,11 @@ class MThreadInternal : public QThread virtual void run(void) { m_parent.run(); } void QThreadRun(void) { QThread::run(); } - int QThreadExec(void) { return QThread::exec(); } + int exec(void) + { + DBPurgeHandler ph(); + return QThread::exec(); + } static void SetTerminationEnabled(bool enabled = true) { QThread::setTerminationEnabled(enabled); } @@ -289,7 +309,7 @@ void MThread::run(void) int MThread::exec(void) { - return m_thread->QThreadExec(); + return m_thread->exec(); } void MThread::setTerminationEnabled(bool enabled) diff --git a/mythtv/libs/libmythbase/mythdbcon.cpp b/mythtv/libs/libmythbase/mythdbcon.cpp index 814601ba5ad..a82957f1d19 100644 --- a/mythtv/libs/libmythbase/mythdbcon.cpp +++ b/mythtv/libs/libmythbase/mythdbcon.cpp @@ -15,6 +15,7 @@ #include "compat.h" #include "mythdbcon.h" #include "mythdb.h" +#include "mythcorecontext.h" #include "mythlogging.h" #include "mythsystem.h" #include "exitcodes.h" @@ -269,12 +270,22 @@ MDBManager::~MDBManager() MSqlDatabase *MDBManager::popConnection() { - PurgeIdleConnections(); + PurgeIdleConnections(true); m_lock.lock(); MSqlDatabase *db; +#if REUSE_CONNECTION + db = m_inuse[QThread::currentThread()]; + if (db != NULL) + { + m_inuse_count[QThread::currentThread()]++; + m_lock.unlock(); + return db; + } +#endif + DBList &list = m_pool[QThread::currentThread()]; if (list.isEmpty()) { @@ -289,6 +300,11 @@ MSqlDatabase *MDBManager::popConnection() list.pop_back(); } +#if REUSE_CONNECTION + m_inuse_count[QThread::currentThread()]=1; + m_inuse[QThread::currentThread()] = db; +#endif + m_lock.unlock(); db->OpenDatabase(); @@ -300,6 +316,19 @@ void MDBManager::pushConnection(MSqlDatabase *db) { m_lock.lock(); +#if REUSE_CONNECTION + if (db == m_inuse[QThread::currentThread()]) + { + int cnt = --m_inuse_count[QThread::currentThread()]; + if (cnt > 0) + { + m_lock.unlock(); + return; + } + m_inuse[QThread::currentThread()] = NULL; + } +#endif + if (db) { db->m_lastDBKick = QDateTime::currentDateTime(); @@ -308,13 +337,15 @@ void MDBManager::pushConnection(MSqlDatabase *db) m_lock.unlock(); - PurgeIdleConnections(); + PurgeIdleConnections(true); } -void MDBManager::PurgeIdleConnections(void) +void MDBManager::PurgeIdleConnections(bool leaveOne) { QMutexLocker locker(&m_lock); + leaveOne = leaveOne || (gCoreContext && gCoreContext->IsUIThread()); + QDateTime now = QDateTime::currentDateTime(); DBList &list = m_pool[QThread::currentThread()]; DBList::iterator it = list.begin(); @@ -347,7 +378,7 @@ void MDBManager::PurgeIdleConnections(void) // threads didn't exit". This workaround simply creates an // extra DB connection before all pooled connections are // purged so that my_thread_global_end() won't be called. - if (it == list.end() && + if (leaveOne && it == list.end() && purgedConnections > 0 && totalConnections == purgedConnections) { diff --git a/mythtv/libs/libmythbase/mythdbcon.h b/mythtv/libs/libmythbase/mythdbcon.h index 2b782e7a108..0ed2c967fad 100644 --- a/mythtv/libs/libmythbase/mythdbcon.h +++ b/mythtv/libs/libmythbase/mythdbcon.h @@ -14,7 +14,7 @@ #include "mythbaseexp.h" #include "mythdbparams.h" -class QSemaphore; +#define REUSE_CONNECTION 1 MBASE_PUBLIC bool TestDatabase(QString dbHostName, QString dbUserName, @@ -57,7 +57,7 @@ class MBASE_PUBLIC MDBManager ~MDBManager(void); void CloseDatabases(void); - void PurgeIdleConnections(void); + void PurgeIdleConnections(bool leaveOne = false); protected: MSqlDatabase *popConnection(void); @@ -75,6 +75,10 @@ class MBASE_PUBLIC MDBManager QMutex m_lock; typedef QList DBList; QHash m_pool; // protected by m_lock +#if REUSE_CONNECTION + QHash m_inuse; // protected by m_lock + QHash m_inuse_count; // protected by m_lock +#endif int m_nextConnID; int m_connCount; From 3c0898f13b3a097e8aab15bb0a08561a71e04f9d Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sun, 7 Aug 2011 10:41:29 -0400 Subject: [PATCH 36/49] Add some housekeeping to threadpool. --- mythtv/libs/libmythbase/mthreadpool.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mythtv/libs/libmythbase/mthreadpool.cpp b/mythtv/libs/libmythbase/mthreadpool.cpp index 9c0b8cd0893..b3052583e2d 100644 --- a/mythtv/libs/libmythbase/mthreadpool.cpp +++ b/mythtv/libs/libmythbase/mthreadpool.cpp @@ -24,6 +24,7 @@ using namespace std; // Qt headers +#include #include #include #include @@ -38,6 +39,7 @@ using namespace std; #include "mythlogging.h" #include "mythtimer.h" #include "mthread.h" +#include "mythdb.h" typedef QPair MPoolEntry; typedef QList MPoolQueue; @@ -90,6 +92,10 @@ class MPoolThread : public MThread threadDeregister(); threadRegister(objectName()); + + GetMythDB()->GetDBManager()->PurgeIdleConnections(false); + QCoreApplication::processEvents(); + t.start(); if (m_do_run) From 33dbe84d905010a68190aa36647e5283ab55c31a Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sun, 7 Aug 2011 10:42:27 -0400 Subject: [PATCH 37/49] Add the ability for startReserved to wait a little while for a free thread before going ahead with creating a new one. --- mythtv/libs/libmythbase/mthreadpool.cpp | 15 ++++++++++++++- mythtv/libs/libmythbase/mthreadpool.h | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mythtv/libs/libmythbase/mthreadpool.cpp b/mythtv/libs/libmythbase/mthreadpool.cpp index b3052583e2d..e8ae3010553 100644 --- a/mythtv/libs/libmythbase/mthreadpool.cpp +++ b/mythtv/libs/libmythbase/mthreadpool.cpp @@ -310,9 +310,22 @@ void MThreadPool::start(QRunnable *runnable, QString debugName, int priority) } void MThreadPool::startReserved( - QRunnable *runnable, QString debugName, int priority) + QRunnable *runnable, QString debugName, int waitForAvailMS) { QMutexLocker locker(&m_priv->m_lock); + if (waitForAvailMS > 0 && m_priv->m_avail_threads.empty() && + m_priv->m_running_threads.size() >= m_priv->m_max_thread_count) + { + MythTimer t; + t.start(); + int left = waitForAvailMS - t.elapsed(); + while (left > 0 && m_priv->m_avail_threads.empty() && + m_priv->m_running_threads.size() >= m_priv->m_max_thread_count) + { + m_priv->m_wait.wait(locker.mutex(), left); + left = waitForAvailMS - t.elapsed(); + } + } TryStartInternal(runnable, debugName, true); } diff --git a/mythtv/libs/libmythbase/mthreadpool.h b/mythtv/libs/libmythbase/mthreadpool.h index f0ad6cae5a6..19cc9f8019b 100644 --- a/mythtv/libs/libmythbase/mthreadpool.h +++ b/mythtv/libs/libmythbase/mthreadpool.h @@ -31,7 +31,7 @@ class MBASE_PUBLIC MThreadPool bool tryStart(QRunnable *runnable, QString debugName); void startReserved(QRunnable *runnable, QString debugName, - int priority = 0); + int waitForAvailMS = 0); int expiryTimeout(void) const; void setExpiryTimeout(int expiryTimeout); From 9cf7e5528db4c1b34783e46a97b2942d62cf9117 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sun, 7 Aug 2011 10:43:44 -0400 Subject: [PATCH 38/49] Convert MainServer's ProcessRequest thread poll to MThreadPool. --- mythtv/programs/mythbackend/mainserver.cpp | 130 +++------------------ mythtv/programs/mythbackend/mainserver.h | 7 +- 2 files changed, 19 insertions(+), 118 deletions(-) diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp index 72d291bf0ac..1feca777175 100644 --- a/mythtv/programs/mythbackend/mainserver.cpp +++ b/mythtv/programs/mythbackend/mainserver.cpp @@ -121,70 +121,31 @@ int delete_file_immediately(const QString &filename, QMutex MainServer::truncate_and_close_lock; const uint MainServer::kMasterServerReconnectTimeout = 1000; //ms -class ProcessRequestThread : public MThread +class ProcessRequestRunnable : public QRunnable { public: - ProcessRequestThread(MainServer *ms) : - MThread("ProcessRequestThread"), - parent(ms), socket(NULL), threadlives(false) {} - ~ProcessRequestThread() { killit(); wait(); } - - void setup(MythSocket *sock) + ProcessRequestRunnable(MainServer &parent, MythSocket *sock) : + m_parent(parent), m_sock(sock) { - QMutexLocker locker(&lock); - socket = sock; - socket->UpRef(); - waitCond.wakeAll(); - } - - void killit(void) - { - QMutexLocker locker(&lock); - threadlives = false; - waitCond.wakeAll(); + m_sock->UpRef(); } virtual void run(void) { - RunProlog(); - QMutexLocker locker(&lock); - threadlives = true; - waitCond.wakeAll(); // Signal to creating thread - - while (true) - { - waitCond.wait(locker.mutex()); - - if (!threadlives) - break; - - if (!socket) - continue; - - parent->ProcessRequest(socket); - socket->DownRef(); - socket = NULL; - parent->MarkUnused(this); - } - RunEpilog(); + m_parent.ProcessRequest(m_sock); + m_sock->DownRef(); } - QMutex lock; - QWaitCondition waitCond; - - private: - MainServer *parent; - - MythSocket *socket; - - bool threadlives; + MainServer &m_parent; + MythSocket *m_sock; }; MainServer::MainServer(bool master, int port, QMap *tvList, Scheduler *sched, AutoExpire *expirer) : encoderList(tvList), mythserver(NULL), masterServerReconnect(NULL), - masterServer(NULL), ismaster(master), masterBackendOverride(false), + masterServer(NULL), ismaster(master), threadPool("ProcessRequestPool"), + masterBackendOverride(false), m_sched(sched), m_expirer(expirer), deferredDeleteTimer(NULL), autoexpireUpdateTimer(NULL), m_exitCode(GENERIC_EXIT_OK), m_stopped(false) @@ -193,16 +154,7 @@ MainServer::MainServer(bool master, int port, PreviewGenerator::kLocalAndRemote, ~0, 0); PreviewGeneratorQueue::AddListener(this); - for (int i = 0; i < PRT_STARTUP_THREAD_COUNT; i++) - { - ProcessRequestThread *prt = new ProcessRequestThread(this); - prt->lock.lock(); - prt->start(); - prt->waitCond.wait(&prt->lock); - prt->lock.unlock(); - threadPool.push_back(prt); - threadPoolAll.push_back(prt); - } + threadPool.setMaxThreadCount(PRT_STARTUP_THREAD_COUNT); masterBackendOverride = gCoreContext->GetNumSetting("MasterBackendOverride", 0); @@ -253,12 +205,16 @@ MainServer::MainServer(bool master, int port, MainServer::~MainServer() { + if (!m_stopped) + Stop(); } void MainServer::Stop() { m_stopped = true; + threadPool.Stop(); + // since Scheduler::SetMainServer() isn't thread-safe // we need to shut down the scheduler thread before we // can call SetMainServer(NULL) @@ -283,21 +239,6 @@ void MainServer::Stop() if (m_expirer) m_expirer->SetMainServer(NULL); - - QMutexLocker locker(&threadPoolLock); - threadPool.clear(); - - MythDeque::iterator it, it2; - for (it = threadPoolAll.begin(); it != threadPoolAll.end(); ++it) - (*it)->killit(); - for (it = threadPoolAll.begin(); it != threadPoolAll.end(); ++it) - { - locker.unlock(); - (*it)->wait(); - delete (*it); - locker.relock(); - } - threadPoolAll.clear(); } void MainServer::autoexpireUpdate(void) @@ -319,37 +260,9 @@ void MainServer::readyRead(MythSocket *sock) if (expecting_reply) return; - ProcessRequestThread *prt = NULL; - { - QMutexLocker locker(&threadPoolLock); - if (m_stopped) - return; - - if (threadPool.empty()) - { - LOG(VB_GENERAL, LOG_NOTICE, - "ThreadPool exhausted. Waiting for a process request thread.."); - threadPoolCond.wait(&threadPoolLock, PRT_TIMEOUT); - } - - if (!threadPool.empty()) - { - prt = threadPool.front(); - threadPool.pop_front(); - } - else - { - LOG(VB_GENERAL, LOG_NOTICE, "Adding a new process request thread"); - prt = new ProcessRequestThread(this); - prt->lock.lock(); - prt->start(); - prt->waitCond.wait(&prt->lock); - prt->lock.unlock(); - threadPoolAll.push_back(prt); - } - } - - prt->setup(sock); + threadPool.startReserved( + new ProcessRequestRunnable(*this, sock), + "ProcessRequest", PRT_TIMEOUT); } void MainServer::ProcessRequest(MythSocket *sock) @@ -795,13 +708,6 @@ void MainServer::ProcessRequestWork(MythSocket *sock) pbs->DownRef(); } -void MainServer::MarkUnused(ProcessRequestThread *prt) -{ - QMutexLocker locker(&threadPoolLock); - threadPool.push_back(prt); - threadPoolCond.wakeAll(); -} - void MainServer::customEvent(QEvent *e) { QStringList broadcast; diff --git a/mythtv/programs/mythbackend/mainserver.h b/mythtv/programs/mythbackend/mainserver.h index ff3d372dac0..1251f4b323f 100644 --- a/mythtv/programs/mythbackend/mainserver.h +++ b/mythtv/programs/mythbackend/mainserver.h @@ -28,7 +28,6 @@ using namespace std; #undef DeleteFile #endif -class ProcessRequestThread; class QUrl; class MythServer; class QTimer; @@ -105,7 +104,6 @@ class MainServer : public QObject, public MythSocketCBs void ShutSlaveBackendsDown(QString &haltcmd); void ProcessRequest(MythSocket *sock); - void MarkUnused(ProcessRequestThread *prt); void readyRead(MythSocket *socket); void connectionClosed(MythSocket *socket); @@ -271,10 +269,7 @@ class MainServer : public QObject, public MythSocketCBs bool ismaster; QMutex deletelock; - QMutex threadPoolLock; - QWaitCondition threadPoolCond; - MythDeque threadPool; - MythDeque threadPoolAll; + MThreadPool threadPool; bool masterBackendOverride; From 37961e22c72ac25d2b9ecb9476567b548aec92bb Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sun, 7 Aug 2011 14:30:09 -0400 Subject: [PATCH 39/49] Convert UPnP to MThreadPool --- mythtv/libs/libmythupnp/eventing.cpp | 2 +- mythtv/libs/libmythupnp/eventing.h | 2 +- mythtv/libs/libmythupnp/htmlserver.cpp | 2 +- mythtv/libs/libmythupnp/htmlserver.h | 2 +- mythtv/libs/libmythupnp/httprequest.cpp | 6 +- mythtv/libs/libmythupnp/httpserver.cpp | 149 ++++++------------ mythtv/libs/libmythupnp/httpserver.h | 130 +++++++-------- mythtv/libs/libmythupnp/libmythupnp.pro | 6 +- mythtv/libs/libmythupnp/servicehost.cpp | 2 +- mythtv/libs/libmythupnp/servicehost.h | 2 +- mythtv/libs/libmythupnp/ssdp.cpp | 2 +- mythtv/libs/libmythupnp/ssdp.h | 2 +- mythtv/libs/libmythupnp/upnp.cpp | 2 +- mythtv/libs/libmythupnp/upnpcds.cpp | 4 +- mythtv/libs/libmythupnp/upnpcds.h | 2 +- mythtv/libs/libmythupnp/upnpcmgr.cpp | 4 +- mythtv/libs/libmythupnp/upnpcmgr.h | 2 +- mythtv/libs/libmythupnp/upnpmsrr.cpp | 5 +- mythtv/libs/libmythupnp/upnpmsrr.h | 3 +- mythtv/libs/libmythupnp/upnpsubscription.cpp | 4 +- mythtv/libs/libmythupnp/upnpsubscription.h | 3 +- mythtv/libs/libmythupnp/upnptasknotify.cpp | 2 +- mythtv/libs/libmythupnp/upnptasksearch.cpp | 2 +- mythtv/programs/mythbackend/httpconfig.cpp | 2 +- mythtv/programs/mythbackend/httpconfig.h | 2 +- mythtv/programs/mythbackend/httpstatus.cpp | 3 +- mythtv/programs/mythbackend/httpstatus.h | 3 +- .../programs/mythbackend/internetContent.cpp | 3 +- mythtv/programs/mythbackend/internetContent.h | 2 +- mythtv/programs/mythbackend/mediaserver.cpp | 1 - .../programs/mythfrontend/mediarenderer.cpp | 19 +-- mythtv/programs/mythfrontend/mythfexml.cpp | 2 +- mythtv/programs/mythfrontend/mythfexml.h | 2 +- 33 files changed, 149 insertions(+), 230 deletions(-) diff --git a/mythtv/libs/libmythupnp/eventing.cpp b/mythtv/libs/libmythupnp/eventing.cpp index 5344b1cb65a..4d3adb95252 100644 --- a/mythtv/libs/libmythupnp/eventing.cpp +++ b/mythtv/libs/libmythupnp/eventing.cpp @@ -157,7 +157,7 @@ QStringList Eventing::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool Eventing::ProcessRequest( HttpWorkerThread * /*pThread*/, HTTPRequest *pRequest ) +bool Eventing::ProcessRequest( HTTPRequest *pRequest ) { if (pRequest) { diff --git a/mythtv/libs/libmythupnp/eventing.h b/mythtv/libs/libmythupnp/eventing.h index 56dd26e3547..7291fefdbc5 100644 --- a/mythtv/libs/libmythupnp/eventing.h +++ b/mythtv/libs/libmythupnp/eventing.h @@ -299,7 +299,7 @@ class UPNP_PUBLIC Eventing : public HttpServerExtension, virtual QStringList GetBasePaths(); - virtual bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + virtual bool ProcessRequest( HTTPRequest *pRequest ); short HoldEvents ( ); short ReleaseEvents ( ); diff --git a/mythtv/libs/libmythupnp/htmlserver.cpp b/mythtv/libs/libmythupnp/htmlserver.cpp index 5e8891b1a46..121b9640e9e 100644 --- a/mythtv/libs/libmythupnp/htmlserver.cpp +++ b/mythtv/libs/libmythupnp/htmlserver.cpp @@ -66,7 +66,7 @@ HtmlServerExtension::~HtmlServerExtension( ) // ///////////////////////////////////////////////////////////////////////////// -bool HtmlServerExtension::ProcessRequest( HttpWorkerThread *, HTTPRequest *pRequest ) +bool HtmlServerExtension::ProcessRequest( HTTPRequest *pRequest ) { if (pRequest) { diff --git a/mythtv/libs/libmythupnp/htmlserver.h b/mythtv/libs/libmythupnp/htmlserver.h index 7026e8b71b9..5e29042a3fd 100644 --- a/mythtv/libs/libmythupnp/htmlserver.h +++ b/mythtv/libs/libmythupnp/htmlserver.h @@ -51,7 +51,7 @@ class UPNP_PUBLIC HtmlServerExtension : public HttpServerExtension virtual QStringList GetBasePaths() { return QStringList(); } - bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + bool ProcessRequest( HTTPRequest *pRequest ); QScriptEngine* ScriptEngine() { diff --git a/mythtv/libs/libmythupnp/httprequest.cpp b/mythtv/libs/libmythupnp/httprequest.cpp index dd72cc451b8..75d63660eea 100644 --- a/mythtv/libs/libmythupnp/httprequest.cpp +++ b/mythtv/libs/libmythupnp/httprequest.cpp @@ -180,9 +180,9 @@ QString HTTPRequest::BuildHeader( long long nSize ) sHeader = QString( "HTTP/%1.%2 %3\r\n" "Date: %4\r\n" "Server: %5, UPnP/1.0, MythTV %6\r\n" ) - .arg(m_nMajor) .arg(m_nMinor) .arg(GetResponseStatus()) - .arg(QDateTime::currentDateTime().toString("d MMM yyyy hh:mm:ss")) - .arg(HttpServer::g_sPlatform) .arg(MYTH_BINARY_VERSION); + .arg(m_nMajor).arg(m_nMinor).arg(GetResponseStatus()) + .arg(QDateTime::currentDateTime().toString("d MMM yyyy hh:mm:ss")) + .arg(HttpServer::GetPlatform()).arg(MYTH_BINARY_VERSION); sHeader += GetAdditionalHeaders(); diff --git a/mythtv/libs/libmythupnp/httpserver.cpp b/mythtv/libs/libmythupnp/httpserver.cpp index 579234cfb26..76457140605 100644 --- a/mythtv/libs/libmythupnp/httpserver.cpp +++ b/mythtv/libs/libmythupnp/httpserver.cpp @@ -51,51 +51,40 @@ ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -QString HttpServer::g_sPlatform; +QMutex HttpServer::s_platformLock; +QString HttpServer::s_platform; ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// -HttpServer::HttpServer() : QTcpServer(), ThreadPool("HTTP") +HttpServer::HttpServer() : + QTcpServer(), m_sSharePath(GetShareDir()), + m_pHtmlServer(new HtmlServerExtension(m_sSharePath)), + m_threadPool("HttpServerPool"), m_running(true) { setMaxPendingConnections(20); - InitializeThreads(); // ---------------------------------------------------------------------- // Build Platform String // ---------------------------------------------------------------------- - + { + QMutexLocker locker(&s_platformLock); #ifdef USING_MINGW - g_sPlatform = QString( "Windows %1.%2" ) - .arg(LOBYTE(LOWORD(GetVersion()))) - .arg(HIBYTE(LOWORD(GetVersion()))); + s_platform = QString("Windows %1.%2") + .arg(LOBYTE(LOWORD(GetVersion()))) + .arg(HIBYTE(LOWORD(GetVersion()))); #else - struct utsname uname_info; - - uname( &uname_info ); - - g_sPlatform = QString( "%1 %2" ).arg( uname_info.sysname ) - .arg( uname_info.release ); + struct utsname uname_info; + uname( &uname_info ); + s_platform = QString("%1 %2") + .arg(uname_info.sysname).arg(uname_info.release); #endif + } - // ---------------------------------------------------------------------- - // Initialize Share Path - // ---------------------------------------------------------------------- - - m_sSharePath = GetShareDir(); LOG(VB_UPNP, LOG_INFO, QString("HttpServer() - SharePath = %1") .arg(m_sSharePath)); - // ---------------------------------------------------------------------- - // The HtmlServer Extension is our fall back if a request isn't processed - // by any other extension. (This is needed here since it listens for - // '/' as it's base url ). - // ---------------------------------------------------------------------- - - m_pHtmlServer = new HtmlServerExtension( m_sSharePath ); - - // -=>TODO: Load Config XML // -=>TODO: Load & initialize - HttpServerExtensions } @@ -106,6 +95,12 @@ HttpServer::HttpServer() : QTcpServer(), ThreadPool("HTTP") HttpServer::~HttpServer() { + m_rwlock.lockForWrite(); + m_running = false; + m_rwlock.unlock(); + + m_threadPool.Stop(); + while (!m_extensions.empty()) { delete m_extensions.takeFirst(); @@ -119,19 +114,19 @@ HttpServer::~HttpServer() // ///////////////////////////////////////////////////////////////////////////// -QScriptEngine* HttpServer::ScriptEngine() +QString HttpServer::GetPlatform(void) { - return ((HtmlServerExtension *)m_pHtmlServer)->ScriptEngine(); + QMutexLocker locker(&s_platformLock); + return s_platform; } ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// -WorkerThread *HttpServer::CreateWorkerThread( ThreadPool * /*pThreadPool */, - const QString &sName ) +QScriptEngine* HttpServer::ScriptEngine() { - return( new HttpWorkerThread( this, sName )); + return ((HtmlServerExtension *)m_pHtmlServer)->ScriptEngine(); } ///////////////////////////////////////////////////////////////////////////// @@ -140,10 +135,9 @@ WorkerThread *HttpServer::CreateWorkerThread( ThreadPool * /*pThreadPool */, void HttpServer::incomingConnection(int nSocket) { - HttpWorkerThread *pThread = (HttpWorkerThread *)GetWorkerThread(); - - if (pThread != NULL) - pThread->StartWork( nSocket ); + m_threadPool.startReserved( + new HttpWorker(*this, nSocket), + QString("HttpServer%1").arg(nSocket)); } ///////////////////////////////////////////////////////////////////////////// @@ -195,7 +189,7 @@ void HttpServer::UnregisterExtension( HttpServerExtension *pExtension ) // ///////////////////////////////////////////////////////////////////////////// -void HttpServer::DelegateRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ) +void HttpServer::DelegateRequest(HTTPRequest *pRequest) { bool bProcessed = false; @@ -207,7 +201,7 @@ void HttpServer::DelegateRequest( HttpWorkerThread *pThread, HTTPRequest *pReque { try { - bProcessed = list[ nIdx ]->ProcessRequest(pThread, pRequest); + bProcessed = list[ nIdx ]->ProcessRequest(pRequest); } catch(...) { @@ -224,7 +218,7 @@ void HttpServer::DelegateRequest( HttpWorkerThread *pThread, HTTPRequest *pReque { try { - bProcessed = (*it)->ProcessRequest(pThread, pRequest); + bProcessed = (*it)->ProcessRequest(pRequest); } catch(...) { @@ -237,7 +231,7 @@ void HttpServer::DelegateRequest( HttpWorkerThread *pThread, HTTPRequest *pReque m_rwlock.unlock(); if (!bProcessed) - bProcessed = m_pHtmlServer->ProcessRequest( pThread, pRequest ); + bProcessed = m_pHtmlServer->ProcessRequest(pRequest); if (!bProcessed) { @@ -254,67 +248,22 @@ void HttpServer::DelegateRequest( HttpWorkerThread *pThread, HTTPRequest *pReque ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -HttpWorkerThread::HttpWorkerThread( HttpServer *pParent, const QString &sName ) : - WorkerThread( (ThreadPool *)pParent, sName ) +HttpWorker::HttpWorker(HttpServer &httpServer, int sock) : + m_httpServer(httpServer), m_socket(sock), m_socketTimeout(10000) { - m_pHttpServer = pParent; - m_nSocket = 0; - m_nSocketTimeout = 1000 * + m_socketTimeout = 1000 * UPnp::GetConfiguration()->GetValue("HTTP/KeepAliveTimeoutSecs", 10); - - m_pData = NULL; } ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// -HttpWorkerThread::~HttpWorkerThread() -{ - if (m_pData != NULL) - delete m_pData; -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void HttpWorkerThread::SetWorkerData( HttpWorkerData *pData ) -{ - // WorkerThread takes ownership of pData pointer. - // (Must be allocated on heap) - - if (m_pData != NULL) - delete m_pData; - - m_pData = pData; -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void HttpWorkerThread::StartWork( int nSocket ) -{ - m_nSocket = nSocket; - - SignalWork(); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void HttpWorkerThread::ProcessWork() +void HttpWorker::run(void) { #if 0 LOG(VB_UPNP, LOG_DEBUG, - QString("HttpWorkerThread::ProcessWork:Begin( %1 ) socket=%2") - .arg((long)QThread::currentThread()) .arg(m_nSocket)); + QString("HttpWorker::run() socket=%1 -- begin").arg(m_socket)); #endif bool bTimeout = false; @@ -324,7 +273,7 @@ void HttpWorkerThread::ProcessWork() try { - if ((pSocket = new BufferedSocketDevice( m_nSocket )) == NULL) + if ((pSocket = new BufferedSocketDevice( m_socket )) == NULL) { LOG(VB_GENERAL, LOG_ERR, "Error Creating BufferedSocketDevice"); return; @@ -332,11 +281,13 @@ void HttpWorkerThread::ProcessWork() pSocket->SocketDevice()->setBlocking( true ); - while( !m_bTermRequested && bKeepAlive && pSocket->IsValid()) + while (m_httpServer.IsRunning() && bKeepAlive && pSocket->IsValid()) { - bTimeout = 0; + bTimeout = false; - int64_t nBytes = pSocket->WaitForMore(m_nSocketTimeout, &bTimeout); + int64_t nBytes = pSocket->WaitForMore(m_socketTimeout, &bTimeout); + if (!m_httpServer.IsRunning()) + break; if ( nBytes > 0) { @@ -357,7 +308,7 @@ void HttpWorkerThread::ProcessWork() // ------------------------------------------------------ if (pRequest->m_nResponseStatus != 401) - m_pHttpServer->DelegateRequest( this, pRequest ); + m_httpServer.DelegateRequest(pRequest); } else { @@ -391,7 +342,7 @@ void HttpWorkerThread::ProcessWork() LOG(VB_UPNP, LOG_ERR, QString("socket(%1) - Error returned from " "SendResponse... Closing connection") - .arg(m_nSocket)); + .arg(m_socket)); } // ------------------------------------------------------- @@ -429,12 +380,10 @@ void HttpWorkerThread::ProcessWork() pSocket->Close(); delete pSocket; - m_nSocket = 0; + m_socket = 0; #if 0 - LOG(VB_UPNP, LOG_DEBUG, - QString( "HttpWorkerThread::ProcessWork:End( %1 )") - .arg((long)QThread::currentThread())); + LOG(VB_UPNP, LOG_DEBUG, "HttpWorkerThread::run() -- end"); #endif } diff --git a/mythtv/libs/libmythupnp/httpserver.h b/mythtv/libs/libmythupnp/httpserver.h index a6b3cf3ab68..d71cab6847c 100644 --- a/mythtv/libs/libmythupnp/httpserver.h +++ b/mythtv/libs/libmythupnp/httpserver.h @@ -36,12 +36,16 @@ #include #include #include +#include +#include +#include +#include // MythTV headers -#include "upnputil.h" #include "httprequest.h" -#include "threadpool.h" +#include "mthreadpool.h" #include "refcounted.h" +#include "upnputil.h" #include "compat.h" typedef struct timeval TaskTime; @@ -74,8 +78,7 @@ class UPNP_PUBLIC HttpServerExtension : public QObject virtual ~HttpServerExtension() {}; - virtual bool ProcessRequest( HttpWorkerThread *pThread, - HTTPRequest *pRequest ) = 0; + virtual bool ProcessRequest(HTTPRequest *pRequest) = 0; virtual QStringList GetBasePaths() = 0; }; @@ -90,58 +93,47 @@ typedef QList > HttpServerExtensionList; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -class UPNP_PUBLIC HttpServer : public QTcpServer, - public ThreadPool -{ - - protected: - - QReadWriteLock m_rwlock; - HttpServerExtensionList m_extensions; - - // This multimap does NOT take ownership of the HttpServerExtension* - QMultiMap< QString, HttpServerExtension* > m_basePaths; - - HttpServerExtension* m_pHtmlServer; - - virtual WorkerThread *CreateWorkerThread( ThreadPool *, - const QString &sName ); - virtual void incomingConnection ( int socket ); - - public: - - static QString g_sPlatform; - QString m_sSharePath; - - public: - - HttpServer(); - virtual ~HttpServer(); - - void RegisterExtension ( HttpServerExtension *pExtension ); - void UnregisterExtension( HttpServerExtension *pExtension ); - - void DelegateRequest ( HttpWorkerThread *pThread, - HTTPRequest *pRequest ); - - QScriptEngine* ScriptEngine(); - -}; - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// Base class for WorkerThread Specific data -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -class UPNP_PUBLIC HttpWorkerData +class UPNP_PUBLIC HttpServer : public QTcpServer { - public: - - HttpWorkerData() {}; - virtual ~HttpWorkerData() {}; + protected: + mutable QReadWriteLock m_rwlock; + HttpServerExtensionList m_extensions; + // This multimap does NOT take ownership of the HttpServerExtension* + QMultiMap< QString, HttpServerExtension* > m_basePaths; + QString m_sSharePath; + HttpServerExtension *m_pHtmlServer; + MThreadPool m_threadPool; + bool m_running; // protected by m_rwlock + + static QMutex s_platformLock; + static QString s_platform; + + public: + HttpServer(); + virtual ~HttpServer(); + + void RegisterExtension(HttpServerExtension*); + void UnregisterExtension(HttpServerExtension*); + void DelegateRequest(HTTPRequest*); + + QScriptEngine *ScriptEngine(void); + + virtual void incomingConnection(int socket); // QTcpServer + + QString GetSharePath(void) const + { // never modified after creation, so no need to lock + return m_sSharePath; + } + + bool IsRunning(void) const + { + m_rwlock.lockForRead(); + bool tmp = m_running; + m_rwlock.unlock(); + return tmp; + } + + static QString GetPlatform(void); }; ///////////////////////////////////////////////////////////////////////////// @@ -152,29 +144,17 @@ class UPNP_PUBLIC HttpWorkerData ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -class UPNP_PUBLIC HttpWorkerThread : public WorkerThread +class HttpWorker : public QRunnable { - protected: - - HttpServer *m_pHttpServer; - int m_nSocket; - int m_nSocketTimeout; - - HttpWorkerData *m_pData; - - protected: - - virtual void ProcessWork(); - - public: - - HttpWorkerThread( HttpServer *pParent, const QString &sName ); - virtual ~HttpWorkerThread(); + public: + HttpWorker(HttpServer &httpServer, int sock); - void StartWork( int nSocket ); + virtual void run(void); - void SetWorkerData( HttpWorkerData *pData ); - HttpWorkerData *GetWorkerData( ) { return( m_pData ); } + protected: + HttpServer &m_httpServer; + int m_socket; + int m_socketTimeout; }; diff --git a/mythtv/libs/libmythupnp/libmythupnp.pro b/mythtv/libs/libmythupnp/libmythupnp.pro index bc6613a7404..ec48bfb70cf 100644 --- a/mythtv/libs/libmythupnp/libmythupnp.pro +++ b/mythtv/libs/libmythupnp/libmythupnp.pro @@ -19,7 +19,7 @@ QMAKE_CLEAN += version.cpp HEADERS += mmulticastsocketdevice.h mbroadcastsocketdevice.h HEADERS += httprequest.h upnp.h ssdp.h taskqueue.h upnpsubscription.h -HEADERS += upnpdevice.h upnptasknotify.h upnptasksearch.h threadpool.h upnputil.h +HEADERS += upnpdevice.h upnptasknotify.h upnptasksearch.h upnputil.h HEADERS += httpserver.h upnpcds.h upnpcdsobjects.h bufferedsocketdevice.h upnpmsrr.h HEADERS += eventing.h upnpcmgr.h upnptaskevent.h upnptaskcache.h ssdpcache.h HEADERS += configuration.h @@ -32,7 +32,7 @@ HEADERS += serializers/jsonSerializer.h serializers/soapSerializer.h SOURCES += mmulticastsocketdevice.cpp SOURCES += httprequest.cpp upnp.cpp ssdp.cpp taskqueue.cpp upnputil.cpp -SOURCES += upnpdevice.cpp upnptasknotify.cpp upnptasksearch.cpp threadpool.cpp +SOURCES += upnpdevice.cpp upnptasknotify.cpp upnptasksearch.cpp SOURCES += httpserver.cpp upnpcds.cpp upnpcdsobjects.cpp bufferedsocketdevice.cpp SOURCES += eventing.cpp upnpcmgr.cpp upnpmsrr.cpp upnptaskevent.cpp ssdpcache.cpp SOURCES += configuration.cpp soapclient.cpp mythxmlclient.cpp mmembuf.cpp @@ -60,7 +60,7 @@ mingw { inc.path = $${PREFIX}/include/mythtv/upnp/ inc.files = httprequest.h upnp.h ssdp.h taskqueue.h bufferedsocketdevice.h -inc.files += upnpdevice.h upnptasknotify.h upnptasksearch.h threadpool.h upnputil.h +inc.files += upnpdevice.h upnptasknotify.h upnptasksearch.h upnputil.h inc.files += httpserver.h httpstatus.h upnpcds.h upnpcdsobjects.h inc.files += eventing.h upnpcmgr.h upnptaskevent.h upnptaskcache.h ssdpcache.h inc.files += upnpimpl.h configuration.h diff --git a/mythtv/libs/libmythupnp/servicehost.cpp b/mythtv/libs/libmythupnp/servicehost.cpp index f74efb6256c..d39941d8797 100644 --- a/mythtv/libs/libmythupnp/servicehost.cpp +++ b/mythtv/libs/libmythupnp/servicehost.cpp @@ -274,7 +274,7 @@ QStringList ServiceHost::GetBasePaths() // ////////////////////////////////////////////////////////////////////////////// -bool ServiceHost::ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ) +bool ServiceHost::ProcessRequest( HTTPRequest *pRequest ) { bool bHandled = false; Service *pService = NULL; diff --git a/mythtv/libs/libmythupnp/servicehost.h b/mythtv/libs/libmythupnp/servicehost.h index f8aa40234fd..ff207739015 100644 --- a/mythtv/libs/libmythupnp/servicehost.h +++ b/mythtv/libs/libmythupnp/servicehost.h @@ -93,7 +93,7 @@ class UPNP_PUBLIC ServiceHost : public HttpServerExtension virtual QStringList GetBasePaths(); - virtual bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + virtual bool ProcessRequest( HTTPRequest *pRequest ); virtual QString GetServiceControlURL() { return m_sBaseUrl.mid( 1 ); } diff --git a/mythtv/libs/libmythupnp/ssdp.cpp b/mythtv/libs/libmythupnp/ssdp.cpp index 104e945784c..9cbe457518e 100644 --- a/mythtv/libs/libmythupnp/ssdp.cpp +++ b/mythtv/libs/libmythupnp/ssdp.cpp @@ -678,7 +678,7 @@ QStringList SSDPExtension::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool SSDPExtension::ProcessRequest( HttpWorkerThread *, HTTPRequest *pRequest ) +bool SSDPExtension::ProcessRequest( HTTPRequest *pRequest ) { if (pRequest) { diff --git a/mythtv/libs/libmythupnp/ssdp.h b/mythtv/libs/libmythupnp/ssdp.h index 43f32e93f2a..01c3262fcb5 100644 --- a/mythtv/libs/libmythupnp/ssdp.h +++ b/mythtv/libs/libmythupnp/ssdp.h @@ -172,7 +172,7 @@ class SSDPExtension : public HttpServerExtension virtual QStringList GetBasePaths(); - bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + bool ProcessRequest( HTTPRequest *pRequest ); }; #endif diff --git a/mythtv/libs/libmythupnp/upnp.cpp b/mythtv/libs/libmythupnp/upnp.cpp index be0235ab19f..e5c14bf1e75 100644 --- a/mythtv/libs/libmythupnp/upnp.cpp +++ b/mythtv/libs/libmythupnp/upnp.cpp @@ -132,7 +132,7 @@ bool UPnp::Initialize( QStringList &sIPAddrList, int nServicePort, HttpServer *p // ---------------------------------------------------------------------- m_pHttpServer->RegisterExtension( - new SSDPExtension( m_nServicePort, m_pHttpServer->m_sSharePath)); + new SSDPExtension(m_nServicePort, m_pHttpServer->GetSharePath())); LOG(VB_UPNP, LOG_DEBUG, "UPnp::Initialize - End"); diff --git a/mythtv/libs/libmythupnp/upnpcds.cpp b/mythtv/libs/libmythupnp/upnpcds.cpp index eadf9e7bad6..26ce74934a9 100644 --- a/mythtv/libs/libmythupnp/upnpcds.cpp +++ b/mythtv/libs/libmythupnp/upnpcds.cpp @@ -165,11 +165,11 @@ QStringList UPnpCDS::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool UPnpCDS::ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ) +bool UPnpCDS::ProcessRequest( HTTPRequest *pRequest ) { if (pRequest) { - if (Eventing::ProcessRequest( pThread, pRequest )) + if (Eventing::ProcessRequest( pRequest )) return true; if ( pRequest->m_sBaseUrl != m_sControlUrl ) diff --git a/mythtv/libs/libmythupnp/upnpcds.h b/mythtv/libs/libmythupnp/upnpcds.h index 446f2327b38..ed3b094b323 100644 --- a/mythtv/libs/libmythupnp/upnpcds.h +++ b/mythtv/libs/libmythupnp/upnpcds.h @@ -294,7 +294,7 @@ class UPNP_PUBLIC UPnpCDS : public Eventing virtual QStringList GetBasePaths(); - virtual bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + virtual bool ProcessRequest( HTTPRequest *pRequest ); }; #endif diff --git a/mythtv/libs/libmythupnp/upnpcmgr.cpp b/mythtv/libs/libmythupnp/upnpcmgr.cpp index a66e354ff2e..b0afd943b2b 100644 --- a/mythtv/libs/libmythupnp/upnpcmgr.cpp +++ b/mythtv/libs/libmythupnp/upnpcmgr.cpp @@ -121,11 +121,11 @@ QStringList UPnpCMGR::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool UPnpCMGR::ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ) +bool UPnpCMGR::ProcessRequest( HTTPRequest *pRequest ) { if (pRequest) { - if (Eventing::ProcessRequest( pThread, pRequest )) + if (Eventing::ProcessRequest( pRequest )) return true; if ( pRequest->m_sBaseUrl != m_sControlUrl ) diff --git a/mythtv/libs/libmythupnp/upnpcmgr.h b/mythtv/libs/libmythupnp/upnpcmgr.h index eefa00a278b..566504ff63e 100644 --- a/mythtv/libs/libmythupnp/upnpcmgr.h +++ b/mythtv/libs/libmythupnp/upnpcmgr.h @@ -92,7 +92,7 @@ class UPNP_PUBLIC UPnpCMGR : public Eventing virtual QStringList GetBasePaths(); - virtual bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + virtual bool ProcessRequest( HTTPRequest *pRequest ); }; #endif diff --git a/mythtv/libs/libmythupnp/upnpmsrr.cpp b/mythtv/libs/libmythupnp/upnpmsrr.cpp index 764fb151630..17769978074 100644 --- a/mythtv/libs/libmythupnp/upnpmsrr.cpp +++ b/mythtv/libs/libmythupnp/upnpmsrr.cpp @@ -83,12 +83,11 @@ QStringList UPnpMSRR::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool UPnpMSRR::ProcessRequest( HttpWorkerThread *pThread, - HTTPRequest *pRequest ) +bool UPnpMSRR::ProcessRequest( HTTPRequest *pRequest ) { if (pRequest) { - if (Eventing::ProcessRequest( pThread, pRequest )) + if (Eventing::ProcessRequest( pRequest )) return true; if ( pRequest->m_sBaseUrl != m_sControlUrl ) diff --git a/mythtv/libs/libmythupnp/upnpmsrr.h b/mythtv/libs/libmythupnp/upnpmsrr.h index 63cc30e8510..7ad00e70661 100644 --- a/mythtv/libs/libmythupnp/upnpmsrr.h +++ b/mythtv/libs/libmythupnp/upnpmsrr.h @@ -1,3 +1,4 @@ + #ifndef UPnpMSRR_H_ #define UPnpMSRR_H_ @@ -56,7 +57,7 @@ class UPNP_PUBLIC UPnpMSRR : public Eventing virtual QStringList GetBasePaths(); - bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + bool ProcessRequest( HTTPRequest *pRequest ); }; #endif diff --git a/mythtv/libs/libmythupnp/upnpsubscription.cpp b/mythtv/libs/libmythupnp/upnpsubscription.cpp index 03965a0c8c5..9614cf1cc3a 100644 --- a/mythtv/libs/libmythupnp/upnpsubscription.cpp +++ b/mythtv/libs/libmythupnp/upnpsubscription.cpp @@ -166,10 +166,8 @@ void UPNPSubscription::Remove(const QString &usn) m_subscriptionLock.unlock(); } -bool UPNPSubscription::ProcessRequest(HttpWorkerThread *pThread, - HTTPRequest *pRequest) +bool UPNPSubscription::ProcessRequest(HTTPRequest *pRequest) { - (void)pThread; if (!pRequest) return false; diff --git a/mythtv/libs/libmythupnp/upnpsubscription.h b/mythtv/libs/libmythupnp/upnpsubscription.h index 864e4da4f76..af9ab147788 100644 --- a/mythtv/libs/libmythupnp/upnpsubscription.h +++ b/mythtv/libs/libmythupnp/upnpsubscription.h @@ -28,8 +28,7 @@ class UPNP_PUBLIC UPNPSubscription : public HttpServerExtension, public MythObse virtual ~UPNPSubscription(); virtual QStringList GetBasePaths() { return QStringList( "/Subscriptions" ); } - virtual bool ProcessRequest(HttpWorkerThread *pThread, - HTTPRequest *pRequest); + virtual bool ProcessRequest(HTTPRequest *pRequest); int Subscribe(const QString &usn, const QUrl &url, const QString &path); void Unsubscribe(const QString &usn); diff --git a/mythtv/libs/libmythupnp/upnptasknotify.cpp b/mythtv/libs/libmythupnp/upnptasknotify.cpp index 202c3f5146a..d0737a768d6 100644 --- a/mythtv/libs/libmythupnp/upnptasknotify.cpp +++ b/mythtv/libs/libmythupnp/upnptasknotify.cpp @@ -85,7 +85,7 @@ void UPnpNotifyTask::SendNotifyMsg( MSocketDevice *pSocket, "USN: %5\r\n" "CACHE-CONTROL: max-age=%6\r\n" "Content-Length: 0\r\n\r\n" ) - .arg( HttpServer::g_sPlatform ) + .arg( HttpServer::GetPlatform() ) .arg( MYTH_BINARY_VERSION ) .arg( GetNTSString() ) .arg( sNT ) diff --git a/mythtv/libs/libmythupnp/upnptasksearch.cpp b/mythtv/libs/libmythupnp/upnptasksearch.cpp index 093a742a319..3db674c430a 100644 --- a/mythtv/libs/libmythupnp/upnptasksearch.cpp +++ b/mythtv/libs/libmythupnp/upnptasksearch.cpp @@ -94,7 +94,7 @@ void UPnpSearchTask::SendMsg( MSocketDevice *pSocket, "Content-Length: 0\r\n\r\n" ) .arg( m_nMaxAge ) .arg( sDate ) - .arg( HttpServer::g_sPlatform ) + .arg( HttpServer::GetPlatform() ) .arg( MYTH_BINARY_VERSION ) .arg( sST ) .arg( sUSN ); diff --git a/mythtv/programs/mythbackend/httpconfig.cpp b/mythtv/programs/mythbackend/httpconfig.cpp index 36c2102051a..b8590158d6b 100644 --- a/mythtv/programs/mythbackend/httpconfig.cpp +++ b/mythtv/programs/mythbackend/httpconfig.cpp @@ -30,7 +30,7 @@ QStringList HttpConfig::GetBasePaths() return paths; } -bool HttpConfig::ProcessRequest(HttpWorkerThread*, HTTPRequest *request) +bool HttpConfig::ProcessRequest(HTTPRequest *request) { if (!request) return false; diff --git a/mythtv/programs/mythbackend/httpconfig.h b/mythtv/programs/mythbackend/httpconfig.h index 3cded6d451e..bc61d5e6106 100644 --- a/mythtv/programs/mythbackend/httpconfig.h +++ b/mythtv/programs/mythbackend/httpconfig.h @@ -16,7 +16,7 @@ class HttpConfig : public HttpServerExtension virtual QStringList GetBasePaths(); - bool ProcessRequest(HttpWorkerThread *pThread, HTTPRequest *pRequest); + bool ProcessRequest(HTTPRequest *pRequest); private: static void PrintHeader(QBuffer&, const QString &form, diff --git a/mythtv/programs/mythbackend/httpstatus.cpp b/mythtv/programs/mythbackend/httpstatus.cpp index 6328bbb9ba9..01964700a09 100644 --- a/mythtv/programs/mythbackend/httpstatus.cpp +++ b/mythtv/programs/mythbackend/httpstatus.cpp @@ -94,8 +94,7 @@ QStringList HttpStatus::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool HttpStatus::ProcessRequest( HttpWorkerThread * /* pThread */, - HTTPRequest *pRequest ) +bool HttpStatus::ProcessRequest( HTTPRequest *pRequest ) { try { diff --git a/mythtv/programs/mythbackend/httpstatus.h b/mythtv/programs/mythbackend/httpstatus.h index 5e9d2f032ee..b80a99f0a22 100644 --- a/mythtv/programs/mythbackend/httpstatus.h +++ b/mythtv/programs/mythbackend/httpstatus.h @@ -90,8 +90,7 @@ class HttpStatus : public HttpServerExtension virtual QStringList GetBasePaths(); - bool ProcessRequest( HttpWorkerThread *pThread, - HTTPRequest *pRequest ); + bool ProcessRequest( HTTPRequest *pRequest ); }; #endif diff --git a/mythtv/programs/mythbackend/internetContent.cpp b/mythtv/programs/mythbackend/internetContent.cpp index 014e407cb84..f1a5f01e58c 100644 --- a/mythtv/programs/mythbackend/internetContent.cpp +++ b/mythtv/programs/mythbackend/internetContent.cpp @@ -56,8 +56,7 @@ QStringList InternetContent::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool InternetContent::ProcessRequest( HttpWorkerThread *pThread, - HTTPRequest *pRequest ) +bool InternetContent::ProcessRequest( HTTPRequest *pRequest ) { try { diff --git a/mythtv/programs/mythbackend/internetContent.h b/mythtv/programs/mythbackend/internetContent.h index a976a1ec107..8ba21d9e0fc 100644 --- a/mythtv/programs/mythbackend/internetContent.h +++ b/mythtv/programs/mythbackend/internetContent.h @@ -41,7 +41,7 @@ class InternetContent : public HttpServerExtension virtual QStringList GetBasePaths(); - bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + bool ProcessRequest( HTTPRequest *pRequest ); }; diff --git a/mythtv/programs/mythbackend/mediaserver.cpp b/mythtv/programs/mythbackend/mediaserver.cpp index 3c1964dd997..eeaa9c6ca26 100644 --- a/mythtv/programs/mythbackend/mediaserver.cpp +++ b/mythtv/programs/mythbackend/mediaserver.cpp @@ -67,7 +67,6 @@ void MediaServer::Init(bool bIsMaster, bool bDisableUPnp /* = FALSE */) if (!m_pHttpServer) { m_pHttpServer = new HttpServer(); - m_pHttpServer->m_sSharePath = m_sSharePath; m_pHttpServer->RegisterExtension(new HttpConfig()); } diff --git a/mythtv/programs/mythfrontend/mediarenderer.cpp b/mythtv/programs/mythfrontend/mediarenderer.cpp index 9e1cf80d8cc..ae25aa164d6 100644 --- a/mythtv/programs/mythfrontend/mediarenderer.cpp +++ b/mythtv/programs/mythfrontend/mediarenderer.cpp @@ -26,11 +26,8 @@ class MythFrontendStatus : public HttpServerExtension virtual QStringList GetBasePaths() { return QStringList( "/" ); } - virtual bool ProcessRequest(HttpWorkerThread *pThread, - HTTPRequest *pRequest) + virtual bool ProcessRequest(HTTPRequest *pRequest) { - (void)pThread; - if (!pRequest) return false; @@ -253,7 +250,7 @@ MediaRenderer::MediaRenderer() LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Registering MythFrontendStatus service."); m_pHttpServer->RegisterExtension( - new MythFrontendStatus(m_pHttpServer->m_sSharePath)); + new MythFrontendStatus(m_pHttpServer->GetSharePath())); QString sSinkProtocols = "http-get:*:image/gif:*," "http-get:*:image/jpeg:*," @@ -268,8 +265,8 @@ MediaRenderer::MediaRenderer() // Register the MythFEXML protocol... // ------------------------------------------------------------------ LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Registering MythFEXML Service."); - m_pHttpServer->RegisterExtension( new MythFEXML( RootDevice(), - m_pHttpServer->m_sSharePath)); + m_pHttpServer->RegisterExtension( + new MythFEXML(RootDevice(), m_pHttpServer->GetSharePath())); #if 0 LOG(VB_UPNP, LOG_INFO, @@ -280,8 +277,8 @@ MediaRenderer::MediaRenderer() LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Registering CMGR Service."); // HttpServer will be responsible for deleting UPnpCMGR - m_pUPnpCMGR = new UPnpCMGR(RootDevice(), m_pHttpServer->m_sSharePath, - "", sSinkProtocols ); + m_pUPnpCMGR = new UPnpCMGR( + RootDevice(), m_pHttpServer->GetSharePath(), "", sSinkProtocols); m_pHttpServer->RegisterExtension( m_pUPnpCMGR ); #if 0 @@ -297,8 +294,8 @@ MediaRenderer::MediaRenderer() LOG(VB_UPNP, LOG_INFO, "MediaRenderer: Registering subscription service."); - subscription = new UPNPSubscription(m_pHttpServer->m_sSharePath, - nPort); + subscription = new UPNPSubscription( + m_pHttpServer->GetSharePath(), nPort); m_pHttpServer->RegisterExtension(subscription); } diff --git a/mythtv/programs/mythfrontend/mythfexml.cpp b/mythtv/programs/mythfrontend/mythfexml.cpp index bacc626ae63..a13c162989f 100644 --- a/mythtv/programs/mythfrontend/mythfexml.cpp +++ b/mythtv/programs/mythfrontend/mythfexml.cpp @@ -83,7 +83,7 @@ QStringList MythFEXML::GetBasePaths() // ///////////////////////////////////////////////////////////////////////////// -bool MythFEXML::ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ) +bool MythFEXML::ProcessRequest( HTTPRequest *pRequest ) { if (!pRequest) return false; diff --git a/mythtv/programs/mythfrontend/mythfexml.h b/mythtv/programs/mythfrontend/mythfexml.h index 4242ad4e3f0..a4337d361aa 100644 --- a/mythtv/programs/mythfrontend/mythfexml.h +++ b/mythtv/programs/mythfrontend/mythfexml.h @@ -64,7 +64,7 @@ class MythFEXML : public Eventing virtual QStringList GetBasePaths(); - bool ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest ); + bool ProcessRequest( HTTPRequest *pRequest ); // Static methods shared with HttpStatus From b5412918430cfc7fd2d2770bdc55d29eff8e5bd3 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Sun, 7 Aug 2011 14:27:21 -0400 Subject: [PATCH 40/49] Convert MythSocketManager thread pool to MThreadPool --- .../libmythprotoserver/mythsocketmanager.cpp | 129 +---- .../libmythprotoserver/mythsocketmanager.h | 14 +- mythtv/libs/libmythupnp/threadpool.cpp | 526 ------------------ mythtv/libs/libmythupnp/threadpool.h | 198 ------- 4 files changed, 19 insertions(+), 848 deletions(-) delete mode 100644 mythtv/libs/libmythupnp/threadpool.cpp delete mode 100644 mythtv/libs/libmythupnp/threadpool.h diff --git a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp index 9918db41649..fe22b474436 100644 --- a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp +++ b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp @@ -10,6 +10,7 @@ using namespace std; #include #include #include +#include // MythTV #include "mythsocketmanager.h" @@ -24,81 +25,36 @@ using namespace std; #define LOC QString("MythSocketManager: ") -#define PRT_STARTUP_THREAD_COUNT 2 #define PRT_TIMEOUT 10 -uint socket_id = 1; - -class ProcessRequestThread : public MThread +class ProcessRequestRunnable : public QRunnable { public: - ProcessRequestThread(MythSocketManager *ms): - MThread("ProcessRequestThread"), - m_parent(ms), m_socket(NULL), m_threadlives(false) {} - - void setup(MythSocket *sock) - { - QMutexLocker locker(&m_lock); - m_socket = sock; - m_socket->UpRef(); - m_waitCond.wakeAll(); - } - - void killit(void) + ProcessRequestRunnable(MythSocketManager &parent, MythSocket *sock) : + m_parent(parent), m_sock(sock) { - QMutexLocker locker(&m_lock); - m_threadlives = false; - m_waitCond.wakeAll(); + m_sock->UpRef(); } virtual void run(void) { - RunProlog(); - - QMutexLocker locker(&m_lock); - m_threadlives = true; - m_waitCond.wakeAll(); // Signal to creating thread - - while (true) - { - m_waitCond.wait(locker.mutex()); - LOG(VB_SOCKET, LOG_DEBUG, "ProcessRequestThread running."); - - if (!m_threadlives) - break; - - if (!m_socket) - { - LOG(VB_SOCKET, LOG_ERR, "ProcessRequestThread has no target."); - continue; - } - - m_parent->ProcessRequest(m_socket); - m_socket->DownRef(); - m_socket = NULL; - m_parent->MarkUnused(this); - } - - RunEpilog(); + m_parent.ProcessRequest(m_sock); + m_sock->DownRef(); } - QMutex m_lock; - QWaitCondition m_waitCond; - - private: - MythSocketManager *m_parent; - MythSocket *m_socket; - bool m_threadlives; + MythSocketManager &m_parent; + MythSocket *m_sock; }; MythSocketManager::MythSocketManager() : - m_server(NULL) + m_server(NULL), m_threadPool("MythSocketManager") { - SetThreadCount(PRT_STARTUP_THREAD_COUNT); } MythSocketManager::~MythSocketManager() { + m_threadPool.Stop(); + QWriteLocker wlock(&m_handlerLock); QMap::iterator i; @@ -108,36 +64,6 @@ MythSocketManager::~MythSocketManager() m_handlerMap.clear(); } -void MythSocketManager::SetThreadCount(uint count) -{ - if (m_threadPool.size() >= count) - return; - - LOG(VB_GENERAL, LOG_ERR, QString("Increasing thread count to %2") - .arg(count)); - while (count > m_threadPool.size()) - { - ProcessRequestThread *prt = new ProcessRequestThread(this); - prt->m_lock.lock(); - prt->start(); - prt->m_waitCond.wait(&prt->m_lock); - prt->m_lock.unlock(); - m_threadPool.push_back(prt); - } -} - -void MythSocketManager::MarkUnused(ProcessRequestThread *prt) -{ - LOG(VB_SOCKET, LOG_DEBUG, "Releasing ProcessRequestThread."); - - QMutexLocker locker(&m_threadPoolLock); - m_threadPool.push_back(prt); - m_threadPoolCond.wakeAll(); - - LOG(VB_SOCKET, LOG_INFO, QString("ProcessRequestThread pool size: %1") - .arg(m_threadPool.size())); -} - bool MythSocketManager::Listen(int port) { if (m_server != NULL) @@ -209,34 +135,9 @@ void MythSocketManager::readyRead(MythSocket *sock) return; } - ProcessRequestThread *prt = NULL; - { - QMutexLocker locker(&m_threadPoolLock); - - if (m_threadPool.empty()) - { - LOG(VB_GENERAL, LOG_INFO, - "Waiting for a process request thread.. "); - m_threadPoolCond.wait(&m_threadPoolLock, PRT_TIMEOUT); - } - - if (!m_threadPool.empty()) - { - prt = m_threadPool.front(); - m_threadPool.pop_front(); - } - else - { - LOG(VB_GENERAL, LOG_INFO, "Adding a new process request thread"); - prt = new ProcessRequestThread(this); - prt->m_lock.lock(); - prt->start(); - prt->m_waitCond.wait(&prt->m_lock); - prt->m_lock.unlock(); - } - } - - prt->setup(sock); + m_threadPool.startReserved( + new ProcessRequestRunnable(*this, sock), + "ServiceRequest", PRT_TIMEOUT); } void MythSocketManager::connectionClosed(MythSocket *sock) diff --git a/mythtv/libs/libmythprotoserver/mythsocketmanager.h b/mythtv/libs/libmythprotoserver/mythsocketmanager.h index 4793cab8405..cc0b2cd7762 100644 --- a/mythtv/libs/libmythprotoserver/mythsocketmanager.h +++ b/mythtv/libs/libmythprotoserver/mythsocketmanager.h @@ -12,13 +12,10 @@ using namespace std; #include // MythTV -#include "mythsocket.h" -#include "mythdeque.h" #include "socketrequesthandler.h" #include "sockethandler.h" - -class ProcessRequestThread; -class MythSocketManager; +#include "mthreadpool.h" +#include "mythsocket.h" class MythServer : public QTcpServer { @@ -44,7 +41,6 @@ class PROTOSERVER_PUBLIC MythSocketManager : public QObject, public MythSocketCB void connected(MythSocket *socket) { (void)socket; } void SetThreadCount(uint count); - void MarkUnused(ProcessRequestThread *prt); void AddSocketHandler(SocketHandler *socket); SocketHandler *GetConnectionBySocket(MythSocket *socket); @@ -62,10 +58,6 @@ class PROTOSERVER_PUBLIC MythSocketManager : public QObject, public MythSocketCB void HandleVersion(MythSocket *socket, const QStringList slist); void HandleDone(MythSocket *socket); - MythDeque m_threadPool; - QMutex m_threadPoolLock; - QWaitCondition m_threadPoolCond; - QMap m_socketMap; QReadWriteLock m_socketLock; @@ -73,5 +65,7 @@ class PROTOSERVER_PUBLIC MythSocketManager : public QObject, public MythSocketCB QReadWriteLock m_handlerLock; MythServer *m_server; + MThreadPool m_threadPool; + }; #endif diff --git a/mythtv/libs/libmythupnp/threadpool.cpp b/mythtv/libs/libmythupnp/threadpool.cpp deleted file mode 100644 index 55803c2e288..00000000000 --- a/mythtv/libs/libmythupnp/threadpool.cpp +++ /dev/null @@ -1,526 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Program Name: threadpool.cpp -// Created : Oct. 21, 2005 -// -// Purpose : Thread Pool Class -// -// Copyright (c) 2005 David Blain -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or at your option any later version of the LGPL. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library. If not, see . -// -////////////////////////////////////////////////////////////////////////////// - -#include - -#include -using namespace std; - -#include "threadpool.h" -#include "upnp.h" // only needed for Config... remove once config is moved. -#include "mythlogging.h" - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// CEvent Class Implementation -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -CEvent::CEvent( bool bInitiallyOwn /*= false */ ) -{ - m_bSignaled = bInitiallyOwn; -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -CEvent::~CEvent() -{ -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -bool CEvent::SetEvent () -{ - m_mutex.lock(); - m_bSignaled = true; - - m_wait.wakeAll(); - - m_mutex.unlock(); - - return( true ); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -bool CEvent::ResetEvent () -{ - m_mutex.lock(); - m_bSignaled = false; - m_mutex.unlock(); - - return( true ); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -bool CEvent::IsSignaled() -{ - m_mutex.lock(); - bool bSignaled = m_bSignaled; - m_mutex.unlock(); - - return( bSignaled ); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -bool CEvent::WaitForEvent( unsigned long time /*= ULONG_MAX */ ) -{ - m_mutex.lock(); - - if (m_bSignaled) - { - m_mutex.unlock(); - return true; - } - - bool ret = m_wait.wait(&m_mutex, time); - - m_mutex.unlock(); - - return ret; -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// WorkerEvent Class Implementation -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void WorkerEvent::customEvent(QEvent *e) -{ - if (m_parent) - m_parent->WakeForWork(); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void WorkerEvent::TimeOut() -{ - if (m_parent && m_parent->m_nIdleTimeoutMS > 0 && !m_parent->m_bTermRequested) - m_parent->quit(); -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// WorkerThread Class Implementation -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -WorkerThread::WorkerThread( ThreadPool *pThreadPool, const QString &sName ) : - MThread("WorkerThread") -{ - m_bInitialized = false; - m_bTermRequested = false; - m_pThreadPool = pThreadPool; - m_sName = sName; - m_nIdleTimeoutMS = 60000; - m_timer = 0; - m_wakeup = 0; -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -WorkerThread::~WorkerThread() -{ - m_bTermRequested = true; - - quit(); - wait(); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -bool WorkerThread::WaitForInitialized( unsigned long msecs ) -{ - m_mutex.lock(); - bool bInitialized = m_bInitialized; - m_mutex.unlock(); - - if (bInitialized) - return true; - - return( m_Initialized.WaitForEvent( msecs )); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void WorkerThread::SignalWork() -{ - if (!m_bInitialized) - return; - - QCoreApplication::postEvent(m_wakeup, new QEvent(QEvent::User)); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void WorkerThread::WakeForWork() -{ - try - { - m_timer->stop(); - ProcessWork(); - - if (m_nIdleTimeoutMS > 0) - m_timer->start(m_nIdleTimeoutMS); - } - catch(...) - { - LOG(VB_GENERAL, LOG_ERR, - QString("WorkerThread::Run( %1 ) - Unexpected Exception.") - .arg(m_sName)); - } - - if (!m_bTermRequested) - { - m_pThreadPool->ThreadAvailable( this ); - } -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void WorkerThread::SetTimeout( long nIdleTimeout ) -{ - m_nIdleTimeoutMS = nIdleTimeout; -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void WorkerThread::RequestTerminate( void ) -{ - m_bTermRequested = true; - quit(); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void WorkerThread::run( void ) -{ - RunProlog(); - - m_timer = new QTimer(); - m_timer->setSingleShot(true); - - m_wakeup = new WorkerEvent(this); - - m_mutex.lock(); - m_bInitialized = true; - m_mutex.unlock(); - - m_Initialized.SetEvent(); - - connect(m_timer, SIGNAL(timeout()), m_wakeup, SLOT(TimeOut())); - if (m_nIdleTimeoutMS > 0) - m_timer->start(m_nIdleTimeoutMS); - - exec(); - - if (m_pThreadPool != NULL ) - { - m_pThreadPool->ThreadTerminating( this ); - m_pThreadPool = NULL; - } - - delete m_wakeup; - delete m_timer; - - LOG(VB_UPNP, LOG_INFO, QString("WorkerThread:Run - Exiting: %1") - .arg( m_sName )); - RunEpilog(); -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// CThreadPool Class Implementation -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -ThreadPool::ThreadPool( const QString &sName ) -{ - m_sName = sName; - - Configuration *pConfig = UPnp::GetConfiguration(); - - m_nInitialThreadCount = - pConfig->GetValue("ThreadPool/" + m_sName + "/Initial", 1); - m_nMaxThreadCount = - pConfig->GetValue("ThreadPool/" + m_sName + "/Max" , 25); - m_nIdleTimeout = - pConfig->GetValue("ThreadPool/" + m_sName + "/Timeout", 60000); - - m_nInitialThreadCount = min( m_nInitialThreadCount, m_nMaxThreadCount ); - - LOG(VB_GENERAL, LOG_NOTICE, - QString("ThreadPool:%1: Initial %2, Max %3, Timeout %4") - .arg(sName) .arg(m_nInitialThreadCount) .arg(m_nMaxThreadCount) - .arg(m_nIdleTimeout)); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -ThreadPool::~ThreadPool( ) -{ - // -------------------------------------------------------------- - // Request Termination of all worker threads. - // -------------------------------------------------------------- - - m_mList.lock(); - WorkerThreadList list = m_lstThreads; - m_mList.unlock(); - - WorkerThreadList::iterator it = list.begin(); - for (; it != list.end(); ++it) - { - if (*it != NULL) - (*it)->RequestTerminate(); - } - - while (!list.empty()) - { - WorkerThread *pThread = list.front(); - list.pop_front(); - if (pThread != NULL) - { - pThread->wait(); - delete pThread; - } - } -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void ThreadPool::InitializeThreads() -{ - // -------------------------------------------------------------- - // Create the m_nInitialThreadCount threads... - // -------------------------------------------------------------- - - for (long nIdx = 0; nIdx < m_nInitialThreadCount; nIdx ++ ) - AddWorkerThread( true, -1 ); - -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -WorkerThread *ThreadPool::GetWorkerThread() -{ - WorkerThread *pThread = NULL; - long nThreadCount= 0; - - while (pThread == NULL) - { - // -------------------------------------------------------------- - // See if we have a worker thread available. - // -------------------------------------------------------------- - - m_mList.lock(); - if ( m_lstAvailableThreads.size() > 0) - { - pThread = m_lstAvailableThreads.front(); - m_lstAvailableThreads.pop_front(); - } - - nThreadCount = m_lstThreads.size(); - m_mList.unlock(); - - if (pThread == NULL) - { - // ---------------------------------------------------------- - // Check to see if we need to create a new thread or - // wait for one to become available. - // ---------------------------------------------------------- - - if ( nThreadCount < m_nMaxThreadCount) - pThread = AddWorkerThread( false, m_nIdleTimeout ); - else - { - QMutex mutex; - mutex.lock(); - - if (m_threadAvail.wait( &mutex, 5000 ) == false ) - { - LOG(VB_GENERAL, LOG_CRIT, - QString("ThreadPool:%1: thread pool exhausted " - "(max %2 threads)") - .arg(m_sName) .arg(m_nMaxThreadCount)); - return NULL; // timeout exceeded. - } - } - } - } - - return pThread; -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -WorkerThread *ThreadPool::AddWorkerThread( bool bMakeAvailable, long nTimeout ) -{ - QString sName = QString(m_sName + "_WorkerThread"); - long nThreadCount; - - LOG(VB_UPNP, LOG_INFO, QString( "ThreadPool:AddWorkerThread - %1" ) - .arg(sName)); - - WorkerThread *pThread = CreateWorkerThread( this, sName ); - - if (pThread != NULL) - { - pThread->SetTimeout( nTimeout ); - pThread->start(); - - if (pThread->WaitForInitialized( 5000 )) - { - // ------------------------------------------------------ - // Add new worker thread to list. - // ------------------------------------------------------ - - m_mList.lock(); - m_lstThreads.push_back( pThread ); - nThreadCount = m_lstThreads.size(); - - LOG(VB_GENERAL, LOG_DEBUG, - QString("ThreadPool:%1: thread pool size %2") - .arg(m_sName) .arg(nThreadCount)); - - if (bMakeAvailable) - { - m_lstAvailableThreads.push_back( pThread ); - m_threadAvail.wakeAll(); - } - m_mList.unlock(); - - } - else - { - // ------------------------------------------------------ - // It's taking longer than 5 seconds to initialize this thread.... - // give up on it. - // (This should never happen) - // ------------------------------------------------------ - - delete pThread; - pThread = NULL; - } - } - - return pThread; -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void ThreadPool::ThreadAvailable ( WorkerThread *pThread ) -{ - m_mList.lock(); - m_lstAvailableThreads.push_front(pThread); - m_mList.unlock(); - - m_threadAvail.wakeAll(); -} - -///////////////////////////////////////////////////////////////////////////// -// -///////////////////////////////////////////////////////////////////////////// - -void ThreadPool::ThreadTerminating ( WorkerThread *pThread ) -{ - long nThreadCount; - - m_mList.lock(); - WorkerThreadList::iterator it = find(m_lstAvailableThreads.begin(), - m_lstAvailableThreads.end(), pThread); - m_lstAvailableThreads.erase(it); - - it = find(m_lstThreads.begin(), m_lstThreads.end(), pThread); - m_lstThreads.erase(it); - - nThreadCount = m_lstThreads.size(); - LOG(VB_GENERAL, LOG_DEBUG, - QString("ThreadPool:%1: thread pool size %2") - .arg(m_sName) .arg(nThreadCount)); - - m_mList.unlock(); -} - diff --git a/mythtv/libs/libmythupnp/threadpool.h b/mythtv/libs/libmythupnp/threadpool.h deleted file mode 100644 index 1eaad205715..00000000000 --- a/mythtv/libs/libmythupnp/threadpool.h +++ /dev/null @@ -1,198 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Program Name: threadpool.h -// Created : Oct. 21, 2005 -// -// Purpose : Thread Pool Class -// -// Copyright (c) 2005 David Blain -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or at your option any later version of the LGPL. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library. If not, see . -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef __THREADPOOL_H__ -#define __THREADPOOL_H__ - -#include -using namespace std; - -#include -#include -#include -#include -#include -#include - -#include "mthread.h" -#include "upnpexp.h" - -class ThreadPool; - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -class UPNP_PUBLIC CEvent -{ - private: - - QMutex m_mutex; - QWaitCondition m_wait; - bool m_bSignaled; - - public: - - CEvent( bool bInitiallyOwn = false ); - virtual ~CEvent(); - - bool SetEvent (); - bool ResetEvent (); - bool IsSignaled (); - bool WaitForEvent( unsigned long time = ULONG_MAX ); -}; - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// WorkerEvent Class Declaration -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -class WorkerThread; -class UPNP_PUBLIC WorkerEvent : public QObject -{ - Q_OBJECT - - public: - WorkerEvent(WorkerThread *parent) : m_parent(parent) { } - - virtual void customEvent(QEvent *e); - - public slots: - void TimeOut(); - - private: - WorkerThread *m_parent; -}; - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -// -// WorkerThread Class Declaration -// -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -class UPNP_PUBLIC WorkerThread : public QObject, public MThread -{ - Q_OBJECT - - protected: - - QMutex m_mutex; - - CEvent m_Initialized; - bool m_bInitialized; - - QPointer m_pThreadPool; - - volatile bool m_bTermRequested; - QString m_sName; - - long m_nIdleTimeoutMS; - QTimer *m_timer; // audited ref #5318 - WorkerEvent *m_wakeup; - - void WakeForWork(); - - protected: - - virtual void run(); - virtual void ProcessWork() = 0; - - - public: - - WorkerThread( ThreadPool *pThreadPool, const QString &sName ); - virtual ~WorkerThread(); - - bool WaitForInitialized( unsigned long msecs ); - void SetTimeout ( long nIdleTimeout ); - - void RequestTerminate ( void ); - - public slots: - void SignalWork(); - - friend class WorkerEvent; -}; - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -// -// CThreadPool Class Declaration -// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -typedef deque WorkerThreadList; - -class UPNP_PUBLIC ThreadPool : public QObject -{ - Q_OBJECT - - friend class WorkerThread; - - protected: - - QString m_sName; - - QMutex m_mList; - - QWaitCondition m_threadAvail; - - WorkerThreadList m_lstThreads; - WorkerThreadList m_lstAvailableThreads; - - int m_nInitialThreadCount; - int m_nMaxThreadCount; - long m_nIdleTimeout; - - protected: - - void InitializeThreads(); - - WorkerThread *AddWorkerThread ( bool bMakeAvailable, long nTimeout ); - - void ThreadAvailable ( WorkerThread *pThread ); - void ThreadTerminating( WorkerThread *pThread ); - - virtual WorkerThread *CreateWorkerThread( ThreadPool *, const QString &sName ) = 0; - - public: - - ThreadPool( const QString &sName ); - virtual ~ThreadPool( ); - - WorkerThread *GetWorkerThread(); - -}; - - -#endif From 7f9cc30689969970696d4f140fa8548efa99bab3 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Mon, 8 Aug 2011 09:29:37 -0400 Subject: [PATCH 41/49] Make sure MythDownloadManger is shutdown early enough during MythCoreContext teardown. --- mythtv/libs/libmythbase/mythcorecontext.cpp | 3 +++ mythtv/libs/libmythbase/mythdownloadmanager.cpp | 2 +- mythtv/libs/libmythbase/mythdownloadmanager.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mythtv/libs/libmythbase/mythcorecontext.cpp b/mythtv/libs/libmythbase/mythcorecontext.cpp index c0745cc0a7c..6856304f75a 100644 --- a/mythtv/libs/libmythbase/mythcorecontext.cpp +++ b/mythtv/libs/libmythbase/mythcorecontext.cpp @@ -21,6 +21,7 @@ using namespace std; #include "compat.h" #include "mythconfig.h" // for CONFIG_DARWIN +#include "mythdownloadmanager.h" #include "mythsocketthread.h" #include "mythcorecontext.h" #include "mythsocket.h" @@ -118,6 +119,8 @@ MythCoreContextPrivate::~MythCoreContextPrivate() ShutdownMythSystem(); + ShutdownMythDownloadManager(); + logStop(); // need to shutdown db logger before we kill db MThread::Cleanup(); diff --git a/mythtv/libs/libmythbase/mythdownloadmanager.cpp b/mythtv/libs/libmythbase/mythdownloadmanager.cpp index 6f4f5a51626..f49ef544643 100644 --- a/mythtv/libs/libmythbase/mythdownloadmanager.cpp +++ b/mythtv/libs/libmythbase/mythdownloadmanager.cpp @@ -119,7 +119,7 @@ class RemoteFileDownloadThread : public QRunnable /** \fn ShutdownMythDownloadManager(void) * \brief Deletes the running MythDownloadManager at program exit. */ -static void ShutdownMythDownloadManager(void) +void ShutdownMythDownloadManager(void) { if (downloadManager) { diff --git a/mythtv/libs/libmythbase/mythdownloadmanager.h b/mythtv/libs/libmythbase/mythdownloadmanager.h index b9dbfdf4c04..218653da706 100644 --- a/mythtv/libs/libmythbase/mythdownloadmanager.h +++ b/mythtv/libs/libmythbase/mythdownloadmanager.h @@ -15,6 +15,8 @@ class MythDownloadInfo; class RemoteFileDownloadThread; +void ShutdownMythDownloadManager(void); + class MBASE_PUBLIC MythDownloadManager : public QObject, public MThread { Q_OBJECT From 9d81b10ad99005d35723a4d64731c2eed33df5b9 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Mon, 8 Aug 2011 09:55:39 -0400 Subject: [PATCH 42/49] Convert GameScannerThread to MThread. --- mythplugins/mythgame/mythgame/gamescan.cpp | 22 +++++++++++----------- mythplugins/mythgame/mythgame/gamescan.h | 9 ++++----- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/mythplugins/mythgame/mythgame/gamescan.cpp b/mythplugins/mythgame/mythgame/gamescan.cpp index 667b637562d..7e09ec1aa87 100644 --- a/mythplugins/mythgame/mythgame/gamescan.cpp +++ b/mythplugins/mythgame/mythgame/gamescan.cpp @@ -19,19 +19,19 @@ class MythUIProgressDialog; GameScannerThread::GameScannerThread(QObject *parent) : - m_DBDataChanged(false) + MThread("GameScanner"), m_parent(parent), + m_HasGUI(gCoreContext->HasGUI()), + m_dialog(NULL), m_DBDataChanged(false) { - m_parent = parent; - m_HasGUI = gCoreContext->HasGUI(); } GameScannerThread::~GameScannerThread() { } -void GameScannerThread::run() +void GameScannerThread::run(void) { - threadRegister("GameScanner"); + RunProlog(); LOG(VB_GENERAL, LOG_INFO, QString("Beginning Game Scan.")); @@ -43,7 +43,7 @@ void GameScannerThread::run() verifyFiles(); updateDB(); - threadDeregister(); + RunEpilog(); } @@ -64,7 +64,7 @@ void GameScannerThread::verifyFiles() if (m_HasGUI) SendProgressEvent(counter, (uint)m_dbgames.count(), - tr("Verifying game files")); + GameScanner::tr("Verifying game files")); // For every file we know about, check to see if it still exists. for (QList::iterator p = m_dbgames.begin(); @@ -107,7 +107,7 @@ void GameScannerThread::updateDB() uint counter = 0; if (m_HasGUI) SendProgressEvent(counter, (uint)(m_files.size() + m_remove.size()), - tr("Updating game database")); + GameScanner::tr("Updating game database")); for (QList::iterator p = m_files.begin(); p != m_files.end(); ++p) @@ -142,7 +142,7 @@ bool GameScannerThread::buildFileList() if (m_HasGUI) SendProgressEvent(counter, (uint)m_handlers.size(), - tr("Searching for games...")); + GameScanner::tr("Searching for games...")); for (QList::const_iterator iter = m_handlers.begin(); iter != m_handlers.end(); ++iter) @@ -217,9 +217,9 @@ void GameScanner::doScan(QList handlers) if (progressDlg->Create()) { popupStack->AddScreen(progressDlg, false); - connect(m_scanThread, SIGNAL(finished()), + connect(m_scanThread->qthread(), SIGNAL(finished()), progressDlg, SLOT(Close())); - connect(m_scanThread, SIGNAL(finished()), + connect(m_scanThread->qthread(), SIGNAL(finished()), SLOT(finishedScan())); } else diff --git a/mythplugins/mythgame/mythgame/gamescan.h b/mythplugins/mythgame/mythgame/gamescan.h index cd688b414fa..af27cbff0c3 100644 --- a/mythplugins/mythgame/mythgame/gamescan.h +++ b/mythplugins/mythgame/mythgame/gamescan.h @@ -6,9 +6,10 @@ #include // for moc #include -#include #include +#include "mthread.h" + class QStringList; class MythUIProgressDialog; @@ -27,15 +28,13 @@ struct RomFileInfo typedef QList< RomFileInfo > RomFileInfoList; -class GameScannerThread : public QThread +class GameScannerThread : public MThread { - Q_OBJECT - public: GameScannerThread(QObject *parent); ~GameScannerThread(); - void run(); + virtual void run(void); // MThread void SetHandlers(QList handlers) { m_handlers = handlers; }; void SetProgressDialog(MythUIProgressDialog *dialog) { m_dialog = dialog; }; From 6808c7acd59683bd1305873fcb68d3bb67fb27d5 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 8 Aug 2011 15:30:05 +0100 Subject: [PATCH 43/49] AlbumArtList was declared twice, remove one --- mythplugins/mythmusic/mythmusic/metadata.h | 1 - 1 file changed, 1 deletion(-) diff --git a/mythplugins/mythmusic/mythmusic/metadata.h b/mythplugins/mythmusic/mythmusic/metadata.h index e637ea8c8cb..66d75a247eb 100644 --- a/mythplugins/mythmusic/mythmusic/metadata.h +++ b/mythplugins/mythmusic/mythmusic/metadata.h @@ -47,7 +47,6 @@ class AlbumArtImage QString description; bool embedded; }; -typedef QList AlbumArtList; typedef QList AlbumArtList; From d3948d4cbbb022b94e771cf7422cce2e4c4fdd75 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 8 Aug 2011 15:36:14 +0100 Subject: [PATCH 44/49] Use empty() instead of size() comparisons for speed --- .../mytharchive/recordingselector.cpp | 6 +++--- .../mytharchive/mytharchive/videoselector.cpp | 2 +- mythplugins/mythmusic/mythmusic/importmusic.cpp | 16 ++++++++-------- .../mythzoneminder/mythzoneminder/zmevents.cpp | 4 ++-- .../mythzoneminder/mythzoneminder/zmplayer.cpp | 14 +++++++------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/mythplugins/mytharchive/mytharchive/recordingselector.cpp b/mythplugins/mytharchive/mytharchive/recordingselector.cpp index db80787def4..4659e0b3a98 100644 --- a/mythplugins/mytharchive/mytharchive/recordingselector.cpp +++ b/mythplugins/mytharchive/mytharchive/recordingselector.cpp @@ -141,7 +141,7 @@ void RecordingSelector::Init(void) usleep(2000); } - if (!m_recordingList || m_recordingList->size() == 0) + if (!m_recordingList || m_recordingList->empty()) { ShowOkPopup(tr("Either you don't have any recordings or " "no recordings are available locally!")); @@ -391,7 +391,7 @@ void RecordingSelector::cancelPressed() void RecordingSelector::updateRecordingList(void) { - if (!m_recordingList || m_recordingList->size() == 0) + if (!m_recordingList || m_recordingList->empty()) return; m_recordingButtonList->Reset(); @@ -437,7 +437,7 @@ void RecordingSelector::getRecordingList(void) m_recordingList = RemoteGetRecordedList(-1); m_categories.clear(); - if (m_recordingList && m_recordingList->size() > 0) + if (m_recordingList && !m_recordingList->empty()) { vector::iterator i = m_recordingList->begin(); for ( ; i != m_recordingList->end(); i++) diff --git a/mythplugins/mytharchive/mytharchive/videoselector.cpp b/mythplugins/mytharchive/mytharchive/videoselector.cpp index 26bc9c5b9f5..19588cdae05 100644 --- a/mythplugins/mytharchive/mytharchive/videoselector.cpp +++ b/mythplugins/mytharchive/mytharchive/videoselector.cpp @@ -464,7 +464,7 @@ void VideoSelector::getVideoList(void) m_videoList = getVideoListFromDB(); QStringList categories; - if (m_videoList && m_videoList->size() > 0) + if (m_videoList && !m_videoList->empty()) { vector::iterator i = m_videoList->begin(); for ( ; i != m_videoList->end(); i++) diff --git a/mythplugins/mythmusic/mythmusic/importmusic.cpp b/mythplugins/mythmusic/mythmusic/importmusic.cpp index ceccbebdac3..cae58dfced6 100644 --- a/mythplugins/mythmusic/mythmusic/importmusic.cpp +++ b/mythplugins/mythmusic/mythmusic/importmusic.cpp @@ -112,7 +112,7 @@ ImportMusicDialog::~ImportMusicDialog() void ImportMusicDialog::fillWidgets() { - if (m_tracks->size() > 0) + if (!m_tracks->empty()) { // update current m_currentText->SetText(QString("%1 of %2") @@ -312,7 +312,7 @@ void ImportMusicDialog::coverArtPressed() void ImportMusicDialog::playPressed() { - if (m_tracks->size() == 0) + if (m_tracks->empty()) return; m_playingMetaData = m_tracks->at(m_currentTrack)->metadata; @@ -340,7 +340,7 @@ void ImportMusicDialog::nextPressed() void ImportMusicDialog::addPressed() { - if (m_tracks->size() == 0) + if (m_tracks->empty()) return; Metadata *meta = m_tracks->at(m_currentTrack)->metadata; @@ -402,7 +402,7 @@ void ImportMusicDialog::addPressed() void ImportMusicDialog::addAllNewPressed() { - if (m_tracks->size() == 0) + if (m_tracks->empty()) return; m_currentTrack = 0; @@ -431,7 +431,7 @@ void ImportMusicDialog::addAllNewPressed() void ImportMusicDialog::nextNewPressed() { - if (m_tracks->size() == 0) + if (m_tracks->empty()) return; uint track = m_currentTrack + 1; @@ -538,7 +538,7 @@ void ImportMusicDialog::scanDirectory(QString &directory, vector *tr void ImportMusicDialog::showEditMetadataDialog() { - if (m_tracks->size() == 0) + if (m_tracks->empty()) return; Metadata *editMeta = m_tracks->at(m_currentTrack)->metadata; @@ -573,7 +573,7 @@ void ImportMusicDialog::showMenu() if (m_popupMenu) return; - if (m_tracks->size() == 0) + if (m_tracks->empty()) return; MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); @@ -774,7 +774,7 @@ void ImportMusicDialog::setTitleWordCaps(void) void ImportMusicDialog::showImportCoverArtDialog(void) { - if (m_tracks->size() == 0) + if (m_tracks->empty()) return; QFileInfo fi(m_sourceFiles.at(m_currentTrack)); diff --git a/mythplugins/mythzoneminder/mythzoneminder/zmevents.cpp b/mythplugins/mythzoneminder/mythzoneminder/zmevents.cpp index 471313b081b..c360f89afca 100644 --- a/mythplugins/mythzoneminder/mythzoneminder/zmevents.cpp +++ b/mythplugins/mythzoneminder/mythzoneminder/zmevents.cpp @@ -274,7 +274,7 @@ void ZMEvents::eventChanged(MythUIButtonListItem *item) void ZMEvents::playPressed(void) { - if (!m_eventList || m_eventList->size() == 0) + if (!m_eventList || m_eventList->empty()) return; m_savedPosition = m_eventGrid->GetCurrentPos(); @@ -306,7 +306,7 @@ void ZMEvents::playerExited(void) void ZMEvents::deletePressed(void) { - if (!m_eventList || m_eventList->size() == 0) + if (!m_eventList || m_eventList->empty()) return; m_savedPosition = m_eventGrid->GetCurrentPos(); diff --git a/mythplugins/mythzoneminder/mythzoneminder/zmplayer.cpp b/mythplugins/mythzoneminder/mythzoneminder/zmplayer.cpp index 55b41197bb9..2aecfa5a39f 100644 --- a/mythplugins/mythzoneminder/mythzoneminder/zmplayer.cpp +++ b/mythplugins/mythzoneminder/mythzoneminder/zmplayer.cpp @@ -241,7 +241,7 @@ bool ZMPlayer::keyPressEvent(QKeyEvent *event) } else if (action == "TOGGLEASPECT" || action == "TOGGLEFILL") { - if (m_eventList->size() > 0) + if (!m_eventList->empty()) { stopPlayer(); @@ -277,7 +277,7 @@ bool ZMPlayer::keyPressEvent(QKeyEvent *event) void ZMPlayer::playPressed() { - if (m_eventList->size() == 0) + if (m_eventList->empty()) return; if (m_paused) @@ -298,7 +298,7 @@ void ZMPlayer::playPressed() void ZMPlayer::deletePressed() { - if (m_eventList->size() == 0 || *m_currentEvent > (int) m_eventList->size() - 1) + if (m_eventList->empty() || *m_currentEvent > (int) m_eventList->size() - 1) return; Event *event = m_eventList->at(*m_currentEvent); @@ -315,7 +315,7 @@ void ZMPlayer::deletePressed() getEventInfo(); - if (m_eventList->size() > 0) + if (!m_eventList->empty()) { m_frameTimer->start(1000 / 25); m_paused = false; @@ -325,7 +325,7 @@ void ZMPlayer::deletePressed() void ZMPlayer::nextPressed() { - if (m_eventList->size() == 0) + if (m_eventList->empty()) return; if (*m_currentEvent >= (int) m_eventList->size() - 1) @@ -341,7 +341,7 @@ void ZMPlayer::nextPressed() void ZMPlayer::prevPressed() { - if (m_eventList->size() == 0) + if (m_eventList->empty()) return; if (*m_currentEvent <= 0) @@ -380,7 +380,7 @@ void ZMPlayer::updateFrame(void) void ZMPlayer::getFrame(void) { - if (m_eventList->size() == 0) + if (m_eventList->empty()) return; Event *event = m_eventList->at(*m_currentEvent); From b39d35a4bb557e9a68431a61964b4f2286411074 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Mon, 8 Aug 2011 17:46:59 -0400 Subject: [PATCH 45/49] Make sure MThread static's are initialized before any other statically initialized threads, notably MythSocketThread. --- mythtv/libs/libmythbase/libmythbase.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mythtv/libs/libmythbase/libmythbase.pro b/mythtv/libs/libmythbase/libmythbase.pro index 6961839333e..949ef9f3998 100644 --- a/mythtv/libs/libmythbase/libmythbase.pro +++ b/mythtv/libs/libmythbase/libmythbase.pro @@ -10,6 +10,7 @@ INSTALLS = target QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2) # Input +HEADERS += mthread.h mthreadpool.h HEADERS += mythsocket.h mythsocket_cb.h mythsocketthread.h msocketdevice.h HEADERS += mythbaseexp.h mythdbcon.h mythdb.h mythdbparams.h oldsettings.h HEADERS += verbosedefs.h mythversion.h compat.h mythconfig.h @@ -23,8 +24,8 @@ HEADERS += util.h mythhdd.h mythcdrom.h autodeletedeque.h dbutil.h HEADERS += mythhttppool.h mythhttphandler.h mythdeque.h mythlogging.h HEADERS += mythbaseutil.h referencecounter.h version.h mythcommandlineparser.h HEADERS += mythscheduler.h -HEADERS += mthread.h mthreadpool.h +SOURCES += mthread.cpp mthreadpool.cpp SOURCES += mythsocket.cpp mythsocketthread.cpp msocketdevice.cpp SOURCES += mythdbcon.cpp mythdb.cpp oldsettings.cpp SOURCES += mythobservable.cpp mythevent.cpp httpcomms.cpp mcodecs.cpp @@ -36,7 +37,6 @@ SOURCES += unzip.cpp iso639.cpp iso3166.cpp mythmedia.cpp util.cpp SOURCES += mythhdd.cpp mythcdrom.cpp dbutil.cpp SOURCES += mythhttppool.cpp mythhttphandler.cpp logging.cpp SOURCES += referencecounter.cpp mythcommandlineparser.cpp -SOURCES += mthread.cpp mthreadpool.cpp win32:SOURCES += msocketdevice_win.cpp unix { From ab988ce84c68039806e4ef0f64b25a1faca27f07 Mon Sep 17 00:00:00 2001 From: Gavin Hurlbut Date: Sun, 17 Jul 2011 01:07:35 -0700 Subject: [PATCH 46/49] Convert mythtranscode/mpeg2fix code from Qt3->Qt4 structures As Qt3 is long past in our history, it was high time to remove the uses of Q3PtrList, Q3PtrQueue from mpeg2fix. Also changed were some QMap and QString-related code that complained loudly when I removed qt3support from the .pro file. This could well fix a ticket as well. Refs #2077. --- .../programs/mythtranscode/Makefile.standlone | 2 +- mythtv/programs/mythtranscode/main.cpp | 17 +- mythtv/programs/mythtranscode/mpeg2fix.cpp | 855 +++++++++--------- mythtv/programs/mythtranscode/mpeg2fix.h | 42 +- .../programs/mythtranscode/mythtranscode.pro | 2 +- 5 files changed, 476 insertions(+), 442 deletions(-) diff --git a/mythtv/programs/mythtranscode/Makefile.standlone b/mythtv/programs/mythtranscode/Makefile.standlone index c73ab5ea6cc..9cb8c64374d 100644 --- a/mythtv/programs/mythtranscode/Makefile.standlone +++ b/mythtv/programs/mythtranscode/Makefile.standlone @@ -4,7 +4,7 @@ CFLAGS ?= -g -O0 -fno-inline -fno-default-inline -DNO_MYTH -D_FILE_OFFSET_BITS TOOL = mpeg2fix -INCLUDES = -I./libavformat -I./libavcodec -I./libavutil -I./libmpeg2 -I./replex -I/usr/include/qt3 +INCLUDES = -I./libavformat -I./libavcodec -I./libavutil -I./libmpeg2 -I./replex #INCLUDES += -I/usr/src/DVB/include OBJS = $(TOOL).o helper.o replex/libreplex.a diff --git a/mythtv/programs/mythtranscode/main.cpp b/mythtv/programs/mythtranscode/main.cpp index fef7668216e..f9074bb1105 100644 --- a/mythtv/programs/mythtranscode/main.cpp +++ b/mythtv/programs/mythtranscode/main.cpp @@ -632,21 +632,24 @@ static uint64_t ComputeNewBookmark(uint64_t oldBookmark, bool firstMark = true; while (delMap.count() && delMap.begin().key() <= oldBookmark) { - if (delMap.begin().data() == MARK_CUT_START && !withinCut) + uint64_t key = delMap.begin().key(); + MarkTypes mark = delMap.begin().value(); + + if (mark == MARK_CUT_START && !withinCut) { withinCut = true; - startOfCutRegion = delMap.begin().key(); + startOfCutRegion = key; } - else if (delMap.begin().data() == MARK_CUT_END && firstMark) + else if (mark == MARK_CUT_END && firstMark) { - subtraction += delMap.begin().key(); + subtraction += key; } - else if (delMap.begin().data() == MARK_CUT_END && withinCut) + else if (mark == MARK_CUT_END && withinCut) { withinCut = false; - subtraction += (delMap.begin().key() - startOfCutRegion); + subtraction += (key - startOfCutRegion); } - delMap.remove(delMap.begin()); + delMap.remove(key); firstMark = false; } if (withinCut) diff --git a/mythtv/programs/mythtranscode/mpeg2fix.cpp b/mythtv/programs/mythtranscode/mpeg2fix.cpp index 7ac8e533eea..dfc2febb281 100644 --- a/mythtv/programs/mythtranscode/mpeg2fix.cpp +++ b/mythtv/programs/mythtranscode/mpeg2fix.cpp @@ -17,7 +17,8 @@ #include "mpeg2fix.h" #include -#include +#include +#include #include #include "mythlogging.h" @@ -199,7 +200,7 @@ MPEG2fixup::MPEG2fixup(const QString &inf, const QString &outf, bool showprog, int otype, void (*update_func)(float), int (*check_func)()) { - displayFrame = new Q3PtrListIterator (vFrame); + displayFrame = 0; infile = inf; rx.outfile = outf; @@ -218,7 +219,7 @@ MPEG2fixup::MPEG2fixup(const QString &inf, const QString &outf, if (deleteMap && deleteMap->count()) { delMap = *deleteMap; - if(delMap.contains(0)) + if (delMap.contains(0)) { discard = 1; delMap.remove(0); @@ -282,27 +283,24 @@ MPEG2fixup::~MPEG2fixup() max_frames += vFrame.count(); while (vFrame.count()) { - tmpFrame = vFrame.first(); - vFrame.remove(); + tmpFrame = vFrame.takeFirst(); delete tmpFrame; } while (vSecondary.count()) { - tmpFrame = vSecondary.first(); - vSecondary.remove(); + tmpFrame = vSecondary.takeFirst(); delete tmpFrame; } - for (QMap >::iterator it = aFrame.begin(); - it != aFrame.end(); it++) + for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++) { - Q3PtrList *af = &(*it); + FrameList *af = (*it); max_frames += af->count(); while (af->count()) { - tmpFrame = af->first(); - af->remove(); + tmpFrame = af->takeFirst(); delete tmpFrame; } + delete af; } max_frames += framePool.count(); while (framePool.count()) @@ -347,36 +345,36 @@ void MPEG2fixup::inc2x33(int64_t *pts1, int64_t pts2) int64_t MPEG2fixup::udiff2x33(int64_t pts1, int64_t pts2) { - int64_t diff; + int64_t diff; - diff = pts1 - pts2; + diff = pts1 - pts2; - if (diff < 0){ - diff = MAX_PTS + diff; - } - return (diff % MAX_PTS); + if (diff < 0){ + diff = MAX_PTS + diff; + } + return (diff % MAX_PTS); } int64_t MPEG2fixup::diff2x33(int64_t pts1, int64_t pts2) { - switch (cmp2x33(pts1, pts2)){ + switch (cmp2x33(pts1, pts2)) + { case 0: - return 0; - break; + return 0; + break; case 1: case -2: - return (pts1 -pts2); - break; + return (pts1 - pts2); + break; case 2: - return (pts1 + MAX_PTS -pts2); - break; + return (pts1 + MAX_PTS - pts2); + break; case -1: - return (pts1 - (pts2+ MAX_PTS)); - break; - + return (pts1 - (pts2 + MAX_PTS)); + break; } return 0; @@ -392,21 +390,25 @@ int64_t MPEG2fixup::add2x33(int64_t pts1, int64_t pts2) int MPEG2fixup::cmp2x33(int64_t pts1, int64_t pts2) { - int ret; - - if (pts1 > pts2){ - if ((uint64_t)(pts1 - pts2) > MAX_PTS/2) - ret = -1; - else - ret = 1; - } else if (pts1 == pts2) ret = 0; - else { - if ((uint64_t)(pts2 - pts1) > MAX_PTS/2) - ret = 2; - else - ret = -2; - } - return ret; + int ret; + + if (pts1 > pts2) + { + if ((uint64_t)(pts1 - pts2) > MAX_PTS/2) + ret = -1; + else + ret = 1; + } + else if (pts1 == pts2) + ret = 0; + else + { + if ((uint64_t)(pts2 - pts1) > MAX_PTS/2) + ret = 2; + else + ret = -2; + } + return ret; } int MPEG2fixup::FindMPEG2Header(uint8_t *buf, int size, uint8_t code) @@ -530,7 +532,8 @@ void MPEG2replex::Start() mx.priv = (void *)this; - fd_out = open(outfile, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); + fd_out = open(outfile.toLocal8Bit().constData(), + O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); //await buffer fill pthread_mutex_lock(&mutex); @@ -568,8 +571,7 @@ void MPEG2fixup::InitReplex() memset(rx.exttype, 0, sizeof(rx.exttype)); memset(rx.exttypcnt, 0, sizeof(rx.exttypcnt)); int mp2_count = 0, ac3_count = 0; - for (QMap >::iterator it = aFrame.begin(); - it != aFrame.end(); it++) + for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++) { int i = aud_map[it.key()]; AVMetadataTag *metatag = @@ -580,7 +582,7 @@ void MPEG2fixup::InitReplex() ring_init(&rx.index_extrbuf[i], INDEX_BUF); rx.extframe[i].set = 1; rx.extframe[i].bit_rate = getCodecContext(it.key())->bit_rate; - rx.extframe[i].framesize = (*it).first()->pkt.size; + rx.extframe[i].framesize = (*it)->first()->pkt.size; strncpy(rx.extframe[i].language, lang, 4); switch(GetStreamType(it.key())) { @@ -650,7 +652,7 @@ int MPEG2fixup::AddFrame(MPEG2frame *f) iu.framesize = f->pkt.size; } - if (! rb || ! rbi) + if (!rb || !rbi) { LOG(VB_GENERAL, LOG_ERR, "Ringbuffer pointers empty. No stream found"); return 1; @@ -676,7 +678,7 @@ int MPEG2fixup::AddFrame(MPEG2frame *f) ring_avail(&rx.index_extrbuf[i]) < sizeof(index_unit)) ok = 0; - if (! ok && ring_free(rb) < (unsigned int)f->pkt.size && + if (!ok && ring_free(rb) < (unsigned int)f->pkt.size && ring_free(rbi) >= sizeof(index_unit)) { // increase memory to avoid deadlock @@ -688,7 +690,7 @@ int MPEG2fixup::AddFrame(MPEG2frame *f) if (!ring_reinit(rb, rb->size + inc_size)) ok = 1; } - if (! ok) + if (!ok) { pthread_mutex_unlock( &rx.mutex ); //deadlock @@ -707,14 +709,14 @@ int MPEG2fixup::AddFrame(MPEG2frame *f) if (ring_write(rb, f->pkt.data, f->pkt.size)<0){ pthread_mutex_unlock( &rx.mutex ); LOG(VB_GENERAL, LOG_ERR, - QString("Ring buffer overflow %1\n").arg(rb->size)); + QString("Ring buffer overflow %1").arg(rb->size)); return 1; } if (ring_write(rbi, (uint8_t *)&iu, sizeof(index_unit))<0){ pthread_mutex_unlock( &rx.mutex ); LOG(VB_GENERAL, LOG_ERR, - QString("Ring buffer overflow %1\n").arg(rbi->size)); + QString("Ring buffer overflow %1").arg(rbi->size)); return 1; } pthread_mutex_unlock(&rx.mutex); @@ -722,9 +724,11 @@ int MPEG2fixup::AddFrame(MPEG2frame *f) return 0; } -int MPEG2fixup::InitAV(const char *inputfile, const char *type, int64_t offset) +bool MPEG2fixup::InitAV(QString inputfile, const char *type, int64_t offset) { int ret; + QByteArray ifarray = inputfile.toLocal8Bit(); + const char *ifname = ifarray.constData(); AVInputFormat *fmt = NULL; @@ -736,13 +740,12 @@ int MPEG2fixup::InitAV(const char *inputfile, const char *type, int64_t offset) inputFC = NULL; - ret = av_open_input_file(&inputFC, inputfile, fmt, 0, NULL); - - if (ret != 0) + ret = av_open_input_file(&inputFC, ifname, fmt, 0, NULL); + if (ret) { LOG(VB_GENERAL, LOG_ERR, QString("Couldn't open input file, error #%1").arg(ret)); - return 0; + return false; } mkvfile = !strcmp(inputFC->iformat->name, "mkv") ? 1 : 0; @@ -752,27 +755,25 @@ int MPEG2fixup::InitAV(const char *inputfile, const char *type, int64_t offset) // Getting stream information ret = av_find_stream_info(inputFC); - if (ret < 0) { LOG(VB_GENERAL, LOG_ERR, QString("Couldn't get stream info, error #%1").arg(ret)); av_close_input_file(inputFC); inputFC = NULL; - return 0; + return false; } // Dump stream information if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_INFO)) - av_dump_format(inputFC, 0, inputfile, 0); + av_dump_format(inputFC, 0, ifname, 0); for (unsigned int i = 0; i < inputFC->nb_streams; i++) { switch (inputFC->streams[i]->codec->codec_type) { - case CODEC_TYPE_VIDEO: - if(vid_id == -1) + if (vid_id == -1) vid_id = i; break; @@ -788,22 +789,22 @@ int MPEG2fixup::InitAV(const char *inputfile, const char *type, int64_t offset) inputFC->streams[i]->codec->codec_id == CODEC_ID_MP2) { aud_map[i] = ext_count++; - aFrame[i] = Q3PtrList (); + aFrame[i] = new FrameList(); } else LOG(VB_GENERAL, LOG_ERR, QString("Skipping unsupported audio stream: %1") .arg(inputFC->streams[i]->codec->codec_id)); break; - default: LOG(VB_GENERAL, LOG_ERR, QString("Skipping unsupported codec %1 on stream %2") .arg(inputFC->streams[i]->codec->codec_type).arg(i)); + break; } } - return 1; + return true; } void MPEG2fixup::SetFrameNum(uint8_t *ptr, int num) @@ -814,22 +815,23 @@ void MPEG2fixup::SetFrameNum(uint8_t *ptr, int num) void MPEG2fixup::AddSequence(MPEG2frame *frame1, MPEG2frame *frame2) { if (frame1->isSequence || !frame2->isSequence) - return ; + return; int head_size = (frame2->framePos - frame2->pkt.data); frame1->ensure_size(frame1->pkt.size + head_size); memmove(frame1->pkt.data + head_size, frame1->pkt.data, frame1->pkt.size); memcpy(frame1->pkt.data, frame2->pkt.data, head_size); - frame1->pkt.size+=head_size; + frame1->pkt.size += head_size; ProcessVideo(frame1, header_decoder); +#if 0 if (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY)) { static int count = 0; QString filename = QString("hdr%1.yuv").arg(count++); - QByteArray fname = filename.toAscii(); - WriteFrame(fname.constData(), &frame1->pkt); + WriteFrame(filename, &frame1->pkt); } +#endif } int MPEG2fixup::ProcessVideo(MPEG2frame *vf, mpeg2dec_t *dec) @@ -849,7 +851,7 @@ int MPEG2fixup::ProcessVideo(MPEG2frame *vf, mpeg2dec_t *dec) mpeg2_buffer(dec, vf->pkt.data, vf->pkt.data + vf->pkt.size); - while(state != STATE_PICTURE) + while (state != STATE_PICTURE) { state = mpeg2_parse(dec); @@ -916,8 +918,9 @@ int MPEG2fixup::ProcessVideo(MPEG2frame *vf, mpeg2dec_t *dec) if (VERBOSE_LEVEL_CHECK(VB_DECODE, LOG_INFO)) { QString msg = QString(""); - //msg += QString("unused:%1 ") - // .arg(vf->pkt.size - mpeg2_getpos(dec)); +#if 0 + msg += QString("unused:%1 ") .arg(vf->pkt.size - mpeg2_getpos(dec)); +#endif if (vf->isSequence) msg += QString("%1x%2 P:%3 ").arg(info->sequence->width) @@ -934,13 +937,13 @@ int MPEG2fixup::ProcessVideo(MPEG2frame *vf, mpeg2dec_t *dec) if (info->current_picture) { int ct = info->current_picture->flags & PIC_MASK_CODING_TYPE; char coding_type = (ct == PIC_FLAG_CODING_TYPE_I) ? 'I' : - ((ct == PIC_FLAG_CODING_TYPE_P) ? 'P' : - ((ct == PIC_FLAG_CODING_TYPE_B) ? 'B' : - ((ct == PIC_FLAG_CODING_TYPE_D) ?'D' : 'X'))); - char top_bottom = (info->current_picture->flags & - PIC_FLAG_TOP_FIELD_FIRST) ? 'T' : 'B'; - char progressive = (info->current_picture->flags & - PIC_FLAG_PROGRESSIVE_FRAME) ? 'P' : '_'; + ((ct == PIC_FLAG_CODING_TYPE_P) ? 'P' : + ((ct == PIC_FLAG_CODING_TYPE_B) ? 'B' : + ((ct == PIC_FLAG_CODING_TYPE_D) ?'D' : 'X'))); + char top_bottom = (info->current_picture->flags & + PIC_FLAG_TOP_FIELD_FIRST) ? 'T' : 'B'; + char progressive = (info->current_picture->flags & + PIC_FLAG_PROGRESSIVE_FRAME) ? 'P' : '_'; msg += QString("#%1 fl:%2%3%4%5%6 ") .arg(info->current_picture->temporal_reference) .arg(info->current_picture->nb_fields) @@ -956,38 +959,34 @@ int MPEG2fixup::ProcessVideo(MPEG2frame *vf, mpeg2dec_t *dec) return 0; } -void MPEG2fixup::WriteFrame(const char *filename, MPEG2frame *f) +void MPEG2fixup::WriteFrame(QString filename, MPEG2frame *f) { MPEG2frame *tmpFrame = GetPoolFrame(f); if (tmpFrame == NULL) return; - if (! tmpFrame->isSequence) + if (!tmpFrame->isSequence) { - Q3PtrListIterator it (vFrame); - while (*it) + for (FrameList::Iterator it = vFrame.begin(); it != vFrame.end(); it++) { - if((*it)->isSequence) + if ((*it)->isSequence) { AddSequence(tmpFrame, *it); break; } - ++it; } } WriteFrame(filename, &tmpFrame->pkt); framePool.enqueue(tmpFrame); } -void MPEG2fixup::WriteFrame(const char *filename, AVPacket *pkt) +void MPEG2fixup::WriteFrame(QString filename, AVPacket *pkt) { - MPEG2frame *tmpFrame = GetPoolFrame(pkt); if (tmpFrame == NULL) return; - QString fname = QString(filename) + ".enc"; - QByteArray aname = fname.local8Bit(); - WriteData(aname, pkt->data, pkt->size); + QString fname = filename + ".enc"; + WriteData(fname, pkt->data, pkt->size); mpeg2dec_t *tmp_decoder = mpeg2_init(); mpeg2_info_t *info = (mpeg2_info_t *)mpeg2_info(tmp_decoder); @@ -1006,9 +1005,10 @@ void MPEG2fixup::WriteFrame(const char *filename, AVPacket *pkt) mpeg2_close(tmp_decoder); } -void MPEG2fixup::WriteYUV(const char *filename, const mpeg2_info_t *info) +void MPEG2fixup::WriteYUV(QString filename, const mpeg2_info_t *info) { - int fh = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); + int fh = open(filename.toLocal8Bit().constData(), + O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); if (fh == -1) { LOG(VB_GENERAL, LOG_ERR, QString("Couldn't open file %1: ").arg(filename) + ENO); @@ -1043,9 +1043,10 @@ void MPEG2fixup::WriteYUV(const char *filename, const mpeg2_info_t *info) close(fh); } -void MPEG2fixup::WriteData(const char *filename, uint8_t *data, int size) +void MPEG2fixup::WriteData(QString filename, uint8_t *data, int size) { - int fh = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); + int fh = open(filename.toLocal8Bit().constData(), + O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); if (fh == -1) { LOG(VB_GENERAL, LOG_ERR, QString("Couldn't open file %1: ").arg(filename) + ENO); @@ -1073,7 +1074,7 @@ int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) AVCodec *out_codec; info = mpeg2_info(img_decoder); - if (! info->display_fbuf) + if (!info->display_fbuf) return 1; outbuf_size = info->sequence->width * info->sequence->height * 2; @@ -1081,8 +1082,7 @@ int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) if (!fname.isEmpty()) { QString tmpstr = fname + ".yuv"; - QByteArray tmp = tmpstr.toAscii(); - WriteYUV(tmp.constData(), info); + WriteYUV(tmpstr, info); } picture = avcodec_alloc_frame(); @@ -1113,7 +1113,7 @@ int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) out_codec = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO); - if (! out_codec) + if (!out_codec) { free(picture); LOG(VB_GENERAL, LOG_ERR, "Couldn't find MPEG2 encoder"); @@ -1131,7 +1131,7 @@ int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) //sequence->progressive == frame->progressive //We fix the discrepancy by discarding avcodec's sequence header, and //replace it with the original - if(picture->interlaced_frame) + if (picture->interlaced_frame) c->flags |= CODEC_FLAG_INTERLACED_DCT; c->bit_rate = info->sequence->byte_rate << 3; //not used @@ -1181,12 +1181,10 @@ int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) if (!fname.isEmpty()) { QString ename = fname + ".enc"; - QByteArray aename = ename.toLocal8Bit(); - WriteData(aename.constData(), pkt->data, pkt->size); + WriteData(ename, pkt->data, pkt->size); QString yname = fname + ".enc.yuv"; - QByteArray ayname = yname.toLocal8Bit(); - WriteFrame(ayname.constData(), pkt); + WriteFrame(yname, pkt); } int delta = FindMPEG2Header(pkt->data, pkt->size, 0x00); // out_size=avcodec_encode_video(c, outbuf, outbuf_size, picture); @@ -1244,17 +1242,18 @@ int MPEG2fixup::GetFrame(AVPacket *pkt) { int ret; - while (1) + while (true) { - bool done = 0; + bool done = false; if (unreadFrames.count()) { vFrame.append(unreadFrames.dequeue()); - if (real_file_end && ! unreadFrames.count()) + if (real_file_end && !unreadFrames.count()) file_end = true; - return (file_end == true); + return file_end; } - while (! done) + + while (!done) { pkt->pts = AV_NOPTS_VALUE; pkt->dts = AV_NOPTS_VALUE; @@ -1267,15 +1266,17 @@ int MPEG2fixup::GetFrame(AVPacket *pkt) continue; //insert a bogus frame (this won't be written out) - if(vFrame.isEmpty()) + if (vFrame.isEmpty()) { LOG(VB_GENERAL, LOG_ERR, - "Found end of file without finding any frames"); - return GENERIC_EXIT_NOT_OK; + "Found end of file without finding any frames"); + return 1; } + MPEG2frame *tmpFrame = GetPoolFrame(&vFrame.last()->pkt); if (tmpFrame == NULL) - return GENERIC_EXIT_NOT_OK; + return 1; + vFrame.append(tmpFrame); real_file_end = true; file_end = true; @@ -1283,8 +1284,8 @@ int MPEG2fixup::GetFrame(AVPacket *pkt) } if (pkt->stream_index == vid_id || - aFrame.contains(pkt->stream_index)) - done = 1; + aFrame.contains(pkt->stream_index)) + done = true; else av_free_packet(pkt); } @@ -1314,30 +1315,28 @@ int MPEG2fixup::GetFrame(AVPacket *pkt) MPEG2frame *tmpFrame = GetPoolFrame(pkt); if (tmpFrame == NULL) - return GENERIC_EXIT_NOT_OK; + return 1; + switch (inputFC->streams[pkt->stream_index]->codec->codec_type) { - case CODEC_TYPE_VIDEO: vFrame.append(tmpFrame); av_free_packet(pkt); - if (! ProcessVideo(vFrame.last(), header_decoder)) + if (!ProcessVideo(vFrame.last(), header_decoder)) return 0; - framePool.enqueue(vFrame.last()); - vFrame.removeLast(); - + framePool.enqueue(vFrame.takeLast()); break; case CODEC_TYPE_AUDIO: - aFrame[pkt->stream_index].append(tmpFrame); + aFrame[pkt->stream_index]->append(tmpFrame); av_free_packet(pkt); return 0; default: framePool.enqueue(tmpFrame); av_free_packet(pkt); - return GENERIC_EXIT_NOT_OK; + return 1; } } } @@ -1345,56 +1344,53 @@ int MPEG2fixup::GetFrame(AVPacket *pkt) bool MPEG2fixup::FindStart() { AVPacket pkt; - int state = 0; QMap found; av_init_packet(&pkt); - while (!state) + do { if (GetFrame(&pkt)) return false; + if (vid_id == pkt.stream_index) { - while (! vFrame.isEmpty()) + while (!vFrame.isEmpty()) { if (vFrame.first()->isSequence) { - if (pkt.pos == vFrame.first()->pkt.pos) + if (pkt.pos != vFrame.first()->pkt.pos) + break; + + if ((uint64_t)pkt.pts != AV_NOPTS_VALUE || + (uint64_t)pkt.dts != AV_NOPTS_VALUE) { - if ((uint64_t)pkt.pts != AV_NOPTS_VALUE || - (uint64_t)pkt.dts != AV_NOPTS_VALUE) - { - if ((uint64_t)pkt.pts == AV_NOPTS_VALUE) - vFrame.first()->pkt.pts = pkt.dts; - LOG(VB_PROCESS, LOG_INFO, - "Found 1st valid video frame"); - break; - } - } - else + if ((uint64_t)pkt.pts == AV_NOPTS_VALUE) + vFrame.first()->pkt.pts = pkt.dts; + + LOG(VB_PROCESS, LOG_INFO, + "Found 1st valid video frame"); break; + } } - LOG(VB_PROCESS, LOG_INFO, "Dropping V packet"); - framePool.enqueue( vFrame.first()); + LOG(VB_PROCESS, LOG_INFO, "Dropping V packet"); - vFrame.removeFirst(); + framePool.enqueue(vFrame.takeFirst()); } } if (vFrame.isEmpty()) continue; - for (QMap >::iterator it = aFrame.begin(); - it != aFrame.end(); it++) + for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++) { - Q3PtrList *af = &(*it); - if (found.contains(it.key())) continue; - while (! af->isEmpty()) + FrameList *af = (*it); + + while (!af->isEmpty()) { int64_t delta = diff2x33(af->first()->pkt.pts, vFrame.first()->pkt.pts); @@ -1402,47 +1398,45 @@ bool MPEG2fixup::FindStart() { //Check all video sequence packets against current //audio packet - MPEG2frame *found = NULL; - while (vFrame.current()) + MPEG2frame *foundframe = NULL; + for (FrameList::Iterator it2 = vFrame.begin(); + it2 != vFrame.end(); it2++) { - if(vFrame.current()->isSequence) + MPEG2frame *currFrame = (*it2); + if (currFrame->isSequence) { int64_t dlta1 = diff2x33(af->first()->pkt.pts, - vFrame.current()->pkt.pts); + currFrame->pkt.pts); if (dlta1 >= -180000 && dlta1 <= 180000) { - found = vFrame.current(); + foundframe = currFrame; delta = dlta1; break; } } - vFrame.next(); } - if (found) + + while (foundframe && vFrame.first() != foundframe) { - while (vFrame.first() != found) - { - framePool.enqueue( vFrame.first()); - vFrame.removeFirst(); - } + framePool.enqueue(vFrame.takeFirst()); } } + if (delta < -180000 || delta > 180000) //2 seconds { - LOG(VB_PROCESS, LOG_INFO, - QString("Dropping A packet from stream %1") - .arg(it.key())); - LOG(VB_PROCESS, LOG_INFO, - QString(" A:%1 V:%2") - .arg(PtsTime(af->first()->pkt.pts)) - .arg(PtsTime(vFrame.first()->pkt.pts))); - framePool.enqueue( af->first()); - af->removeFirst(); - continue; + LOG(VB_PROCESS, LOG_INFO, + QString("Dropping A packet from stream %1") + .arg(it.key())); + LOG(VB_PROCESS, LOG_INFO, QString(" A:%1 V:%2") + .arg(PtsTime(af->first()->pkt.pts)) + .arg(PtsTime(vFrame.first()->pkt.pts))); + framePool.enqueue(af->takeFirst()); + continue; } + if (delta < 0 && af->count() > 1) { - if (cmp2x33(af->next()->pkt.pts, + if (cmp2x33(af->at(1)->pkt.pts, vFrame.first()->pkt.pts) > 0) { LOG(VB_PROCESS, LOG_INFO, @@ -1456,8 +1450,7 @@ bool MPEG2fixup::FindStart() LOG(VB_PROCESS, LOG_INFO, QString("Dropping A packet from stream %1") .arg(it.key())); - framePool.enqueue( af->first()); - af->removeFirst(); + framePool.enqueue(af->takeFirst()); continue; } } @@ -1474,9 +1467,7 @@ bool MPEG2fixup::FindStart() break; } } - - state = (found.count() == aFrame.count()); - } + } while (found.count() != aFrame.count()); return true; } @@ -1511,7 +1502,7 @@ void MPEG2fixup::SetRepeat(uint8_t *ptr, int size, int fields, bool topff) //set top_field_first ptr[7] |= setmask; ptr[7] &= clrmask; - return ; + return; } ptr++; @@ -1520,14 +1511,10 @@ void MPEG2fixup::SetRepeat(uint8_t *ptr, int size, int fields, bool topff) MPEG2frame *MPEG2fixup::FindFrameNum(int frameNum) { - Q3PtrListIterator it (vFrame); - - while (*it) + for (FrameList::Iterator it = vFrame.begin(); it != vFrame.end(); it++) { - if (GetFrameNum(it.current()) == frameNum) - return it.current(); - - ++it; + if (GetFrameNum((*it)) == frameNum) + return (*it); } return NULL; @@ -1535,37 +1522,29 @@ MPEG2frame *MPEG2fixup::FindFrameNum(int frameNum) void MPEG2fixup::RenumberFrames(int start_pos, int delta) { - // FIXME: We sometimes end up here with invalid frames pointers in the list - // which needs fixing - symptom is segfaults of mythtranscode when - // dereferencing the iterator value - Q3PtrListIterator it (vFrame); + int maxPos = vFrame.count(); - it+= start_pos; - - while (!it.atLast() || (it.atFirst() && (*it)->isSequence)) + for (int pos = start_pos; pos < maxPos; pos++) { - SetFrameNum((*it)->framePos, - GetFrameNum((*it)) + delta); - (*it)->mpeg2_pic.temporal_reference += delta; - - ++it; + MPEG2frame *frame = vFrame.at(pos); + SetFrameNum(frame->framePos, GetFrameNum(frame) + delta); + frame->mpeg2_pic.temporal_reference += delta; } } void MPEG2fixup::StoreSecondary() { - while (vSecondary.first()) + while (vSecondary.count()) { - framePool.enqueue(vSecondary.current()); - vSecondary.remove(); + framePool.enqueue(vSecondary.takeFirst()); } - while (vFrame.first() != vFrame.getLast()) + + while (vFrame.count() > 1) { - if (use_secondary && GetFrameTypeT(vFrame.current()) != 'B') - vSecondary.append(vFrame.current()); + if (use_secondary && GetFrameTypeT(vFrame.first()) != 'B') + vSecondary.append(vFrame.takeFirst()); else - framePool.enqueue(vFrame.current()); - vFrame.remove(); + framePool.enqueue(vFrame.takeFirst()); } } @@ -1573,11 +1552,11 @@ int MPEG2fixup::PlaybackSecondary() { int frame_num = 0; mpeg2_reset(img_decoder, 1); - for (vSecondary.first(); vSecondary.current(); vSecondary.next()) + for (FrameList::Iterator it = vSecondary.begin(); it != vSecondary.end(); + it++) { - - SetFrameNum(vSecondary.current()->framePos, frame_num++); - if (ProcessVideo(vSecondary.current(), img_decoder) < 0) + SetFrameNum((*it)->framePos, frame_num++); + if (ProcessVideo((*it), img_decoder) < 0) return 1; } return 0; @@ -1589,39 +1568,36 @@ MPEG2frame *MPEG2fixup::DecodeToFrame(int frameNum, int skip_reset) int found = 0; bool skip_first = false; const mpeg2_info_t * info = mpeg2_info(img_decoder); + int maxPos = vFrame.count() - 1; - if (displayFrame->current()->isSequence) + if (vFrame.at(displayFrame)->isSequence) { skip_first = true; - if (! skip_reset && - (! displayFrame->atLast() || displayFrame->atFirst())) + if (!skip_reset && (displayFrame != maxPos || displayFrame == 0)) mpeg2_reset(img_decoder, 1); } - spare = FindFrameNum(frameNum); - if (! spare) + if (!spare) return NULL; - int framePos = vFrame.findRef(spare); + int framePos = vFrame.indexOf(spare); - int curPos = vFrame.findRef(displayFrame->current()); - while (! displayFrame->atLast()) + for (int curPos = displayFrame; displayFrame != maxPos; + curPos++, displayFrame++) { - if (ProcessVideo(displayFrame->current(), img_decoder) < 0) + if (ProcessVideo(vFrame.at(displayFrame), img_decoder) < 0) return NULL; - if (! skip_first && curPos >= framePos && info->display_picture && - (int)info->display_picture->temporal_reference >= frameNum) + if (!skip_first && curPos >= framePos && info->display_picture && + (int)info->display_picture->temporal_reference >= frameNum) { found = 1; - ++(*displayFrame); + displayFrame++; break; } skip_first = false; - ++curPos; - ++(*displayFrame); } if (!found) @@ -1630,11 +1606,12 @@ MPEG2frame *MPEG2fixup::DecodeToFrame(int frameNum, int skip_reset) MPEG2frame *tmpFrame = GetPoolFrame(&spare->pkt); if (tmpFrame == NULL) return NULL; + tmpFrame->framePos = tmpFrame->pkt.data + (spare->framePos - spare->pkt.data); - while (! info->display_picture || - (int)info->display_picture->temporal_reference < frameNum) + while (!info->display_picture || + (int)info->display_picture->temporal_reference < frameNum) { SetFrameNum(tmpFrame->framePos, ++tmpFrameNum); if (ProcessVideo(tmpFrame, img_decoder) < 0) @@ -1649,45 +1626,58 @@ MPEG2frame *MPEG2fixup::DecodeToFrame(int frameNum, int skip_reset) // the frame in question doesn't exist. We have no idea where we are. // reset the displayFrame so we start searching from the beginning next // time - displayFrame->toFirst(); + displayFrame = 0; LOG(VB_GENERAL, LOG_NOTICE, QString("Frame %1 > %2. Corruption likely at pos: %3") .arg(info->display_picture->temporal_reference) .arg(frameNum).arg(spare->pkt.pos)); } + return spare; } -int MPEG2fixup::ConvertToI(Q3PtrList *orderedFrames, int headPos) +int MPEG2fixup::ConvertToI(FrameList *orderedFrames, int headPos) { MPEG2frame *spare = NULL; AVPacket pkt; +#ifdef SPEW_FILES static int ins_count = 0; +#endif //head_pos == 0 means that we are decoding B frames after a seq_header if (headPos == 0) if (PlaybackSecondary()) return 1; - Q3PtrListIterator it(*orderedFrames); - for (it.toFirst(); *it; ++it) + for (FrameList::Iterator it = orderedFrames->begin(); + it != orderedFrames->end(); it++) { - int i = GetFrameNum(it.current()); + int i = GetFrameNum((*it)); if ((spare = DecodeToFrame(i, headPos == 0)) == NULL) return 1; - if(GetFrameTypeT(spare) == 'I') + + if (GetFrameTypeT(spare) == 'I') continue; + pkt = spare->pkt; //pkt.data is a newly malloced area + { - QString fname = (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY)) ? - QString("cnv%1").arg(ins_count++) : QString(); - if(BuildFrame(&pkt, fname)) + QString fname; + +#ifdef SPEW_FILES + if (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY)) + fname = QString("cnv%1").arg(ins_count++); +#endif + + if (BuildFrame(&pkt, fname)) return 1; + LOG(VB_GENERAL, LOG_INFO, QString("Converting frame #%1 from %2 to I %3") .arg(i).arg(GetFrameTypeT(spare)).arg(fname)); } + spare->set_pkt(&pkt); av_free(pkt.data); SetFrameNum(spare->pkt.data, GetFrameNum(spare)); @@ -1695,59 +1685,64 @@ int MPEG2fixup::ConvertToI(Q3PtrList *orderedFrames, int headPos) } //reorder frames - spare = vFrame.at(headPos); - - vFrame.remove(); - - vFrame.insert(headPos + orderedFrames->count() - 1, spare); - - vFrame.at(headPos); + vFrame.move(headPos, headPos + orderedFrames->count() - 1); return 0; } int MPEG2fixup::InsertFrame(int frameNum, int64_t deltaPTS, - int64_t ptsIncrement, int64_t initPTS) + int64_t ptsIncrement, int64_t initPTS) { MPEG2frame *spare = NULL; AVPacket pkt; int increment = 0; + int index = 0; +#ifdef SPEW_FILES static int ins_count = 0; +#endif if ((spare = DecodeToFrame(frameNum, 0)) == NULL) return -1; + pkt = spare->pkt; //pkt.data is a newly malloced area + { - QString fname = (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY) ? - (QString("ins%1").arg(ins_count++)) : QString()); + QString fname; +#if SPEW_FILES + fname = (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY) ? + (QString("ins%1").arg(ins_count++)) : QString()); +#endif + if (BuildFrame(&pkt, fname)) return -1; + LOG(VB_GENERAL, LOG_INFO, QString("Inserting %1 I-Frames after #%2 %3") .arg((int)(deltaPTS / ptsIncrement)) .arg(GetFrameNum(spare)).arg(fname)); } + inc2x33(&pkt.pts, ptsIncrement * GetNbFields(spare) / 2 + initPTS); - vFrame.findRef(spare); - - while (vFrame.next() != vFrame.getLast() && - GetFrameTypeT(vFrame.current()) == 'B') - spare = vFrame.current(); + index = vFrame.indexOf(spare); + while (index < vFrame.count() - 1 && + GetFrameTypeT(vFrame.at(index)) == 'B') + spare = vFrame.at(index++); - vFrame.findRef(spare); + index = vFrame.indexOf(spare); while (deltaPTS > 0) { MPEG2frame *tmpFrame; + index++; increment++; pkt.dts = pkt.pts; SetFrameNum(pkt.data, ++frameNum); tmpFrame = GetPoolFrame(&pkt); if (tmpFrame == NULL) return -1; - vFrame.insert(vFrame.at() + 1, tmpFrame); - ProcessVideo(vFrame.current(), header_decoder); //process new frame + vFrame.insert(index, tmpFrame); + ProcessVideo(tmpFrame, header_decoder); //process new frame inc2x33(&pkt.pts, ptsIncrement); deltaPTS -= ptsIncrement; @@ -1756,7 +1751,7 @@ int MPEG2fixup::InsertFrame(int frameNum, int64_t deltaPTS, av_free(pkt.data); // update frame # for all frames in this group - RenumberFrames(vFrame.at() + 1, increment); + RenumberFrames(index, increment); return increment; } @@ -1781,7 +1776,7 @@ void MPEG2fixup::AddRangeList(QStringList rangelist, int type) QByteArray tmp = (*i).toAscii(); if (sscanf(tmp.constData(), "%lld - %lld", &start, &end) == 2) { - if(start == 0) + if (start == 0) { if (type == MPF_TYPE_CUTLIST) discard = 1; @@ -1810,22 +1805,20 @@ void MPEG2fixup::ShowRangeMap(frm_dir_map_t *mapPtr, QString msg) } } -Q3PtrList MPEG2fixup::ReorderDTStoPTS(Q3PtrList *dtsOrder) +FrameList MPEG2fixup::ReorderDTStoPTS(FrameList *dtsOrder, int pos) { - Q3PtrList Lreorder; - int pos = dtsOrder->at(); + FrameList Lreorder; + int maxPos = dtsOrder->count() - 1; - if (dtsOrder->current() == dtsOrder->getLast()) + if (pos >= maxPos) return Lreorder; - for (dtsOrder->next(); - dtsOrder->current() != dtsOrder->getLast() && - GetFrameTypeT(dtsOrder->current()) == 'B'; - dtsOrder->next()) - { - Lreorder.append(dtsOrder->current()); - } - Lreorder.append(dtsOrder->at(pos)); + MPEG2frame *frame = dtsOrder->at(pos); + + for (pos++; pos < maxPos && GetFrameTypeT(dtsOrder->at(pos)) == 'B'; pos++) + Lreorder.append(dtsOrder->at(pos)); + + Lreorder.append(frame); return Lreorder; } @@ -1865,14 +1858,35 @@ void MPEG2fixup::InitialPTSFixup(MPEG2frame *curFrame, int64_t &origvPTS, origvPTS = curFrame->pkt.pts * 300; } ptsinc((uint64_t *)&origvPTS, - (uint64_t)(150 * ptsIncrement * - GetNbFields(curFrame))); + (uint64_t)(150 * ptsIncrement * GetNbFields(curFrame))); +} + +void MPEG2fixup::dumpList(FrameList *list) +{ + LOG(VB_GENERAL, LOG_INFO, "========================================="); + LOG(VB_GENERAL, LOG_INFO, QString("List contains %1 items") + .arg(list->count())); + + for (FrameList::Iterator it = list->begin(); it != list->end(); it++) + { + MPEG2frame *curFrame = (*it); + + LOG(VB_GENERAL, LOG_INFO, + QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 pos: %6") + .arg(GetFrameTypeT(curFrame)) + .arg(GetFrameNum(curFrame)) + .arg(GetNbFields(curFrame)) + .arg(PtsTime(curFrame->pkt.pts)) + .arg(PtsTime(curFrame->pkt.dts)) + .arg(curFrame->pkt.pos)); + } + LOG(VB_GENERAL, LOG_INFO, "========================================="); } int MPEG2fixup::Start() { - //NOTE: expectedvPTS/DTS are in units of SCR (300*PTS) to allow for better - //accounting of rounding errors (still won't be right, but better) + // NOTE: expectedvPTS/DTS are in units of SCR (300*PTS) to allow for better + // accounting of rounding errors (still won't be right, but better) int64_t expectedvPTS, expectedPTS[N_AUDIO]; int64_t expectedDTS = 0, lastPTS = 0, initPTS = 0, deltaPTS = 0; int64_t origvPTS = 0, origaPTS[N_AUDIO]; @@ -1881,42 +1895,36 @@ int MPEG2fixup::Start() int new_discard_state = 0; int ret; QMap af_dlta_cnt, cutState; - // int i; AVPacket pkt, lastRealvPkt; - QByteArray ainfile = infile.toLocal8Bit(); - if (! InitAV(ainfile.constData(), format, 0)) - { - return (GENERIC_EXIT_NOT_OK); - } + if (!InitAV(infile, format, 0)) + return GENERIC_EXIT_NOT_OK; - if (! FindStart()) - return (GENERIC_EXIT_NOT_OK); + if (!FindStart()) + return GENERIC_EXIT_NOT_OK; av_init_packet(&pkt); ptsIncrement = vFrame.first()->mpeg2_seq.frame_period / 300; - initPTS = vFrame.current()->pkt.pts; + initPTS = vFrame.first()->pkt.pts; - LOG(VB_GENERAL, LOG_INFO, - QString("#%1 PTS:%2 Delta: 0.0ms queue: %3") - .arg(vid_id).arg(PtsTime(vFrame.current()->pkt.pts)) + LOG(VB_GENERAL, LOG_INFO, QString("#%1 PTS:%2 Delta: 0.0ms queue: %3") + .arg(vid_id).arg(PtsTime(vFrame.first()->pkt.pts)) .arg(vFrame.count())); - for (QMap >::iterator it = aFrame.begin(); - it != aFrame.end(); it++) + for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++) { - Q3PtrList *af = &(*it); - deltaPTS = diff2x33(vFrame.current()->pkt.pts, af->first()->pkt.pts); + FrameList *af = (*it); + deltaPTS = diff2x33(vFrame.first()->pkt.pts, af->first()->pkt.pts); LOG(VB_GENERAL, LOG_INFO, QString("#%1 PTS:%2 Delta: %3ms queue: %4") - .arg(it.key()) .arg(PtsTime(af->current()->pkt.pts)) + .arg(it.key()) .arg(PtsTime(af->first()->pkt.pts)) .arg(1000.0*deltaPTS / 90000.0).arg(af->count())); - if (cmp2x33(af->current()->pkt.pts, initPTS) < 0) - initPTS = af->current()->pkt.pts; + if (cmp2x33(af->first()->pkt.pts, initPTS) < 0) + initPTS = af->first()->pkt.pts; } initPTS -= 16200; //0.18 seconds back to prevent underflow @@ -1925,14 +1933,14 @@ int MPEG2fixup::Start() LOG(VB_PROCESS, LOG_INFO, QString("ptsIncrement: %1 Frame #: %2 PTS-adjust: %3") - .arg(ptsIncrement).arg(GetFrameNum(vFrame.current())) + .arg(ptsIncrement).arg(GetFrameNum(vFrame.first())) .arg(PtsTime(initPTS))); origvPTS = 300 * udiff2x33(vFrame.first()->pkt.pts, - ptsIncrement * GetFrameNum(vFrame.current())); + ptsIncrement * GetFrameNum(vFrame.first())); expectedvPTS = 300 * (udiff2x33(vFrame.first()->pkt.pts, initPTS) - - (ptsIncrement * GetFrameNum(vFrame.current()))); + (ptsIncrement * GetFrameNum(vFrame.first()))); expectedDTS = expectedvPTS - 300 * ptsIncrement; if (discard) @@ -1940,10 +1948,9 @@ int MPEG2fixup::Start() cutStartPTS = origvPTS / 300; } - for (QMap >::iterator it = aFrame.begin(); - it != aFrame.end(); it++) + for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++) { - Q3PtrList *af = &(*it); + FrameList *af = (*it); origaPTS[it.key()] = af->first()->pkt.pts * 300; expectedPTS[it.key()] = udiff2x33(af->first()->pkt.pts, initPTS); af_dlta_cnt[it.key()] = 0; @@ -1955,93 +1962,100 @@ int MPEG2fixup::Start() InitReplex(); - while (1) + while (!file_end) { /* read packet */ - if (! file_end) - { - if ((ret = GetFrame(&pkt)) < 0) - return ret; - } - else - break; + if ((ret = GetFrame(&pkt)) < 0) + return ret; - if (vFrame.count() && (file_end || vFrame.getLast()->isSequence)) + if (vFrame.count() && (file_end || vFrame.last()->isSequence)) { - MPEG2frame *seqFrame; - if (ptsIncrement != vFrame.first()->mpeg2_seq.frame_period / 300) + displayFrame = 0; + + // since we might reorder the frames when coming out of a cutpoint + // me need to save the first frame here, as it is guaranteed to + // have a sequence header. + MPEG2frame *seqFrame = vFrame.first(); + + if (!seqFrame->isSequence) + { + LOG(VB_GENERAL, LOG_WARNING, + QString("Problem: Frame %1 (type %2) doesn't contain " + "sequence header!") + .arg(frame_count) .arg(GetFrameTypeT(seqFrame))); + } + + if (ptsIncrement != seqFrame->mpeg2_seq.frame_period / 300) { LOG(VB_GENERAL, LOG_WARNING, QString("WARNING - Unsupported FPS change from %1 to %2") .arg(90000.0 / ptsIncrement, 0, 'f', 2) - .arg(27000000.0 / vFrame.first()->mpeg2_seq.frame_period, + .arg(27000000.0 / seqFrame->mpeg2_seq.frame_period, 0, 'f', 2)); } - displayFrame->toFirst(); - - // since we might reorder the frames when coming out of a cutpoint - // me need to save the first frame here, as it is guaranteed to - // have a sequence header. - seqFrame = vFrame.current(); - while (vFrame.current() != vFrame.getLast()) + for (int frame_pos = 0; frame_pos < vFrame.count() - 1;) { bool ptsorder_eq_dtsorder = false; - int frame_pos = vFrame.at(); int64_t dtsExtra = 0, PTSdiscrep = 0; - Q3PtrList Lreorder; + FrameList Lreorder; MPEG2frame *markedFrame = NULL, *markedFrameP = NULL; if (expectedvPTS != expectedDTS + ptsIncrement * 300) { LOG(VB_GENERAL, LOG_ERR, QString("expectedPTS != expectedDTS + ptsIncrement")); - LOG(VB_PROCESS, LOG_ERR, QString("%1 != %2 + %3") + LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3") .arg(PtsTime(expectedvPTS / 300)) .arg(PtsTime(expectedDTS / 300)) .arg(PtsTime(ptsIncrement))); - LOG(VB_PROCESS, LOG_ERR, QString("%1 != %2 + %3") + LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3") .arg(expectedvPTS) .arg(expectedDTS) .arg(ptsIncrement)); return GENERIC_EXIT_NOT_OK; } + //reorder frames in presentation order (to the next I/P frame) - Lreorder = ReorderDTStoPTS(&vFrame); + Lreorder = ReorderDTStoPTS(&vFrame, frame_pos); //First pass at fixing PTS values (fixes gross errors only) - for (MPEG2frame *curFrame = Lreorder.first(); - curFrame; curFrame = Lreorder.next()) + for (FrameList::Iterator it2 = Lreorder.begin(); + it2 != Lreorder.end(); it2++) { - poq.UpdateOrigPTS(vid_id, origvPTS,curFrame->pkt); + MPEG2frame *curFrame = (*it2); + poq.UpdateOrigPTS(vid_id, origvPTS, curFrame->pkt); InitialPTSFixup(curFrame, origvPTS, PTSdiscrep, maxframes, true); } + // if there was a PTS jump, find the largest change // in the next x frames // At the end of this, vFrame should look just like it did // beforehand - if (PTSdiscrep && ! file_end) + if (PTSdiscrep && !file_end) { int pos = vFrame.count(); int count = Lreorder.count(); while (vFrame.count() - frame_pos - count < 20 && !file_end) if ((ret = GetFrame(&pkt)) < 0) return ret; - if (! file_end) + + if (!file_end) { int64_t tmp_origvPTS = origvPTS; int numframes = (maxframes > 1) ? maxframes - 1 : 1; bool done = false; while (!done && - (uint)(frame_pos + count + 1) < vFrame.count()) + (frame_pos + count + 1) < vFrame.count()) { - Q3PtrList tmpReorder; - vFrame.at(frame_pos + count); - tmpReorder = ReorderDTStoPTS(&vFrame); - for (MPEG2frame *curFrame = tmpReorder.first(); - curFrame; curFrame = tmpReorder.next()) + FrameList tmpReorder; + tmpReorder = ReorderDTStoPTS(&vFrame, + frame_pos + count); + for (FrameList::Iterator it2 = tmpReorder.begin(); + it2 != tmpReorder.end(); it2++) { + MPEG2frame *curFrame = (*it2); int64_t tmpPTSdiscrep = 0; InitialPTSFixup(curFrame, tmp_origvPTS, tmpPTSdiscrep, numframes, false); @@ -2059,40 +2073,48 @@ int MPEG2fixup::Start() count += tmpReorder.count(); } } - // push frames onto 'unreadFrames' queue - vFrame.at(pos); - while (vFrame.at() == pos) + + // push extra read frames onto 'unreadFrames' queue + while (vFrame.count() > pos) { - unreadFrames.enqueue(vFrame.current()); - vFrame.remove(); + unreadFrames.enqueue(vFrame.takeAt(pos)); } file_end = false; } //check for cutpoints and convert to I-frames if needed - for (MPEG2frame *curFrame = Lreorder.first(); - curFrame; curFrame = Lreorder.next()) + for (int curIndex = 0; curIndex < Lreorder.count(); curIndex++) { + MPEG2frame *curFrame = Lreorder.at(curIndex); if (saveMap.count()) { if (saveMap.begin().key() <= frame_count) - saveMap.remove(saveMap.begin()); + saveMap.remove(saveMap.begin().key()); if (saveMap.count() && saveMap.begin().value() == 0) { LOG(VB_GENERAL, LOG_INFO, QString("Saving frame #%1") .arg(frame_count)); - if(GetFrameTypeT(curFrame) != 'I') - if (ConvertToI(&Lreorder, frame_pos)) - return GENERIC_EXIT_WRITE_FRAME_ERROR; + + if (GetFrameTypeT(curFrame) != 'I' && + ConvertToI(&Lreorder, frame_pos)) + { + return GENERIC_EXIT_WRITE_FRAME_ERROR; + } + WriteFrame(QString("save%1.yuv").arg(frame_count), curFrame); } } + if (delMap.count() && delMap.begin().key() <= frame_count) { new_discard_state = delMap.begin().value(); + LOG(VB_GENERAL, LOG_INFO, + QString("Del map found %1 at %2 (%3)") + .arg(new_discard_state) .arg(frame_count) + .arg(delMap.begin().key())); - delMap.remove(delMap.begin()); + delMap.remove(delMap.begin().key()); markedFrameP = curFrame; if (!new_discard_state) @@ -2104,19 +2126,20 @@ int MPEG2fixup::Start() } else { - cutStartPTS = add2x33(markedFrameP->pkt.pts, + cutStartPTS = + add2x33(markedFrameP->pkt.pts, ptsIncrement * GetNbFields(markedFrameP) / 2); - QMap >::iterator it; - for (it = aFrame.begin(); it != aFrame.end(); it++) + for (FrameMap::Iterator it3 = aFrame.begin(); + it3 != aFrame.end(); it3++) { - cutState[it.key()] = 1; + cutState[it3.key()] = 1; } } - //Rebuild when 'B' frame, or completing a cut, and the marked - //frame is a 'P' frame. - //After conversion, frames will be in linear order. + // Rebuild when 'B' frame, or completing a cut, and the + // marked frame is a 'P' frame. + // After conversion, frames will be in linear order. if ((GetFrameTypeT(curFrame) == 'B') || (!new_discard_state && (GetFrameTypeT(curFrame) == 'P'))) @@ -2125,35 +2148,37 @@ int MPEG2fixup::Start() return GENERIC_EXIT_WRITE_FRAME_ERROR; ptsorder_eq_dtsorder = true; } - else if (! new_discard_state && + else if (!new_discard_state && GetFrameTypeT(curFrame) == 'I') { - vFrame.remove(frame_pos); - vFrame.insert(frame_pos + Lreorder.at(), curFrame); + vFrame.move(frame_pos, frame_pos + curIndex); ptsorder_eq_dtsorder = true; } //convert from presentation-order to decode-order - markedFrame = vFrame.at(frame_pos + Lreorder.at()); + markedFrame = vFrame.at(frame_pos + curIndex); - if (! new_discard_state) + if (!new_discard_state) { AddSequence(markedFrame, seqFrame); - RenumberFrames(frame_pos + Lreorder.at(), - - GetFrameNum(markedFrame)); + RenumberFrames(frame_pos + curIndex, + - GetFrameNum(markedFrame)); } } frame_count++; } - lastRealvPkt = Lreorder.getLast()->pkt; - if (markedFrame || ! discard) + if (!Lreorder.isEmpty()) + lastRealvPkt = Lreorder.last()->pkt; + + if (markedFrame || !discard) { //check for PTS discontinuity - for (MPEG2frame *curFrame = Lreorder.first(); - curFrame; curFrame = Lreorder.next()) + for (FrameList::Iterator it2 = Lreorder.begin(); + it2 != Lreorder.end(); it2++) { + MPEG2frame *curFrame = (*it2); if (markedFrameP && discard) { if (curFrame != markedFrameP) @@ -2163,7 +2188,7 @@ int MPEG2fixup::Start() } dec2x33(&curFrame->pkt.pts, - poq.Get(vid_id, &curFrame->pkt)); + poq.Get(vid_id, &curFrame->pkt)); deltaPTS = diff2x33(curFrame->pkt.pts, expectedvPTS / 300); @@ -2180,23 +2205,19 @@ int MPEG2fixup::Start() //remove repeat_first_field if necessary if (no_repeat) - { SetRepeat(curFrame, 2, 0); - } //force PTS to stay in sync (this could be a bad idea!) if (fix_PTS) - { curFrame->pkt.pts = expectedvPTS / 300; - } if (deltaPTS > ptsIncrement*maxframes) { LOG(VB_GENERAL, LOG_NOTICE, QString("Need to insert %1 frames > max " - "allowed: %2. Assuming bad PTS\n") + "allowed: %2. Assuming bad PTS") .arg((int)(deltaPTS / ptsIncrement)) - .arg( maxframes)); + .arg(maxframes)); curFrame->pkt.pts = expectedvPTS / 300; deltaPTS = 0; } @@ -2209,71 +2230,74 @@ int MPEG2fixup::Start() break; } - //dtsExtra is applied at the end of this block if the current - //tail has repeat_first_field set + // dtsExtra is applied at the end of this block if the + // current tail has repeat_first_field set if (ptsorder_eq_dtsorder) dtsExtra = 0; else dtsExtra = 150 * ptsIncrement * (GetNbFields(vFrame.at(frame_pos)) - 2); - if (! markedFrame && deltaPTS > (4*ptsIncrement / 5)) + if (!markedFrame && deltaPTS > (4 * ptsIncrement / 5)) { - //if we are off by more than 1/2 frame, it is time to add a frame - // The frame(s) will be added right after lVpkt_tail, and - // lVpkt_head will be adjusted accordingly - + // if we are off by more than 1/2 frame, it is time to + // add a frame + // The frame(s) will be added right after lVpkt_tail, + // and lVpkt_head will be adjusted accordingly vFrame.at(frame_pos)->pkt.pts = lastPTS / 300; - int ret = InsertFrame(GetFrameNum(vFrame.current()), - deltaPTS, ptsIncrement, 0); - if(ret < 0) + int ret = InsertFrame(GetFrameNum(vFrame.at(frame_pos)), + deltaPTS, ptsIncrement, 0); + + if (ret < 0) return GENERIC_EXIT_WRITE_FRAME_ERROR; - for (vFrame.at(frame_pos + Lreorder.count()); ret; - vFrame.next(), --ret) + + for (int index = frame_pos + Lreorder.count(); + ret && index < vFrame.count(); index++, --ret) { lastPTS = expectedvPTS; expectedvPTS += 150 * ptsIncrement * - GetNbFields(vFrame.current()); - Lreorder.append(vFrame.current()); + GetNbFields(vFrame.at(index)); + Lreorder.append(vFrame.at(index)); } } - //Set DTS (ignore any current values), and send frame to - //multiplexer - vFrame.at(frame_pos); + // Set DTS (ignore any current values), and send frame to + // multiplexer - for (uint i = 0; i < Lreorder.count(); i++, vFrame.next()) + for (int i = 0; i < Lreorder.count(); i++, frame_pos++) { + MPEG2frame *curFrame = vFrame.at(frame_pos); if (discard) { - if (markedFrame != vFrame.current()) + if (curFrame != markedFrame) continue; discard = false; - markedFrame = NULL; } - vFrame.current()->pkt.dts = (expectedDTS / 300); - if (GetFrameTypeT(vFrame.current()) == 'B') - vFrame.current()->pkt.pts = (expectedDTS / 300); + curFrame->pkt.dts = (expectedDTS / 300); +#if 0 + if (GetFrameTypeT(curFrame) == 'B') + curFrame->pkt.pts = (expectedDTS / 300); +#endif expectedDTS += 150 * ptsIncrement * - ((! ptsorder_eq_dtsorder && i == 0) ? - 2 : GetNbFields(vFrame.current())); + ((!ptsorder_eq_dtsorder && i == 0) ? 2 : + GetNbFields(curFrame)); LOG(VB_FRAME, LOG_INFO, QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 " "pos: %6") - .arg(GetFrameTypeT(vFrame.current())) - .arg(GetFrameNum(vFrame.current())) - .arg(GetNbFields(vFrame.current())) - .arg(PtsTime(vFrame.current()->pkt.pts)) - .arg(PtsTime(vFrame.current()->pkt.dts)) - .arg(vFrame.current()->pkt.pos)); - if (AddFrame(vFrame.current())) + .arg(GetFrameTypeT(curFrame)) + .arg(GetFrameNum(curFrame)) + .arg(GetNbFields(curFrame)) + .arg(PtsTime(curFrame->pkt.pts)) + .arg(PtsTime(curFrame->pkt.dts)) + .arg(curFrame->pkt.pos)); + if (AddFrame(curFrame)) return GENERIC_EXIT_DEADLOCK; - if (vFrame.current() == markedFrame) + if (curFrame == markedFrame) { markedFrame = NULL; discard = true; @@ -2284,11 +2308,11 @@ int MPEG2fixup::Start() } else { - vFrame.at(frame_pos + Lreorder.count()); + frame_pos += Lreorder.count(); } if (PTSdiscrep) poq.SetNextPos(add2x33(poq.Get(vid_id, &lastRealvPkt), - PTSdiscrep), lastRealvPkt); + PTSdiscrep), lastRealvPkt); } if (discard) @@ -2300,10 +2324,9 @@ int MPEG2fixup::Start() StoreSecondary(); } - for (QMap >::iterator it = aFrame.begin(); - it != aFrame.end(); it++) + for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++) { - Q3PtrList *af = &(*it); + FrameList *af = (*it); AVCodecContext *CC = getCodecContext(it.key()); bool backwardsPTS = false; @@ -2338,6 +2361,7 @@ int MPEG2fixup::Start() tmpPTS = diff2x33(af->first()->pkt.pts, origaPTS[it.key()] / 300); + if (tmpPTS < -incPTS) { #ifdef DEBUG_AUDIO @@ -2346,11 +2370,11 @@ int MPEG2fixup::Start() .arg(PtsTime(af->first()->pkt.pts)) .arg(PtsTime(origaPTS[it.key()] / 300))); #endif - framePool.enqueue(af->first()); - af->remove(); + framePool.enqueue(af->takeFirst()); af_dlta_cnt[it.key()] = 0; continue; } + if (tmpPTS > incPTS * maxframes) { LOG(VB_PROCESS, LOG_INFO, @@ -2393,6 +2417,7 @@ int MPEG2fixup::Start() backwardsPTS = false; af_dlta_cnt[it.key()] = 0; } + nextPTS = add2x33(af->first()->pkt.pts, 90000LL * (int64_t)CC->frame_size / CC->sample_rate); @@ -2408,12 +2433,12 @@ int MPEG2fixup::Start() .arg(PtsTime(af->first()->pkt.pts)) .arg(PtsTime(cutEndPTS))); #endif - framePool.enqueue(af->first()); - af->remove(); + framePool.enqueue(af->takeFirst()); cutState[it.key()] = 2; ptsinc((uint64_t *)&origaPTS[it.key()], incPTS * 300); continue; } + int64_t deltaPTS = poq.Get(it.key(), &af->first()->pkt); if (udiff2x33(nextPTS, deltaPTS) * 300 > expectedDTS && @@ -2440,18 +2465,13 @@ int MPEG2fixup::Start() #endif LOG(VB_FRAME, LOG_INFO, QString("AUD #%1: pts: %2 pos: %3") .arg(it.key()) - .arg(PtsTime(af->current()->pkt.pts)) - .arg(af->current()->pkt.pos)); - if (AddFrame(af->current())) + .arg(PtsTime(af->first()->pkt.pts)) + .arg(af->first()->pkt.pos)); + if (AddFrame(af->first())) return GENERIC_EXIT_DEADLOCK; - framePool.enqueue(af->first()); - - af->remove(); + framePool.enqueue(af->takeFirst()); } } - - if (file_end) - break; } rx.done = 1; @@ -2598,8 +2618,7 @@ int MPEG2fixup::BuildKeyframeIndex(QString &file, int count = 0; /*============ initialise AV ===============*/ - QByteArray fname = file.toLocal8Bit(); - if (!InitAV(fname.constData(), NULL, 0)) + if (!InitAV(file, NULL, 0)) return GENERIC_EXIT_NOT_OK; if (mkvfile) @@ -2629,3 +2648,7 @@ int MPEG2fixup::BuildKeyframeIndex(QString &file, return REENCODE_OK; } + +/* + * vim:ts=4:sw=4:ai:et:si:sts=4 + */ diff --git a/mythtv/programs/mythtranscode/mpeg2fix.h b/mythtv/programs/mythtranscode/mpeg2fix.h index ea286bbc2b0..7d6285d9448 100644 --- a/mythtv/programs/mythtranscode/mpeg2fix.h +++ b/mythtv/programs/mythtranscode/mpeg2fix.h @@ -25,13 +25,11 @@ extern "C" //Qt #include +#include +#include #include #include -#include -#include -#include - // MythTV #include "transcodedefs.h" #include "programtypes.h" @@ -131,6 +129,10 @@ class MPEG2replex multiplex_t *mplex; }; +typedef QList FrameList; +typedef QQueue FrameQueue; +typedef QMap FrameMap; + class MPEG2fixup { public: @@ -161,13 +163,13 @@ class MPEG2fixup void InitReplex(); void FrameInfo(MPEG2frame *f); int AddFrame(MPEG2frame *f); - int InitAV(const char *inputfile, const char *type, int64_t offset); + bool InitAV(QString inputfile, const char *type, int64_t offset); void ScanAudio(); int ProcessVideo(MPEG2frame *vf, mpeg2dec_t *dec); - void WriteFrame(const char *filename, MPEG2frame *f); - void WriteFrame(const char *filename, AVPacket *pkt); - void WriteYUV(const char *filename, const mpeg2_info_t *info); - void WriteData(const char *filename, uint8_t *data, int size); + void WriteFrame(QString filename, MPEG2frame *f); + void WriteFrame(QString filename, AVPacket *pkt); + void WriteYUV(QString filename, const mpeg2_info_t *info); + void WriteData(QString filename, uint8_t *data, int size); int BuildFrame(AVPacket *pkt, QString fname); MPEG2frame *GetPoolFrame(AVPacket *pkt); MPEG2frame *GetPoolFrame(MPEG2frame *f); @@ -180,11 +182,11 @@ class MPEG2fixup void StoreSecondary(); int PlaybackSecondary(); MPEG2frame *DecodeToFrame(int frameNum, int skip_reset); - int ConvertToI(Q3PtrList *orderedFrames, int headPos); + int ConvertToI(FrameList *orderedFrames, int headPos); int InsertFrame(int frameNum, int64_t deltaPTS, int64_t ptsIncrement, int64_t initPTS); void AddSequence(MPEG2frame *frame1, MPEG2frame *frame2); - Q3PtrList ReorderDTStoPTS(Q3PtrList *dtsOrder); + FrameList ReorderDTStoPTS(FrameList *dtsOrder, int pos); void InitialPTSFixup(MPEG2frame *curFrame, int64_t &origvPTS, int64_t &PTSdiscrep, int numframes, bool fix); void SetFrameNum(uint8_t *ptr, int num); @@ -216,17 +218,19 @@ class MPEG2fixup return inputFC->streams[id]->codec; } + void dumpList(FrameList *list); + int (*check_abort)(); void (*update_status)(float percent_done); - Q3PtrList vSecondary; + FrameList vSecondary; bool use_secondary; - Q3PtrList vFrame; - QMap > aFrame; - Q3PtrQueue framePool; - Q3PtrQueue unreadFrames; - Q3PtrListIterator *displayFrame; + FrameList vFrame; + FrameMap aFrame; + FrameQueue framePool; + FrameQueue unreadFrames; + int displayFrame; mpeg2dec_t *header_decoder; mpeg2dec_t *img_decoder; @@ -289,3 +293,7 @@ class MPEG2fixup #include "exitcodes.h" #include "mythcontext.h" #endif + +/* + * vim:ts=4:sw=4:ai:et:si:sts=4 + */ diff --git a/mythtv/programs/mythtranscode/mythtranscode.pro b/mythtv/programs/mythtranscode/mythtranscode.pro index 71c9b54c35c..535efdb4981 100644 --- a/mythtv/programs/mythtranscode/mythtranscode.pro +++ b/mythtv/programs/mythtranscode/mythtranscode.pro @@ -2,7 +2,7 @@ include ( ../../settings.pro) include ( ../../version.pro) include ( ../programs-libs.pro) -QT += network xml sql qt3support +QT += network xml sql TEMPLATE = app CONFIG += thread From a2eca2099df3663ba9b027fbadff4a07f2c039f4 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Mon, 8 Aug 2011 18:06:33 -0400 Subject: [PATCH 47/49] Fixes #9966. cattype should not be null. --- mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp b/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp index 198401eb827..7c70709ecc3 100644 --- a/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp +++ b/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp @@ -209,7 +209,7 @@ QString myth_category_type_to_string(uint category_type) if ((category_type > kCategoryNone) && (category_type < kCategoryLast)) return QString(cattype[category_type]); - return QString(); + return ""; } MythCategoryType string_to_myth_category_type(const QString &category_type) From c199aac5bd66c5e98bbed4074d6ec106435e2360 Mon Sep 17 00:00:00 2001 From: Daniel Kristjansson Date: Mon, 8 Aug 2011 18:10:39 -0400 Subject: [PATCH 48/49] Update binary version.. I should have done it this morning for some of the libmythbase changes. --- mythtv/libs/libmythbase/mythversion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h index db6425c6cc2..22dc17d45a2 100644 --- a/mythtv/libs/libmythbase/mythversion.h +++ b/mythtv/libs/libmythbase/mythversion.h @@ -12,7 +12,7 @@ /// Update this whenever the plug-in API changes. /// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and /// libmythui class methods used by plug-ins. -#define MYTH_BINARY_VERSION "0.25.20110805-1" +#define MYTH_BINARY_VERSION "0.25.20110808-1" /** \brief Increment this whenever the MythTV network protocol changes. * From 8f37c6e8c9666c8d5df7185b4ac76497255ac686 Mon Sep 17 00:00:00 2001 From: Gavin Hurlbut Date: Mon, 8 Aug 2011 15:16:21 -0700 Subject: [PATCH 49/49] Fix a compile warning in non-Linux case There was no return value if it wasn't Linux. Now returning "N/A" --- mythtv/libs/libmythtv/jitterometer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mythtv/libs/libmythtv/jitterometer.cpp b/mythtv/libs/libmythtv/jitterometer.cpp index db537e8914d..5fdf1cf7cb5 100644 --- a/mythtv/libs/libmythtv/jitterometer.cpp +++ b/mythtv/libs/libmythtv/jitterometer.cpp @@ -177,5 +177,7 @@ QString Jitterometer::GetCPUStat(void) ptr += 9; } return res; +#else + return "N/A"; #endif }