BWAPI
|
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 }