Timing.h

Go to the documentation of this file.
00001 #ifndef __LDK_TIMING_HH__
00002 #define __LDK_TIMING_HH__
00003 
00005 //   Copyright (C) 2003-2006 Lorien Dunn.
00006 //
00007 //   Contact: loriendunn AT users DOT sourceforge DOT net
00008 //
00009 //   This software is provided 'as-is', without any express or implied warranty.
00010 //   In no event will the authors be held liable for any damages arising from
00011 //   the use of this software.
00012 //
00013 //   Permission is granted to anyone to use this software for any purpose,
00014 //   including commercial applications, and to alter it and redistribute it
00015 //   freely, subject to the following restrictions:
00016 //
00017 //   1. The origin of this software must not be misrepresented; you must not
00018 //   claim that you wrote the original software. If you use this software in a
00019 //   product, an acknowledgment in the product documentation would be
00020 //   appreciated but is not required.
00021 //
00022 //   2. Altered source versions must be plainly marked as such, and must not be
00023 //   misrepresented as being the original software.
00024 //
00025 //   3. This notice may not be removed or altered from any source distribution.
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 //just to make the compiler complain if you try passing a date as an ID :)
00145 //NB empty structs are part of the C++ standard
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     //called internally. Do not touch.
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 }//namespace LDK
00513 
00514 
00515 
00516 
00517 
00518 #endif //__LDK_TIMING_HH__

Generated on Fri Aug 17 18:32:26 2007 for LDK by  doxygen 1.5.1