BWAPI
SPAR/AIModule/SparAIModule/Scheduler/Scheduler.h
Go to the documentation of this file.
00001 #pragma once
00002 #include "../Utils/Component.h"
00003 #include "../Utils/SafeMultiset.h"
00004 #include "../Utils/Task.h"
00005 #include <cassert>
00006 #include <string>
00007 #include <vector>
00008 #include "timer.h"
00009 
00013 class Scheduler
00014 {
00015 public:
00016   class InternalSchedulerTask;
00020   struct TaskComparator
00021   {
00022     bool operator() (const InternalSchedulerTask* task1, const InternalSchedulerTask* task2) const;
00023   };
00024   typedef SafeMultiset<InternalSchedulerTask*, TaskComparator> TaskList;
00025 
00026 public:
00030   struct TaskID
00031   {
00032     TaskID()
00033       : m_isActive(false)
00034     {
00035     }
00039     TaskList::iterator m_posInMultiset;
00043     bool m_isActive;
00044   };
00045 
00051   class InternalSchedulerTask : public RunnableTask
00052   {
00053   public:
00058     InternalSchedulerTask(const Component& owner)
00059       : RunnableTask(owner)
00060     {
00061     }
00062 
00063 #ifdef _DEBUG_COMPONENT
00064     ~InternalSchedulerTask()
00065     {
00066       m_owner.onDeleteTask(this);
00067     }
00068 #endif
00069 
00072     bool isActive() const
00073     {
00074       return m_taskID.m_isActive;
00075     }
00076 
00077   private:
00078     friend class Scheduler;
00079     //
00080     // The following members are not visible to the client; they are only stored as part of the task
00081     // to eliminate the need to dynamically create them (to reduce the 'new' operations).
00082     //
00083 
00087     TaskID m_taskID;
00091     unsigned int m_priority;
00095     size_t m_period;
00099     size_t m_executionFrame;
00100   };
00101 
00102 public:
00103   static const int MILLISECOND_PER_FRAME = 40;
00104 
00105   Scheduler()
00106     : m_tasks(TaskComparator())
00107   {
00108   }
00109 
00113         //~Scheduler();
00114 
00115   void initialize() {};
00116 
00120         void onFrame()
00121   {
00122     //SPAR_LOG(LogTypes::GENERAL_ERROR, "%d, %d, %d", BWAPI::Broodwar->getLatencyTime(), BWAPI::Broodwar->getLatencyFrames(), BWAPI::Broodwar->getLatencyTime() / BWAPI::Broodwar->getLatencyFrames());
00123     // We need a better function to evaluate the time available at each frame
00124     m_tasks.do_while(ExecuteTask(*this, 99999999/*(Scheduler::MILLISECOND_PER_FRAME * Spar->getTimer().timeFrequency()) / 1000*/)); 
00125   }
00126 
00134         void activate(InternalSchedulerTask* task, unsigned int priority, size_t period, size_t waitingTimeBeforeExecution)
00135   {
00136 #ifdef _DEBUG_COMPONENT
00137     task->m_owner.onActivateTask(task);
00138 #endif
00139     task->m_priority = priority;
00140     task->m_period = period;
00141     task->m_executionFrame = BWAPI::Broodwar->getFrameCount() + waitingTimeBeforeExecution;
00142     TaskList::iterator it = m_tasks.insert(task);
00143     task->m_taskID.m_posInMultiset = it;
00144     task->m_taskID.m_isActive = true;
00145   }
00146 
00151   void deactivate(InternalSchedulerTask* task)
00152   {
00153     if (task->m_taskID.m_isActive)
00154     {
00155 #ifdef _DEBUG_COMPONENT
00156       task->m_owner.onDeactivateTask(task);
00157 #endif
00158       task->m_taskID.m_isActive = false;
00159       m_tasks.erase(task->m_taskID.m_posInMultiset);
00160     }
00161   }
00162 
00163   static const unsigned int SCHEDULING_MEDIUM_PRIORITY = 1000;
00164   static const unsigned int FSM_SCHEDULING_PRIORITY = SCHEDULING_MEDIUM_PRIORITY;
00165 
00166 #ifdef _DEBUG_COMPONENT
00167   template <class Function>
00168   Function for_each_task(Function function) const
00169   {
00170     return m_tasks.do_while(function);
00171   }
00172 #endif
00173 
00174 private:
00178   TaskList m_tasks;
00179 
00183   class ExecuteTask
00184   {
00185   public:
00186     ExecuteTask(Scheduler& scheduler, Timer::value_type timeLimit)
00187       : m_scheduler(scheduler)
00188       , m_timeLimit(timeLimit)
00189     {
00190     }
00191 
00198     TaskList::FunctionReturn operator()(TaskList::Wrapper& wrapper) const
00199       {
00200         //if(Spar->getTimer().currentTime() < m_timeLimit)
00201         //  return TaskList::FunctionReturn(false,true);
00202 
00203         InternalSchedulerTask* task = wrapper;
00204 
00205         if(static_cast<int>(task->m_executionFrame) > BWAPI::Broodwar->getFrameCount())
00206           return TaskList::FunctionReturn(false,true);
00207         
00208         const size_t period = task->m_period;
00209 
00210         // When running we want to allow the user to reactivate a non-periodic task
00211         if (period == 0)
00212         {
00213           m_scheduler.deactivate(task);
00214         }
00215 
00216         task->run();
00217 
00218         // At this point we have to know whether the user has deactivated explicitely the task (if it is periodic)
00219         
00220         if (period > 0)
00221         {
00222           // We do not use "task->m_taskID.m_isActive" since the user may have deactivated and restarted the task
00223           if (!wrapper.isDeleted())
00224           {
00225             m_scheduler.deactivate(task);
00226 
00227             m_scheduler.activate(task, task->m_priority, task->m_period, task->m_period);
00228           }
00229         }
00230         return TaskList::FunctionReturn(false,false);
00231       }
00232   protected:
00233     Scheduler& m_scheduler;
00234     Timer::value_type m_timeLimit;
00235   };
00236   friend class ExecuteTask;
00237 };
00238 
00239 inline bool Scheduler::TaskComparator::operator() (const InternalSchedulerTask* task1, const InternalSchedulerTask* task2) const
00240 {
00241   return task1->m_executionFrame < task2->m_executionFrame
00242     || (task1->m_executionFrame == task2->m_executionFrame
00243       && task1->m_priority < task2->m_priority);
00244 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines