Merge pull request #628 from flowln/fix_multiple_resource_packs_crash

Fixes https://github.com/PrismLauncher/PrismLauncher/issues/624
This commit is contained in:
Sefa Eyeoglu 2022-12-19 15:35:34 +01:00
parent 3b1ab3c974
commit 5203e72199
No known key found for this signature in database
GPG Key ID: C10411294912A422
7 changed files with 47 additions and 19 deletions

View File

@ -20,6 +20,7 @@ ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent) : QAbstractL
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ResourceFolderModel::directoryChanged); connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ResourceFolderModel::directoryChanged);
connect(&m_helper_thread_task, &ConcurrentTask::finished, this, [this]{ m_helper_thread_task.clear(); });
} }
ResourceFolderModel::~ResourceFolderModel() ResourceFolderModel::~ResourceFolderModel()
@ -275,7 +276,11 @@ void ResourceFolderModel::resolveResource(Resource* res)
connect( connect(
task, &Task::finished, this, [=] { m_active_parse_tasks.remove(ticket); }, Qt::ConnectionType::QueuedConnection); task, &Task::finished, this, [=] { m_active_parse_tasks.remove(ticket); }, Qt::ConnectionType::QueuedConnection);
QThreadPool::globalInstance()->start(task); m_helper_thread_task.addTask(task);
if (!m_helper_thread_task.isRunning()) {
QThreadPool::globalInstance()->start(&m_helper_thread_task);
}
} }
void ResourceFolderModel::onUpdateSucceeded() void ResourceFolderModel::onUpdateSucceeded()

View File

@ -10,6 +10,7 @@
#include "Resource.h" #include "Resource.h"
#include "tasks/Task.h" #include "tasks/Task.h"
#include "tasks/ConcurrentTask.h"
class QSortFilterProxyModel; class QSortFilterProxyModel;
@ -197,6 +198,7 @@ class ResourceFolderModel : public QAbstractListModel {
// Represents the relationship between a resource's internal ID and it's row position on the model. // Represents the relationship between a resource's internal ID and it's row position on the model.
QMap<QString, int> m_resources_index; QMap<QString, int> m_resources_index;
ConcurrentTask m_helper_thread_task;
QMap<int, Task::Ptr> m_active_parse_tasks; QMap<int, Task::Ptr> m_active_parse_tasks;
std::atomic<int> m_next_resolution_ticket = 0; std::atomic<int> m_next_resolution_ticket = 0;
}; };

View File

@ -123,7 +123,7 @@ auto NetJob::getFailedFiles() -> QList<QString>
void NetJob::updateState() void NetJob::updateState()
{ {
emit progress(m_done.count(), m_total_size); emit progress(m_done.count(), totalSize());
setStatus(tr("Executing %1 task(s) (%2 out of %3 are done)") setStatus(tr("Executing %1 task(s) (%2 out of %3 are done)")
.arg(QString::number(m_doing.count()), QString::number(m_done.count()), QString::number(m_total_size))); .arg(QString::number(m_doing.count()), QString::number(m_done.count()), QString::number(totalSize())));
} }

View File

