00001 #ifndef __LDK_TIMING_HH__
00002 #define __LDK_TIMING_HH__
00003
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00028
00035
00036 #include "LDK/Types.h"
00037 #include "LDK/Memory.h"
00038 #include "LDK/SmartPointers.h"
00039 #include <list>
00040
00041
00042
00043 namespace LDK
00044 {
00045
00049
00056 LDK_API uint64 time();
00057
00058
00069 class Timer : public Object
00070 {
00071 private:
00072 bool mPaused;
00073 uint64 mCurrentTick;
00074 uint64 mLastTickTime;
00075 uint32 mTickDur;
00076 public:
00077
00081 inline Timer(uint32 tickDuration=1)
00082 : mPaused(false)
00083 , mCurrentTick(0)
00084 , mLastTickTime(LDK::time())
00085 , mTickDur(tickDuration)
00086 {
00087 assert(tickDuration);
00088 }
00089
00092 inline uint32 tickDuration() const { return mTickDur; }
00096 inline void tickDuration(uint32 duration)
00097 {
00098 assert(duration);
00099 mTickDur = duration;
00100 }
00101
00106 inline uint64 time()
00107 {
00108 uint32 timeDiff = (uint32) (LDK::time() - mLastTickTime);
00109 if(!mPaused && timeDiff >= mTickDur)
00110 {
00111 mCurrentTick += timeDiff / mTickDur;
00112 }
00113 return mCurrentTick;
00114 }
00115
00120 inline void pause()
00121 {
00122 assert(!mPaused);
00123 mPaused = true;
00124 }
00129 inline void unpause()
00130 {
00131 assert(mPaused);
00132 uint64 time = LDK::time();
00133 if(time - mLastTickTime >= mTickDur)
00134 mCurrentTick++;
00135 mLastTickTime = time;
00136 mPaused = false;
00137 }
00140 inline bool isPaused() { return mPaused; }
00141 };
00142 typedef IntrusiveSmartPointer<Timer> SmartTimer;
00143
00144
00145
00146 struct TaskID_T {};
00147 typedef TaskID_T* TaskID;
00148
00156 class LDK_API Task
00157 {
00158 public:
00160 virtual ~Task() {}
00166 virtual void execute(TaskID id, uint64 dueDate, uint32 latency) = 0;
00167 };
00168
00169 class TaskData;
00178 class LDK_API Scheduler
00179 {
00180 private:
00181
00182 SmartTimer mTimer;
00183 typedef std::list<TaskData*,Allocator<TaskData*> > TaskList;
00184 TaskList* mTable;
00185 size_t mTableSize;
00186 uint64 mLastExecTime;
00187 uint64 mActiveTaskFlag;
00188 bool mCanPause;
00189
00190 friend class TaskData;
00191
00192 public:
00197 Scheduler(SmartTimer timer=NULL, size_t tableSize=5000);
00198 ~Scheduler();
00199
00200 inline SmartTimer timer() { return mTimer; }
00201 inline uint64 time() { return mTimer->time(); }
00202 inline uint64 frameTime() { return mLastExecTime; }
00203
00204 inline void pause() { mTimer->pause(); }
00205 inline void unpause() { mTimer->unpause(); }
00206 inline bool isPaused() { return mTimer->isPaused(); }
00207
00208 TaskID absolute(uint64 when, Task* task);
00209 void repeatAbsolute(TaskID id, uint64 when);
00210 inline TaskID relative(uint64 when, Task* task) { return absolute(time()+when,task); }
00211 void repeatRelative(TaskID id, uint64 when);
00212
00213 void cancel(TaskID id);
00217 void execute(uint64 time=0);
00218 void clear();
00219 };
00220
00221
00240 class LDK_API SystemScheduler : public Singleton<Scheduler>
00241 {
00242 private:
00243
00244 SystemScheduler() {}
00245 SystemScheduler(const SystemScheduler&) {}
00246 ~SystemScheduler() {}
00247 void operator=(const SystemScheduler&) {}
00248
00249 public:
00250
00251 static void initialise();
00252
00258 inline static SmartTimer timer() { return instance().timer(); }
00270 inline static uint64 time() { return instance().time(); }
00281 inline static uint64 frameTime(){ return instance().frameTime(); }
00282
00285 inline static void pause() { instance().pause(); }
00288 inline static void unpause() { instance().unpause(); }
00292 inline static bool isPaused() { return instance().isPaused(); }
00293
00303 inline static TaskID absolute(uint64 when, Task* task)
00304 {
00305 return instance().absolute(when,task);
00306 }
00307
00316 inline static TaskID relative(uint64 when, Task* task)
00317 {
00318 return instance().relative(when, task);
00319 }
00320
00331 inline static void repeatAbsolute(TaskID id, uint64 when)
00332 {
00333 instance().repeatAbsolute(id, when);
00334 }
00335
00346 inline static void repeatRelative(TaskID id, uint64 when)
00347 {
00348 instance().repeatRelative(id, when);
00349 }
00350
00355 inline static void cancel(TaskID id) { instance().cancel(id); }
00356
00358 inline static void execute() { instance().execute(); }
00359
00361 inline static void clear() { instance().clear(); }
00362 };
00363
00364
00378 class LDK_API Ticker
00379 {
00380 protected:
00381
00382 bool mRunning;
00383 Scheduler& mScheduler;
00384 uint32 mTickDur;
00385 bool mStrictTiming;
00386 TaskID mID;
00387 uint64 mCurrentTick;
00388 class LDK_API Tick;
00389 Tick* mTick;
00390
00391 class LDK_API Tick : public Task
00392 {
00393 private:
00394
00395 Ticker& mTicker;
00396
00397 public:
00398
00399 inline Tick(Ticker& ticker)
00400 : mTicker(ticker)
00401 {
00402 }
00403
00404 virtual void execute(TaskID id, uint64 dueDate, uint32 latency)
00405 {
00406 if(mTicker.mRunning)
00407 {
00408 mTicker.tick();
00409 mTicker.mCurrentTick++;
00410 if(mTicker.mStrictTiming)
00411 mTicker.mScheduler.repeatAbsolute(id,dueDate+mTicker.mTickDur);
00412 else
00413 mTicker.mScheduler.repeatRelative(id,mTicker.mTickDur);
00414 return;
00415 }
00416 mTicker.mTick = NULL;
00417 }
00418 };
00419
00420 friend class LDK_API Tick;
00421
00422 public:
00423
00430 inline Ticker(Scheduler& sched, uint32 tickDuration, bool strictTiming=true)
00431 : mRunning(false)
00432 , mScheduler(sched)
00433 , mTickDur(tickDuration)
00434 , mStrictTiming(strictTiming)
00435 , mCurrentTick(0)
00436 {
00437 assert(mTickDur);
00438 }
00439
00441 virtual ~Ticker() throw()
00442 {
00443 if(mTick)
00444 LDK::destroy<Tick>(mTick);
00445 mRunning = false;
00446 }
00447
00453 virtual void tick() {}
00454
00456 inline void start()
00457 {
00458 assert(!mRunning);
00459 if(!mTick)
00460 mTick = LDK_CREATE1(Tick,*this);
00461 mScheduler.relative(0,mTick);
00462 }
00463
00465 inline void stop()
00466 {
00467 assert(mTick);
00468 assert(mRunning);
00469 mRunning = false;
00470 mCurrentTick = 0;
00471 }
00472
00474 inline void pause()
00475 {
00476 assert(mTick);
00477 assert(mRunning);
00478 mRunning = false;
00479 }
00480
00482 inline void unpause()
00483 {
00484 assert(!mTick);
00485 assert(!mRunning);
00486 mRunning = true;
00487 mScheduler.relative(1,mTick);
00488 }
00489
00492 inline uint32 tickDuration() const { return mTickDur; }
00493
00496 inline void tickDuration(uint32 duration)
00497 {
00498 assert(duration);
00499 mTickDur = duration;
00500 }
00501
00506 inline uint64 currentTick() const { return mCurrentTick; }
00507 };
00508
00511
00512 }
00513
00514
00515
00516
00517
00518 #endif //__LDK_TIMING_HH__