From c4960e5e9b2eb84834b455a4ce0dc96fd08fe414 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Mon, 12 Aug 2013 12:00:32 +1000 Subject: [PATCH] Use a queue to cancel downloads. cancelDownload can be blocking or not. Add API to cancel a list of urls. Hopefully prevent another racing conditions seen with HLS recorder when changing channels quickly. Fixes #11663 --- .../libs/libmythbase/mythdownloadmanager.cpp | 77 ++++++++++++++----- mythtv/libs/libmythbase/mythdownloadmanager.h | 6 +- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/mythtv/libs/libmythbase/mythdownloadmanager.cpp b/mythtv/libs/libmythbase/mythdownloadmanager.cpp index bd3ed71e21f..aff4c9fda79 100644 --- a/mythtv/libs/libmythbase/mythdownloadmanager.cpp +++ b/mythtv/libs/libmythbase/mythdownloadmanager.cpp @@ -240,6 +240,7 @@ void MythDownloadManager::run(void) bool downloading = false; bool itemsInQueue = false; + bool itemsInCancellationQueue = false; bool waitAnyway = false; m_queueThread = QThread::currentThread(); @@ -276,8 +277,13 @@ void MythDownloadManager::run(void) } m_infoLock->lock(); downloading = !m_downloadInfos.isEmpty(); + itemsInCancellationQueue = !m_cancellationQueue.isEmpty(); m_infoLock->unlock(); + if (itemsInCancellationQueue) + { + downloadCanceled(); + } if (downloading) QCoreApplication::processEvents(); @@ -861,39 +867,65 @@ bool MythDownloadManager::downloadNow(MythDownloadInfo *dlInfo, bool deleteInfo) /** \brief Cancel a queued or current download. * \param url for download to cancel */ -void MythDownloadManager::cancelDownload(const QString &url) +void MythDownloadManager::cancelDownload(const QString &url, bool block) +{ + cancelDownload(QStringList(url), block); +} + +/** \brief Cancel a queued or current download. + * \param list of urls for download to cancel + */ +void MythDownloadManager::cancelDownload(const QStringList &urls, bool block) { - QMutexLocker locker(m_infoLock); MythDownloadInfo *dlInfo; - QMutableListIterator lit(m_downloadQueue); - while (lit.hasNext()) + m_infoLock->lock(); + foreach (QString url, urls) { - lit.next(); - dlInfo = lit.value(); - if (dlInfo->m_url == url) + QMutableListIterator lit(m_downloadQueue); + while (lit.hasNext()) + { + lit.next(); + dlInfo = lit.value(); + if (dlInfo->m_url == url) + { + if (!m_cancellationQueue.contains(dlInfo)) + m_cancellationQueue.append(dlInfo); + lit.remove(); + } + } + + if (m_downloadInfos.contains(url)) { + dlInfo = m_downloadInfos[url]; + if (!m_cancellationQueue.contains(dlInfo)) m_cancellationQueue.append(dlInfo); - lit.remove(); + + if (dlInfo->m_reply) + m_downloadReplies.remove(dlInfo->m_reply); + + m_downloadInfos.remove(url); } } + m_infoLock->unlock(); - if (m_downloadInfos.contains(url)) + if (QThread::currentThread() == this->thread()) { - dlInfo = m_downloadInfos[url]; + downloadCanceled(); + return; + } - if (!m_cancellationQueue.contains(dlInfo)) - m_cancellationQueue.append(dlInfo); + // wake-up running thread + m_queueWaitCond.wakeAll(); - if (dlInfo->m_reply) - m_downloadReplies.remove(dlInfo->m_reply); + if (!block) + return; - m_downloadInfos.remove(url); + while (!m_cancellationQueue.isEmpty()) + { + usleep(50000); // re-test in another 50ms } - - QMetaObject::invokeMethod(this, "downloadCanceled", - Qt::QueuedConnection); } void MythDownloadManager::downloadCanceled() @@ -906,7 +938,8 @@ void MythDownloadManager::downloadCanceled() { lit.next(); dlInfo = lit.value(); - + dlInfo->m_lock.lock(); + if (dlInfo->m_reply) { LOG(VB_FILE, LOG_DEBUG, @@ -914,9 +947,11 @@ void MythDownloadManager::downloadCanceled() dlInfo->m_reply->abort(); } lit.remove(); - if (dlInfo->IsDone()) + if (dlInfo->m_done) + { + dlInfo->m_lock.unlock(); continue; - dlInfo->m_lock.lock(); + } dlInfo->m_errorCode = QNetworkReply::OperationCanceledError; dlInfo->m_done = true; dlInfo->m_lock.unlock(); diff --git a/mythtv/libs/libmythbase/mythdownloadmanager.h b/mythtv/libs/libmythbase/mythdownloadmanager.h index c49278da276..d5bf9e99e92 100644 --- a/mythtv/libs/libmythbase/mythdownloadmanager.h +++ b/mythtv/libs/libmythbase/mythdownloadmanager.h @@ -71,7 +71,8 @@ class MBASE_PUBLIC MythDownloadManager : public QObject, public MThread const QHash *headers = NULL); // Cancel a download - void cancelDownload(const QString &url); + void cancelDownload(const QString &url, bool block = true); + void cancelDownload(const QStringList &urls, bool block = true); // Generic helpers void removeListener(QObject *caller); @@ -97,8 +98,6 @@ class MBASE_PUBLIC MythDownloadManager : public QObject, public MThread void downloadError(QNetworkReply::NetworkError errorCode); void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void downloadCanceled(); - private: // Notification from RemoteFile downloads void downloadFinished(MythDownloadInfo *dlInfo); @@ -120,6 +119,7 @@ class MBASE_PUBLIC MythDownloadManager : public QObject, public MThread void downloadRemoteFile(MythDownloadInfo *dlInfo); void downloadQNetworkRequest(MythDownloadInfo *dlInfo); bool downloadNow(MythDownloadInfo *dlInfo, bool deleteInfo = true); + void downloadCanceled(void); QUrl redirectUrl(const QUrl& possibleRedirectUrl, const QUrl& oldRedirectUrl) const;