Skip to content

Commit

Permalink
Use a queue to cancel downloads.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jyavenard committed Aug 12, 2013
1 parent ea2e3c8 commit c4960e5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 24 deletions.
77 changes: 56 additions & 21 deletions mythtv/libs/libmythbase/mythdownloadmanager.cpp
Expand Up @@ -240,6 +240,7 @@ void MythDownloadManager::run(void)

bool downloading = false;
bool itemsInQueue = false;
bool itemsInCancellationQueue = false;
bool waitAnyway = false;

m_queueThread = QThread::currentThread();
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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<MythDownloadInfo*> lit(m_downloadQueue);
while (lit.hasNext())
m_infoLock->lock();
foreach (QString url, urls)
{
lit.next();
dlInfo = lit.value();
if (dlInfo->m_url == url)
QMutableListIterator<MythDownloadInfo*> 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()
Expand All @@ -906,17 +938,20 @@ void MythDownloadManager::downloadCanceled()
{
lit.next();
dlInfo = lit.value();

dlInfo->m_lock.lock();

if (dlInfo->m_reply)
{
LOG(VB_FILE, LOG_DEBUG,
LOC + QString("Aborting download - user request"));
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();
Expand Down
6 changes: 3 additions & 3 deletions mythtv/libs/libmythbase/mythdownloadmanager.h
Expand Up @@ -71,7 +71,8 @@ class MBASE_PUBLIC MythDownloadManager : public QObject, public MThread
const QHash<QByteArray, QByteArray> *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);
Expand All @@ -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);
Expand All @@ -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;
Expand Down

0 comments on commit c4960e5

Please sign in to comment.