1 /* 2 * TaskManager.cpp 3 * OpenLieroX 4 * 5 * Created by Albert Zeyer on 09.02.09. 6 * code under LGPL 7 * 8 */ 9 10 #include "ThreadPool.h" 11 #include "TaskManager.h" 12 #include "Debug.h" 13 #include "ReadWriteLock.h" 14 #include "Command.h" 15 16 TaskManager* taskManager = NULL; 17 InitTaskManager()18void InitTaskManager() { 19 if(!taskManager) { 20 taskManager = new TaskManager(); 21 } 22 } 23 UnInitTaskManager()24void UnInitTaskManager() { 25 if(taskManager) { 26 delete taskManager; 27 taskManager = NULL; 28 } 29 } 30 31 TaskManager()32TaskManager::TaskManager() { 33 quitSignal = false; 34 mutex = SDL_CreateMutex(); 35 taskFinished = SDL_CreateCond(); 36 queueThreadWakeup = SDL_CreateCond(); 37 38 struct QueuedTaskHandler : Action { 39 TaskManager* manager; 40 QueuedTaskHandler(TaskManager* m) : manager(m) {} 41 int handle() { 42 ScopedLock lock(manager->mutex); 43 while(true) { 44 if(manager->queuedTasks.size() > 0) { 45 Action* act = manager->queuedTasks.front(); 46 manager->queuedTasks.pop_front(); 47 SDL_mutexV(manager->mutex); 48 act->handle(); 49 delete act; 50 SDL_mutexP(manager->mutex); 51 continue; 52 } 53 if(manager->quitSignal) { 54 return 0; 55 } 56 SDL_CondWait(manager->queueThreadWakeup, manager->mutex); 57 } 58 } 59 }; 60 queueThread = threadPool->start(new QueuedTaskHandler(this), "queued task handler"); 61 } 62 ~TaskManager()63TaskManager::~TaskManager() { 64 SDL_mutexP(mutex); 65 while(runningTasks.size() > 0) { 66 notes << "waiting for " << runningTasks.size() << " task(s) to finish:" << endl; 67 for(std::set<Task*>::iterator i = runningTasks.begin(); i != runningTasks.end(); ++i) { 68 notes << " " << (*i)->name << endl; 69 } 70 SDL_CondWait(taskFinished, mutex); 71 } 72 SDL_mutexV(mutex); 73 74 finishQueuedTasks(); 75 76 SDL_DestroyMutex(mutex); 77 SDL_DestroyCond(taskFinished); 78 SDL_DestroyCond(queueThreadWakeup); 79 } 80 81 start(Task * t,bool queued)82void TaskManager::start(Task* t, bool queued) { 83 Mutex::ScopedLock tlock(t->mutex); 84 85 { 86 ScopedLock lock(mutex); 87 runningTasks.insert(t); 88 } 89 90 struct TaskHandler : Action { 91 Task* task; 92 int handle() { 93 { 94 Mutex::ScopedLock lock(task->mutex); 95 task->state = Task::TS_QUEUED ? Task::TS_RUNNINGQUEUED : Task::TS_RUNNING; 96 } 97 int ret = task->handle(); 98 if(task->manager == NULL) { 99 errors << "TaskManager::TaskHandler: invalid task with unset manager" << endl; 100 return ret; 101 } 102 SDL_mutexP(task->manager->mutex); 103 task->manager->runningTasks.erase(task); 104 SDL_CondSignal(task->manager->taskFinished); 105 SDL_mutexV(task->manager->mutex); 106 delete task; 107 return ret; 108 } 109 }; 110 TaskHandler* handler = new TaskHandler(); 111 handler->task = t; 112 if(t->manager != NULL) 113 errors << "Task->manager must be NULL" << endl; 114 t->manager = this; 115 116 if(!queued) { 117 t->state = Task::TS_WAITFORIMMSTART; 118 threadPool->start(handler, t->name + " handler", true); 119 } else { 120 ScopedLock lock(mutex); 121 if(quitSignal) { 122 warnings << "tried to start queued task " << t->name << " when queued task manager was already shutdown" << endl; 123 return; 124 } 125 t->state = Task::TS_QUEUED; 126 queuedTasks.push_back(handler); 127 SDL_CondSignal(queueThreadWakeup); 128 } 129 } 130 finishQueuedTasks()131void TaskManager::finishQueuedTasks() { 132 { 133 ScopedLock lock(mutex); 134 if(quitSignal) // means that we have already finished 135 return; 136 quitSignal = true; 137 SDL_CondSignal(queueThreadWakeup); 138 } 139 140 threadPool->wait(queueThread); 141 queueThread = NULL; 142 } 143 144 dumpState(CmdLineIntf & cli) const145void TaskManager::dumpState(CmdLineIntf& cli) const { 146 ScopedLock lock(mutex); 147 for(std::set<Task*>::const_iterator i = runningTasks.begin(); i != runningTasks.end(); ++i) { 148 Task::State state; 149 { 150 Mutex::ScopedLock lock((*i)->mutex); 151 state = (*i)->state; 152 } 153 switch(state) { 154 case Task::TS_QUEUED: cli.writeMsg("task '" + (*i)->name + "': queued for execution"); break; 155 case Task::TS_WAITFORIMMSTART: cli.writeMsg("task '" + (*i)->name + "': wait for immediate start"); break; 156 case Task::TS_RUNNINGQUEUED: cli.writeMsg("task '" + (*i)->name + "': running from queue"); break; 157 case Task::TS_RUNNING: cli.writeMsg("task '" + (*i)->name + "': running independently"); break; 158 case Task::TS_INVALID: cli.writeMsg("task '" + (*i)->name + "': invalid state"); break; 159 } 160 } 161 if(runningTasks.size() == 0) 162 cli.writeMsg("no tasks queued/running"); 163 } 164 165