Enumerate drives in seperate thread

Ref #87
This commit is contained in:
Floris Bos 2020-07-02 23:31:20 +02:00
parent 6069e8f441
commit 755d7dc6ab
8 changed files with 115 additions and 23 deletions

View file

@ -19,7 +19,7 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
# Adding headers explicity so they are displayed in Qt Creator # Adding headers explicity so they are displayed in Qt Creator
set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h driveformatthread.h powersaveblocker.h set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h drivelistmodelpollthread.h driveformatthread.h powersaveblocker.h
downloadthread.h downloadextractthread.h localfileextractthread.h dependencies/mountutils/src/mountutils.hpp) downloadthread.h downloadextractthread.h localfileextractthread.h dependencies/mountutils/src/mountutils.hpp)
# Add dependencies # Add dependencies
@ -67,7 +67,7 @@ if (NOT atomicbuiltin)
endif() endif()
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp" set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp"
"drivelistitem.cpp" "drivelistmodel.cpp" "downloadthread.cpp" "downloadextractthread.cpp" "drivelistitem.cpp" "drivelistmodel.cpp" "drivelistmodelpollthread.cpp" "downloadthread.cpp" "downloadextractthread.cpp"
"driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "qml.qrc") "driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "qml.qrc")
find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg OPTIONAL_COMPONENTS Widgets) find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg OPTIONAL_COMPONENTS Widgets)

View file

@ -20,6 +20,9 @@ DriveListModel::DriveListModel(QObject *parent)
{isScsiRole, "isScsi"}, {isScsiRole, "isScsi"},
{mountpointsRole, "mountpoints"} {mountpointsRole, "mountpoints"}
}; };
// Enumerate drives in seperate thread, but process results in UI thread
connect(&_thread, SIGNAL(newDriveList(std::vector<Drivelist::DeviceDescriptor>)), SLOT(processDriveList(std::vector<Drivelist::DeviceDescriptor>)));
} }
int DriveListModel::rowCount(const QModelIndex &) const int DriveListModel::rowCount(const QModelIndex &) const
@ -45,11 +48,10 @@ QVariant DriveListModel::data(const QModelIndex &index, int role) const
return _drivelist.values().at(row)->property(propertyName); return _drivelist.values().at(row)->property(propertyName);
} }
void DriveListModel::refreshDriveList() void DriveListModel::processDriveList(std::vector<Drivelist::DeviceDescriptor> l)
{ {
bool changes = false; bool changes = false;
bool filterSystemDrives = DRIVELIST_FILTER_SYSTEM_DRIVES; bool filterSystemDrives = DRIVELIST_FILTER_SYSTEM_DRIVES;
auto l = Drivelist::ListStorageDevices();
QSet<QString> drivesInNewList; QSet<QString> drivesInNewList;
for (auto &i: l) for (auto &i: l)
@ -117,3 +119,13 @@ void DriveListModel::refreshDriveList()
if (changes) if (changes)
endResetModel(); endResetModel();
} }
void DriveListModel::startPolling()
{
_thread.start();
}
void DriveListModel::stopPolling()
{
_thread.stop();
}

View file

@ -10,25 +10,30 @@
#include <QMap> #include <QMap>
#include <QHash> #include <QHash>
#include "drivelistitem.h" #include "drivelistitem.h"
#include "drivelistmodelpollthread.h"
class DriveListModel : public QAbstractListModel class DriveListModel : public QAbstractListModel
{ {
Q_OBJECT
public: public:
DriveListModel(QObject *parent = nullptr); DriveListModel(QObject *parent = nullptr);
virtual int rowCount(const QModelIndex &) const; virtual int rowCount(const QModelIndex &) const;
virtual QHash<int, QByteArray> roleNames() const; virtual QHash<int, QByteArray> roleNames() const;
virtual QVariant data(const QModelIndex &index, int role) const; virtual QVariant data(const QModelIndex &index, int role) const;
void startPolling();
void stopPolling();
enum driveListRoles { enum driveListRoles {
deviceRole = Qt::UserRole + 1, descriptionRole, sizeRole, isUsbRole, isScsiRole, mountpointsRole deviceRole = Qt::UserRole + 1, descriptionRole, sizeRole, isUsbRole, isScsiRole, mountpointsRole
}; };
public slots: public slots:
void refreshDriveList(); void processDriveList(std::vector<Drivelist::DeviceDescriptor> l);
protected: protected:
QMap<QString,DriveListItem *> _drivelist; QMap<QString,DriveListItem *> _drivelist;
QHash<int, QByteArray> _rolenames; QHash<int, QByteArray> _rolenames;
DriveListModelPollThread _thread;
}; };
#endif // DRIVELISTMODEL_H #endif // DRIVELISTMODEL_H

View file