@ -27,18 +27,13 @@ auto ConcurrentTask::getStepTotalProgress() const -> qint64
void ConcurrentTask::addTask(Task::Ptr task) void ConcurrentTask::addTask(Task::Ptr task)
{ {
if (!isRunning()) m_queue.append(task);
m_queue.append(task);
else
qWarning() << "Tried to add a task to a running concurrent task!";
} }
void ConcurrentTask::executeTask() void ConcurrentTask::executeTask()
{ {
m_total_size = m_queue.size();
// Start the least amount of tasks needed, but at least one // Start the least amount of tasks needed, but at least one
int num_starts = std::max(1, std::min(m_total_max_size, m_total_size)); int num_starts = qMax(1, qMin(m_total_max_size, m_queue.size()));
for (int i = 0; i < num_starts; i++) { for (int i = 0; i < num_starts; i++) {
QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection); QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection);
} }
@ -73,6 +68,20 @@ bool ConcurrentTask::abort()
return suceedeed; return suceedeed;
} }
void ConcurrentTask::clear()
{
Q_ASSERT(!isRunning());
m_done.clear();
m_failed.clear();
m_queue.clear();
m_aborted = false;
m_progress = 0;
m_stepProgress = 0;
}
void ConcurrentTask::startNext() void ConcurrentTask::startNext()
{ {
if (m_aborted || m_doing.count() > m_total_max_size) if (m_aborted || m_doing.count() > m_total_max_size)
@ -101,9 +110,14 @@ void ConcurrentTask::startNext()
setStepStatus(next->isMultiStep() ? next->getStepStatus() : next->getStatus()); setStepStatus(next->isMultiStep() ? next->getStepStatus() : next->getStatus());
updateState(); updateState();
QCoreApplication::processEvents(); QMetaObject::invokeMethod(next.get(), &Task::start, Qt::QueuedConnection);
next->start(); // Allow going up the number of concurrent tasks in case of tasks being added in the middle of a running task.
int num_starts = m_total_max_size - m_doing.size();
for (int i = 0; i < num_starts; i++)
QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection);
QCoreApplication::processEvents();
} }
void ConcurrentTask::subTaskSucceeded(Task::Ptr task) void ConcurrentTask::subTaskSucceeded(Task::Ptr task)
@ -145,7 +159,7 @@ void ConcurrentTask::subTaskProgress(qint64 current, qint64 total)
void ConcurrentTask::updateState() void ConcurrentTask::updateState()
{ {
setProgress(m_done.count(), m_total_size); setProgress(m_done.count(), totalSize());
setStatus(tr("Executing %1 task(s) (%2 out of %3 are done)") setStatus(tr("Executing %1 task(s) (%2 out of %3 are done)")
.arg(QString::number(m_doing.count()), QString::number(m_done.count()), QString::number(m_total_size))); .arg(QString::number(m_doing.count()), QString::number(m_done.count()), QString::number(totalSize())));
} }

View File

@ -24,6 +24,11 @@ public:
public slots: public slots:
bool abort() override; bool abort() override;
/** Resets the internal state of the task.
* This allows the same task to be re-used.
*/
void clear();
protected protected
slots: slots:
void executeTask() override; void executeTask() override;
@ -36,6 +41,9 @@ slots:
void subTaskProgress(qint64 current, qint64 total); void subTaskProgress(qint64 current, qint64 total);
protected: protected:
// NOTE: This is not thread-safe.
[[nodiscard]] unsigned int totalSize() const { return m_queue.size() + m_doing.size() + m_done.size(); }
void setStepStatus(QString status) { m_step_status = status; emit stepStatus(status); }; void setStepStatus(QString status) { m_step_status = status; emit stepStatus(status); };
virtual void updateState(); virtual void updateState();
@ -51,7 +59,6 @@ protected:
QHash<Task*, Task::Ptr> m_failed; QHash<Task*, Task::Ptr> m_failed;
int m_total_max_size; int m_total_max_size;
int m_total_size;
qint64 m_stepProgress = 0; qint64 m_stepProgress = 0;
qint64 m_stepTotalProgress = 100; qint64 m_stepTotalProgress = 100;

View File

@ -22,6 +22,6 @@ void MultipleOptionsTask::startNext()
void MultipleOptionsTask::updateState() void MultipleOptionsTask::updateState()
{ {
setProgress(m_done.count(), m_total_size); setProgress(m_done.count(), totalSize());
setStatus(tr("Attempting task %1 out of %2").arg(QString::number(m_doing.count() + m_done.count()), QString::number(m_total_size))); setStatus(tr("Attempting task %1 out of %2").arg(QString::number(m_doing.count() + m_done.count()), QString::number(totalSize())));
} }

View File

@ -17,6 +17,6 @@ void SequentialTask::startNext()
void SequentialTask::updateState() void SequentialTask::updateState()
{ {
setProgress(m_done.count(), m_total_size); setProgress(m_done.count(), totalSize());
setStatus(tr("Executing task %1 out of %2").arg(QString::number(m_doing.count() + m_done.count()), QString::number(m_total_size))); setStatus(tr("Executing task %1 out of %2").arg(QString::number(m_doing.count() + m_done.count()), QString::number(totalSize())));
} }