1 /** 2 * UGENE - Integrated Bioinformatics Tools. 3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru> 4 * http://ugene.net 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 * MA 02110-1301, USA. 20 */ 21 22 #ifndef _U2_TASK_SCHEDULER_IMPL_H_ 23 #define _U2_TASK_SCHEDULER_IMPL_H_ 24 25 #include <QMap> 26 #include <QMutex> 27 #include <QThread> 28 #include <QTimer> 29 #include <QWaitCondition> 30 31 #include <U2Core/Task.h> 32 #include <U2Core/global.h> 33 34 namespace U2 { 35 36 class TaskInfo; 37 class AppResourcePool; 38 class AppResource; 39 40 /** 41 * Some systems can go to hibernation during UGENE work. 42 * This class prevents this behavior if top-level tasks exist. 43 */ 44 class SleepPreventer { 45 public: ~SleepPreventer()46 virtual ~SleepPreventer() { 47 } capture()48 virtual void capture() { 49 } release()50 virtual void release() { 51 } 52 }; 53 54 class TaskThread : public QThread { 55 Q_OBJECT 56 public: 57 TaskThread(TaskInfo *_ti); 58 void run(); 59 void resume(); 60 QList<Task *> getProcessedSubtasks() const; 61 void appendProcessedSubtask(Task *); 62 63 TaskInfo *ti; 64 QObject *finishEventListener; 65 QMutex subtasksLocker; 66 QList<Task *> unconsideredNewSubtasks; 67 volatile bool newSubtasksObtained; 68 69 QWaitCondition pauser; 70 volatile bool isPaused; 71 QMutex pauseLocker; 72 signals: 73 void si_processMySubtasks(); 74 75 protected: 76 bool event(QEvent *event); 77 78 private: 79 void getNewSubtasks(); 80 void terminateMessageLoop(); 81 void pause(); 82 83 QList<Task *> processedSubtasks; 84 }; 85 86 class TaskInfo { 87 public: TaskInfo(Task * t,TaskInfo * p)88 TaskInfo(Task *t, TaskInfo *p) 89 : task(t), parentTaskInfo(p), wasPrepared(false), subtasksWereCanceled(false), selfRunFinished(false), 90 hasLockedPrepareResources(false), hasLockedRunResources(false), 91 prevProgress(0), numPreparedSubtasks(0), numRunningSubtasks(0), numFinishedSubtasks(0), thread(nullptr) { 92 } 93 94 virtual ~TaskInfo(); 95 96 // true if task state >= RUN && thread is finished or not used at all 97 98 Task *task; 99 TaskInfo *parentTaskInfo; 100 QList<Task *> newSubtasks; 101 102 bool wasPrepared; // 'true' if prepare() was called for the task 103 bool subtasksWereCanceled; // 'true' if canceled task has called cancel() on its subtasks 104 bool selfRunFinished; // indicates that the 'run' method of this task was finished 105 bool hasLockedPrepareResources; // true if there were resource locks for 'prepare' stage 106 bool hasLockedRunResources; // true if there were resource locks for 'run' stage 107 108 int prevProgress; // used for TaskProgress_Manual 109 QString prevDesc; 110 111 int numPreparedSubtasks; 112 int numRunningSubtasks; 113 int numFinishedSubtasks; 114 115 TaskThread *thread; 116 numActiveSubtasks()117 inline int numActiveSubtasks() const { 118 return numPreparedSubtasks + numRunningSubtasks; 119 } 120 }; 121 122 class U2PRIVATE_EXPORT TaskSchedulerImpl : public TaskScheduler { 123 Q_OBJECT 124 public: 125 using TaskScheduler::onSubTaskFinished; 126 127 TaskSchedulerImpl(AppResourcePool *rp); 128 ~TaskSchedulerImpl(); 129 130 virtual void registerTopLevelTask(Task *t); 131 132 virtual void unregisterTopLevelTask(Task *t); 133 getTopLevelTasks()134 const QList<Task *> &getTopLevelTasks() const { 135 return topLevelTasks; 136 } 137 138 Task *getTopLevelTaskById(qint64 id) const; 139 140 QDateTime estimatedFinishTime(Task *) const; 141 142 virtual void cancelTask(Task *t); 143 144 virtual void cancelAllTasks(); 145 146 virtual QString getStateName(Task *t) const; 147 addThreadId(qint64 taskId,Qt::HANDLE id)148 void addThreadId(qint64 taskId, Qt::HANDLE id) { /*threadIds.insert(taskId, id);*/ 149 threadIds[taskId] = id; 150 } removeThreadId(qint64 taskId)151 void removeThreadId(qint64 taskId) { 152 threadIds.remove(taskId); 153 } getNameByThreadId(Qt::HANDLE id)154 qint64 getNameByThreadId(Qt::HANDLE id) const { 155 return threadIds.key(id); 156 } 157 void pauseThreadWithTask(const Task *task); 158 void resumeThreadWithTask(const Task *task); 159 void onSubTaskFinished(TaskThread *thread, Task *subtask); 160 161 private slots: 162 void update(); 163 void sl_threadFinished(); 164 void sl_processSubtasks(); 165 166 private: 167 bool processFinishedTasks(); 168 void unregisterFinishedTopLevelTasks(); 169 void processNewSubtasks(); 170 void prepareNewTasks(); 171 void runReady(); 172 173 bool readyToFinish(TaskInfo *ti); 174 bool addToPriorityQueue(Task *t, TaskInfo *parentInfo); // return true if added. Failure can be caused if a task requires resources 175 void runThread(TaskInfo *pi); 176 void stopTask(Task *t); 177 void updateTaskProgressAndDesc(TaskInfo *ti); 178 void promoteTask(TaskInfo *ti, Task::State newState); 179 void deleteTask(Task *t); 180 void finishSubtasks(TaskInfo *pti); 181 182 QString tryLockResources(Task *task, bool prepareStage, bool &hasLockedResourcesAfterCall); // returns error message 183 void releaseResources(TaskInfo *ti, bool prepareStage); 184 185 void propagateStateToParent(Task *t); 186 void updateOldTasksPriority(); 187 void checkSerialPromotion(TaskInfo *pti, Task *subtask); 188 void createSleepPreventer(); 189 190 private: 191 QTimer timer; 192 QList<Task *> topLevelTasks; 193 QList<TaskInfo *> priorityQueue; 194 QList<TaskInfo *> tasksWithNewSubtasks; 195 QList<Task *> newTasks; 196 QList<Task *> loadingTasks; 197 QStringList stateNames; 198 QMap<quint64, Qt::HANDLE> threadIds; 199 200 AppResourcePool *resourcePool; 201 AppResource *threadsResource; 202 bool stateChangesObserved; 203 bool stateIsLoaded; 204 SleepPreventer *sleepPreventer; 205 }; 206 207 } // namespace U2 208 #endif 209