// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdmisc.h" #include "nel/misc/task_manager.h" #include "nel/misc/big_file.h" using namespace std; #define NLMISC_DONE_TASK_SIZE 20 namespace NLMISC { /* * Constructor */ CTaskManager::CTaskManager() : _RunningTask (""), _TaskQueue (""), _DoneTaskQueue ("") { _IsTaskRunning = false; _ThreadRunning = true; CSynchronized::CAccessor currentTask(&_RunningTask); currentTask.value () = ""; _Thread = IThread::create(this); _Thread->start(); _ChangePriorityCallback = NULL; } /* * Destructeur */ CTaskManager::~CTaskManager() { _ThreadRunning = false; while(!_ThreadRunning) nlSleep(10); // There should be no remaining Tasks CSynchronized >::CAccessor acces(&_TaskQueue); nlassert(acces.value().empty()); _Thread->wait(); delete _Thread; _Thread = NULL; } // Manage TaskQueue void CTaskManager::run(void) { IRunnable *runnableTask; float priorityTask = 0.f; while(_ThreadRunning) { { CSynchronized >::CAccessor acces(&_TaskQueue); if(acces.value().empty()) { runnableTask = NULL; } else { // Update task priorities changeTaskPriority (); // Get the best task list &taskList = acces.value(); list::iterator ite = taskList.begin(); list::iterator bestIte = ite; while (ite != taskList.end()) { if (ite->Priority < bestIte->Priority) bestIte = ite; // Next task; ite++; } _IsTaskRunning = true; runnableTask = bestIte->Task; priorityTask = bestIte->Priority; taskList.erase (bestIte); } } if(runnableTask) { { CSynchronized::CAccessor currentTask(&_RunningTask); string temp; runnableTask->getName(temp); currentTask.value () = temp + " " + toString (priorityTask); } runnableTask->run(); { CSynchronized::CAccessor currentTask(&_RunningTask); CSynchronized >::CAccessor doneTask(&_DoneTaskQueue); doneTask.value().push_front (currentTask.value ()); currentTask.value () = ""; if (doneTask.value().size () > NLMISC_DONE_TASK_SIZE) doneTask.value().resize (NLMISC_DONE_TASK_SIZE); } _IsTaskRunning = false; } else { sleepTask(); } } CBigFile::getInstance().currentThreadFinished(); _ThreadRunning = true; } // Add a task to TaskManager void CTaskManager::addTask(IRunnable *r, float priority) { CSynchronized >::CAccessor acces(&_TaskQueue); acces.value().push_back(CWaitingTask(r, priority)); } /// Delete a task, only if task is not running, return true if found and deleted bool CTaskManager::deleteTask(IRunnable *r) { CSynchronized >::CAccessor acces(&_TaskQueue); for(list::iterator it = acces.value().begin(); it != acces.value().end(); it++) { if(it->Task == r) { acces.value().erase(it); return true; } } return false; } /// Task list size uint CTaskManager::taskListSize(void) { CSynchronized >::CAccessor acces(&_TaskQueue); return (uint)acces.value().size(); } void CTaskManager::waitCurrentTaskToComplete () { while (_IsTaskRunning) sleepTask(); } // *************************************************************************** void CTaskManager::dump (std::vector &result) { CSynchronized::CAccessor accesCurrent(&_RunningTask); CSynchronized >::CAccessor acces(&_TaskQueue); CSynchronized >::CAccessor accesDone(&_DoneTaskQueue); const list &taskList = acces.value(); const deque &taskDone = accesDone.value(); const string &taskCurrent = accesCurrent.value(); // Resize the destination array result.clear (); result.reserve (taskList.size () + taskDone.size () + 1); // Add the done strings deque::const_reverse_iterator iteDone = taskDone.rbegin (); while (iteDone != taskDone.rend ()) { result.push_back ("Done : " + *iteDone); // Next task iteDone++; } // Add the current string if (!taskCurrent.empty()) { result.push_back ("Current : " + taskCurrent); } // Add the waiting strings list::const_iterator ite = taskList.begin (); while (ite != taskList.end ()) { string name; ite->Task->getName (name); result.push_back ("Waiting : " + name + " " + toString(ite->Priority)); // Next task ite++; } } // *************************************************************************** void CTaskManager::clearDump() { CSynchronized >::CAccessor accesDone(&_DoneTaskQueue); accesDone.value().clear(); } // *************************************************************************** uint CTaskManager::getNumWaitingTasks() { CSynchronized >::CAccessor acces(&_TaskQueue); return (uint)acces.value().size(); } // *************************************************************************** void CTaskManager::changeTaskPriority () { if (_ChangePriorityCallback) { CSynchronized >::CAccessor acces(&_TaskQueue); list &taskList = acces.value(); list::iterator ite = taskList.begin(); while(ite != taskList.end()) { // Get the new priority ite->Priority = _ChangePriorityCallback->getTaskPriority(*(ite->Task)); // Next task ite++; } } } // *************************************************************************** void CTaskManager::registerTaskPriorityCallback (IChangeTaskPriority *callback) { _ChangePriorityCallback = callback; } // *************************************************************************** } // NLMISC