Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "cxutils/timer.h"
00041 #include "cxutils/time.h"
00042 #include <cxutils/math/cxmath.h>
00043 #include <assert.h>
00044
00045 #ifdef WIN32
00046 #include <windows.h>
00047 #include <mmsystem.h>
00048 #else
00049 #include <sys/time.h>
00050 #endif
00051
00052 using namespace CxUtils;
00053
00054
00063 Timer::Callback::Function::Function(void (*func)(void* args), void* fargs)
00064 {
00065 mpFunctionPtr = func;
00066 mpFunctionArgs = fargs;
00067 }
00068
00069
00075 Timer::Callback::Function::~Function()
00076 {
00077 }
00078
00079
00085 void Timer::Callback::Function::Run()
00086 {
00087 if(mpFunctionPtr)
00088 {
00089 mpFunctionPtr(mpFunctionArgs);
00090 }
00091 }
00092
00093
00094 #ifdef WIN32
00095 class Timer::Data
00096 {
00097 public:
00098 Data()
00099 {
00100 mResult = 0;
00101 mLeaveFlag = true;
00102 mEnteredFlag = false;
00103 mStopCounter = -1;
00104 mKillTimer = false;
00105 InitializeCriticalSection(&mCritSection);
00106 InitializeCriticalSection(&mDelayCritSection);
00107 }
00108 ~Data()
00109 {
00110 if(mResult)
00111 mResult = timeKillEvent(mResult);
00112 DeleteCriticalSection(&mCritSection);
00113 DeleteCriticalSection(&mDelayCritSection);
00114 }
00115 Timer* mpTimer;
00116 static void CALLBACK PauseTimerProcedure(UINT id, UINT msg, DWORD_PTR user, DWORD_PTR one, DWORD_PTR two);
00117 static void CALLBACK TimerProcedure(UINT id, UINT msg, DWORD_PTR user, DWORD_PTR one, DWORD_PTR two);
00118 MMRESULT mResult;
00119 CRITICAL_SECTION mCritSection;
00120 CRITICAL_SECTION mDelayCritSection;
00121 volatile bool mEnteredFlag;
00122 volatile bool mLeaveFlag;
00123 volatile int mStopCounter;
00124 volatile bool mKillTimer;
00125 };
00126 #endif
00127
00128
00129
00135 Timer::Timer()
00136 {
00137 #ifdef WIN32
00138 mpTimerData = new Timer::Data();
00139 ((Timer::Data*)(mpTimerData))->mpTimer = this;
00140 #endif
00141 mTimerActive = false;
00142 mDelayTimeMs = 0;
00143 mShutdownFlag = false;
00144 }
00145
00146
00152 Timer::~Timer()
00153 {
00154 Stop();
00155 #ifdef WIN32
00156 delete mpTimerData;
00157 #endif
00158 }
00159
00160
00181 int Timer::Start(const double frequencyHz,
00182 const double hptThresholdHz)
00183 {
00184 Stop();
00185
00186 mShutdownFlag = false;
00187
00188
00189 mDelayTimeMs = (unsigned int)(1000.0/(frequencyHz + CX_EPSILON));
00190 if(mDelayTimeMs == 0)
00191 {
00192 mDelayTimeMs = 1;
00193 }
00194 #ifdef WIN32
00195 if(frequencyHz > hptThresholdHz)
00196 {
00197 ((Timer::Data *)(mpTimerData))->mKillTimer = false;
00198 ((Timer::Data *)(mpTimerData))->mResult = timeSetEvent(mDelayTimeMs,
00199 0,
00200 &Timer::Data::TimerProcedure,
00201 (DWORD_PTR)this->mpTimerData,
00202 TIME_PERIODIC);
00203 if( ((Timer::Data *)(mpTimerData))->mResult != NULL )
00204 {
00205 mTimerActive = true;
00206 return 1;
00207 }
00208 }
00209 else
00210 {
00211 if(mTimerEventThread.CreateThread(&TimerEventThread, this))
00212 {
00213 mTimerEventThread.SetThreadPriority(50);
00214 mTimerActive = true;
00215 return 1;
00216 }
00217 }
00218 #else
00219 if(mTimerEventThread.CreateThread(&TimerEventThread, this))
00220 {
00221 mTimerEventThread.SetThreadPriority(50);
00222 mTimerActive = true;
00223 return 1;
00224 }
00225 #endif
00226
00227 return 0;
00228 }
00229
00230
00231
00239 void Timer::Stop()
00240 {
00241 mShutdownFlag = true;
00242 #ifdef WIN32
00243 if(((Timer::Data *)(mpTimerData))->mResult)
00244 {
00245 ((Timer::Data *)(mpTimerData))->mKillTimer = true;
00246 ((Timer::Data *)(mpTimerData))->mResult = timeKillEvent(((Timer::Data *)(mpTimerData))->mResult);
00247 return;
00248 }
00249 ((Timer::Data *)(mpTimerData))->mKillTimer = false;
00250 #endif
00251 mTimerEventThread.StopThread(1000);
00252
00253 mTimerActive = false;
00254 }
00255
00256
00267 bool Timer::RegisterTimerEvent(Timer::Callback* timerCallback)
00268 {
00269 bool result = false;
00270 Callback::Set::iterator cb;
00271 mCallbacksMutex.Lock();
00272 cb = mCallbackObjects.find(timerCallback);
00273 if(cb == mCallbackObjects.end())
00274 {
00275 mCallbackObjects.insert(timerCallback);
00276 result = true;
00277 }
00278 mCallbacksMutex.Unlock();
00279 return result;
00280 }
00281
00282
00294 bool Timer::RegisterTimerEvent(void (*func)(void *args), void* fargs)
00295 {
00296 bool result = true;
00297 mCallbacksMutex.Lock();
00298 mCallbackFunctions.push_back(Timer::Callback::Function(func, fargs));
00299 mCallbacksMutex.Unlock();
00300 return result;
00301 }
00302
00303
00312 void Timer::RemoveTimerEvent(Timer::Callback* timerCallback)
00313 {
00314 Callback::Set::iterator cb;
00315 mCallbacksMutex.Lock();
00316 cb = mCallbackObjects.find(timerCallback);
00317 if(cb != mCallbackObjects.end())
00318 {
00319 mCallbackObjects.erase(cb);
00320 }
00321 mCallbacksMutex.Unlock();
00322 }
00323
00324
00334 void Timer::RemoveTimerEvent(void (*func)(void *args), void* fargs)
00335 {
00336 Callback::Function::List::iterator cb;
00337 mCallbacksMutex.Lock();
00338 for(cb = mCallbackFunctions.begin();
00339 cb != mCallbackFunctions.end();
00340 cb++)
00341 {
00342 if(cb->mpFunctionPtr == func && cb->mpFunctionArgs == fargs)
00343 {
00344 mCallbackFunctions.erase(cb);
00345 break;
00346 }
00347 }
00348 mCallbacksMutex.Unlock();
00349 }
00350
00351
00361 void Timer::Pause(const unsigned int ms)
00362 {
00363 if(ms > 0)
00364 {
00365 #ifdef WIN32
00366 Timer timer;
00367 EnterCriticalSection( &((Timer::Data *)(timer.mpTimerData))->mDelayCritSection );
00368
00369 if (((Timer::Data *)(timer.mpTimerData))->mResult == NULL)
00370 {
00371 ((Timer::Data *)(timer.mpTimerData))->mResult = timeSetEvent(1,
00372 0,
00373 &Timer::Data::PauseTimerProcedure,
00374 (DWORD_PTR)timer.mpTimerData,
00375 TIME_PERIODIC);
00376 assert(((Timer::Data *)(timer.mpTimerData))->mResult);
00377 }
00378
00379 ((Timer::Data *)(timer.mpTimerData))->mStopCounter = (int)ms;
00380 ((Timer::Data *)(timer.mpTimerData))->mLeaveFlag = false;
00381 ((Timer::Data *)(timer.mpTimerData))->mEnteredFlag = false;
00382 while(!((Timer::Data *)(timer.mpTimerData))->mEnteredFlag) {}
00383
00384 EnterCriticalSection(&((Timer::Data *)(timer.mpTimerData))->mCritSection);
00385 LeaveCriticalSection(&((Timer::Data *)(timer.mpTimerData))->mCritSection);
00386 LeaveCriticalSection(&((Timer::Data *)(timer.mpTimerData))->mDelayCritSection );
00387 #else
00388 usleep(ms*1000);
00389 #endif
00390 }
00391 }
00392
00393
00401 double Timer::GetTimeMs()
00402 {
00403 #ifdef WIN32
00404 LARGE_INTEGER count;
00405 static LARGE_INTEGER freq;
00406
00407 if(freq.QuadPart == 0)
00408 {
00409 if(QueryPerformanceFrequency(&freq))
00410 {
00411 freq.QuadPart /= 1000;
00412 }
00413 else
00414 {
00415
00416 freq.QuadPart = 0;
00417 return (double)CxUtils::GetTimeMs();
00418 }
00419 }
00420 if(freq.QuadPart != 0)
00421 {
00422 if(QueryPerformanceCounter(&count))
00423 {
00424 return (double)count.QuadPart/(double)freq.QuadPart;
00425 }
00426 else
00427 {
00428 return (double)CxUtils::GetTimeMs();
00429 }
00430 }
00431 return (double)CxUtils::GetTimeMs();
00432 #else
00433 return (double)CxUtils::GetTimeMs();
00434 #endif
00435 }
00436
00437
00445 double Timer::GetTimeSeconds() { return GetTimeMs()/1000.0; }
00446
00447 #ifdef WIN32
00448
00449
00457 void CALLBACK Timer::Data::PauseTimerProcedure(UINT id,
00458 UINT msg,
00459 DWORD_PTR user,
00460 DWORD_PTR one,
00461 DWORD_PTR two)
00462 {
00463 Timer::Data* pData = (Timer::Data*)user;
00464 if(pData)
00465 {
00466
00467 if (!pData->mEnteredFlag && !pData->mLeaveFlag)
00468 {
00469 EnterCriticalSection(&pData->mCritSection);
00470 pData->mEnteredFlag = true;
00471 --pData->mStopCounter;
00472 }
00473
00474 else if (pData->mEnteredFlag && !pData->mLeaveFlag && pData->mStopCounter > 0)
00475 {
00476 --pData->mStopCounter;
00477
00478
00479 if (pData->mStopCounter == 0 || pData->mKillTimer)
00480 {
00481 LeaveCriticalSection(&pData->mCritSection);
00482 pData->mLeaveFlag = true;
00483 pData->mKillTimer = false;
00484 }
00485 }
00486 }
00487 }
00488
00489
00497 void CALLBACK Timer::Data::TimerProcedure(UINT id,
00498 UINT msg,
00499 DWORD_PTR user,
00500 DWORD_PTR one,
00501 DWORD_PTR two)
00502 {
00503 Timer::Data* pData = (Timer::Data*)user;
00504 if (pData && !pData->mKillTimer)
00505 {
00506
00507 pData->mpTimer->TriggerEvents();
00508 }
00509 }
00510
00511 #endif
00512
00519 void Timer::TimerEventThread(void *args)
00520 {
00521 Timer* pThis = (Timer*)args;
00522 #ifdef WIN32
00523 double eventTimeMs = 0;
00524 #endif
00525
00526 while(!pThis->mTimerEventThread.QuitThreadFlag())
00527 {
00528 #ifdef WIN32
00529 if(Timer::GetTimeMs() - eventTimeMs >= pThis->mDelayTimeMs)
00530 {
00531
00532 pThis->TriggerEvents();
00533 eventTimeMs = Timer::GetTimeMs();
00534 }
00535 Sleep(1);
00536 #else
00537
00538 pThis->mSleepMutex.Lock();
00539 unsigned int delayMs = (unsigned int)(pThis->mDelayTimeMs*1000);
00540 pThis->mSleepMutex.Unlock();
00541 usleep(delayMs);
00542
00543 pThis->TriggerEvents();
00544 #endif
00545 }
00546 }
00547
00548
00554 void Timer::TriggerEvents()
00555 {
00556 Callback::Set::iterator cbObject;
00557 Callback::Function::List::iterator cbFunction;
00558
00559 mCallbacksMutex.Lock();
00560 for(cbObject = mCallbackObjects.begin();
00561 cbObject != mCallbackObjects.end() && mShutdownFlag == false;
00562 cbObject++)
00563 {
00564 (*cbObject)->ProcessTimerEvent();
00565 }
00566
00567 for(cbFunction = mCallbackFunctions.begin();
00568 cbFunction != mCallbackFunctions.end() && mShutdownFlag == false;
00569 cbFunction++)
00570 {
00571 cbFunction->Run();
00572 }
00573
00574 mCallbacksMutex.Unlock();
00575 }
00576
00577
00583 double Timer::GetFrequency() const
00584 {
00585 return 1.0/(CX_EPSILON + mDelayTimeMs/1000.0);
00586 }
00587
00588
00589
00606 bool Timer::ChangeFrequency(const double frequencyHz, const double hptThresholdHz)
00607 {
00608 if(mTimerActive)
00609 {
00610 #ifdef WIN32
00611
00612
00613
00614 if(frequencyHz >= hptThresholdHz || mTimerEventThread.IsThreadActive() == false)
00615 {
00616 Stop();
00617 return Start(frequencyHz, hptThresholdHz) > 0 ? true : false;
00618 }
00619 #endif
00620 Mutex::ScopedLock lock(&mSleepMutex);
00621
00622 mDelayTimeMs = (unsigned int)(1000.0/(frequencyHz + CX_EPSILON));
00623 if(mDelayTimeMs == 0)
00624 {
00625 mDelayTimeMs = 1;
00626 }
00627 return true;
00628 }
00629 return false;
00630 }
00631
00632
00633