File indexing completed on 2024-04-28 04:20:53

0001 // SPDX-FileCopyrightText: 2012-2022 The KPhotoAlbum Development Team
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-or-later
0004 
0005 #include "JobManager.h"
0006 
0007 #include "JobInfo.h"
0008 
0009 #include <ImageManager/AsyncLoader.h>
0010 
0011 #include <QThread>
0012 
0013 /**
0014   \class BackgroundTaskManager::JobManager
0015   \brief Engine for running background jobs
0016 
0017   This is the engine for running background jobs. Each job is a subclass of
0018   \ref BackgroundTaskManager::JobInterface. The jobs are added using \ref addJob.
0019 
0020   Currently the jobs are executed one after the other on the main thread, but down the road I
0021   imagine it will provide for running jobs on secondary threads. The jobs would need to
0022   indicate that that is a possibility.
0023 */
0024 
0025 BackgroundTaskManager::JobManager *BackgroundTaskManager::JobManager::s_instance = nullptr;
0026 
0027 BackgroundTaskManager::JobManager::JobManager()
0028     : m_isPaused(false)
0029 {
0030 }
0031 
0032 bool BackgroundTaskManager::JobManager::shouldExecute() const
0033 {
0034     return m_queue.hasForegroundTasks() || !m_isPaused;
0035 }
0036 
0037 int BackgroundTaskManager::JobManager::maxJobCount() const
0038 {
0039     // See comment in ImageManager::AsyncLoader::init()
0040     // We will at least have one active background task at the time, as some of them
0041     // currently aren't that much for background stuff. The key example of this is generating video thumbnails.
0042     const int max = qMin(3, QThread::idealThreadCount());
0043     int count = qMax(1, max - ImageManager::AsyncLoader::instance()->activeCount() - 1);
0044     return count;
0045 }
0046 
0047 void BackgroundTaskManager::JobManager::execute()
0048 {
0049     if (m_queue.isEmpty())
0050         return;
0051 
0052     if (!shouldExecute())
0053         return;
0054 
0055     while (m_active.count() < maxJobCount() && !m_queue.isEmpty()) {
0056         JobInterface *job = m_queue.dequeue();
0057         connect(job, &JobInterface::completed, this, &JobManager::jobCompleted);
0058         m_active.append(job);
0059         Q_EMIT jobStarted(job);
0060         job->start();
0061     }
0062 }
0063 
0064 void BackgroundTaskManager::JobManager::addJob(BackgroundTaskManager::JobInterface *job)
0065 {
0066     m_queue.enqueue(job, job->priority());
0067     execute();
0068 }
0069 
0070 BackgroundTaskManager::JobManager *BackgroundTaskManager::JobManager::instance()
0071 {
0072     if (!s_instance)
0073         s_instance = new JobManager;
0074     return s_instance;
0075 }
0076 
0077 int BackgroundTaskManager::JobManager::activeJobCount() const
0078 {
0079     return m_active.count();
0080 }
0081 
0082 BackgroundTaskManager::JobInfo *BackgroundTaskManager::JobManager::activeJob(int index) const
0083 {
0084     if (index < m_active.count())
0085         return m_active[index];
0086     return nullptr;
0087 }
0088 
0089 int BackgroundTaskManager::JobManager::futureJobCount() const
0090 {
0091     return m_queue.count();
0092 }
0093 
0094 BackgroundTaskManager::JobInfo *BackgroundTaskManager::JobManager::futureJob(int index) const
0095 {
0096     return m_queue.peek(index);
0097 }
0098 
0099 bool BackgroundTaskManager::JobManager::isPaused() const
0100 {
0101     return m_isPaused;
0102 }
0103 
0104 bool BackgroundTaskManager::JobManager::hasActiveJobs() const
0105 {
0106     return !m_active.isEmpty();
0107 }
0108 
0109 void BackgroundTaskManager::JobManager::jobCompleted()
0110 {
0111     JobInterface *job = qobject_cast<JobInterface *>(sender());
0112     Q_ASSERT(job);
0113     Q_EMIT jobEnded(job);
0114     m_active.removeAll(job);
0115     job->deleteLater();
0116     execute();
0117 }
0118 
0119 void BackgroundTaskManager::JobManager::togglePaused()
0120 {
0121     m_isPaused = !m_isPaused;
0122     execute();
0123 }
0124 // vi:expandtab:tabstop=4 shiftwidth=4:
0125 
0126 #include "moc_JobManager.cpp"