@ -0,0 +1,47 @@
#include "drivelistmodelpollthread.h"
#include <QElapsedTimer>
#include <QDebug>
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
*/
DriveListModelPollThread::DriveListModelPollThread(QObject *parent)
: QThread(parent), _terminate(false)
{
qRegisterMetaType< std::vector<Drivelist::DeviceDescriptor> >( "std::vector<Drivelist::DeviceDescriptor>" );
}
DriveListModelPollThread::~DriveListModelPollThread()
{
_terminate = true;
if (!wait(2000)) {
terminate();
}
}
void DriveListModelPollThread::stop()
{
_terminate = true;
}
void DriveListModelPollThread::start()
{
_terminate = false;
QThread::start();
}
void DriveListModelPollThread::run()
{
QElapsedTimer t1;
while (!_terminate)
{
t1.start();
emit newDriveList( Drivelist::ListStorageDevices() );
if (t1.elapsed() > 1000)
qDebug() << "Enumerating drives took a long time:" << t1.elapsed()/1000.0 << "seconds";
QThread::sleep(1);
}
}

View file

@ -0,0 +1,29 @@
#ifndef DRIVELISTMODELPOLLTHREAD_H
#define DRIVELISTMODELPOLLTHREAD_H
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
*/
#include <QThread>
#include "dependencies/drivelist/src/drivelist.hpp"
class DriveListModelPollThread : public QThread
{
Q_OBJECT
public:
DriveListModelPollThread(QObject *parent = nullptr);
~DriveListModelPollThread();
void start();
void stop();
protected:
bool _terminate;
virtual void run() override;
signals:
void newDriveList(std::vector<Drivelist::DeviceDescriptor> list);
};
#endif // DRIVELISTMODELPOLLTHREAD_H

View file

@ -323,10 +323,16 @@ void ImageWriter::setCustomOsListUrl(const QUrl &url)
_repo = url; _repo = url;
} }
/* Refresh the list of available drives */ /* Start polling the list of available drives */
void ImageWriter::refreshDriveList() void ImageWriter::startDriveListPolling()
{ {
_drivelist.refreshDriveList(); _drivelist.startPolling();
}
/* Stop polling the list of available drives */
void ImageWriter::stopDriveListPolling()
{
_drivelist.stopPolling();
} }
DriveListModel *ImageWriter::getDriveList() DriveListModel *ImageWriter::getDriveList()

View file

@ -48,10 +48,13 @@ public:
/* Return true if url is in our local disk cache */ /* Return true if url is in our local disk cache */
Q_INVOKABLE bool isCached(const QUrl &url, const QByteArray &sha256); Q_INVOKABLE bool isCached(const QUrl &url, const QByteArray &sha256);
/* Refresh the list of available drives */ /* Start polling the list of available drives */
Q_INVOKABLE void refreshDriveList(); Q_INVOKABLE void startDriveListPolling();
/* Return list of available drives. Call refreshDriveList() first */ /* Stop polling the list of available drives */
Q_INVOKABLE void stopDriveListPolling();
/* Return list of available drives. Call startDriveListPolling() first */
DriveListModel *getDriveList(); DriveListModel *getDriveList();
/* Utility function to return filename part from URL */ /* Utility function to return filename part from URL */

View file

@ -149,8 +149,7 @@ ApplicationWindow {
Layout.preferredWidth: 100 Layout.preferredWidth: 100
Layout.fillWidth: true Layout.fillWidth: true
onClicked: { onClicked: {
imageWriter.refreshDriveList() imageWriter.startDriveListPolling()
drivePollTimer.start()
dstpopup.open() dstpopup.open()
dstlist.forceActiveFocus() dstlist.forceActiveFocus()
} }
@ -546,6 +545,7 @@ ApplicationWindow {
height: parent.height-50 height: parent.height-50
padding: 0 padding: 0
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
onClosed: imageWriter.stopDriveListPolling()
// background of title // background of title
Rectangle { Rectangle {
@ -616,7 +616,6 @@ ApplicationWindow {
if (currentIndex == -1) if (currentIndex == -1)
return return
drivePollTimer.stop()
dstpopup.close() dstpopup.close()
imageWriter.setDst(currentItem.device, currentItem.size) imageWriter.setDst(currentItem.device, currentItem.size)
dstbutton.text = currentItem.description dstbutton.text = currentItem.description
@ -628,7 +627,6 @@ ApplicationWindow {
if (currentIndex == -1) if (currentIndex == -1)
return return
drivePollTimer.stop()
dstpopup.close() dstpopup.close()
imageWriter.setDst(currentItem.device, currentItem.size) imageWriter.setDst(currentItem.device, currentItem.size)
dstbutton.text = currentItem.description dstbutton.text = currentItem.description
@ -720,7 +718,6 @@ ApplicationWindow {
} }
onClicked: { onClicked: {
drivePollTimer.stop()
dstpopup.close() dstpopup.close()
imageWriter.setDst(device, size) imageWriter.setDst(device, size)
dstbutton.text = description dstbutton.text = description
@ -784,13 +781,6 @@ ApplicationWindow {
property alias y: window.y property alias y: window.y
} }
/* Timer for polling drivelist changes */
Timer {
id: drivePollTimer
repeat: true
onTriggered: imageWriter.refreshDriveList()
}
/* Utility functions */ /* Utility functions */
function httpRequest(url, callback) { function httpRequest(url, callback) {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();