dsi_timer.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. This software is subject to the license described in the License.txt file
  3. included with this software distribution. You may not use this file except
  4. in compliance with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2016
  6. All rights reserved.
  7. */
  8. #include "types.h"
  9. #include "dsi_timer.hpp"
  10. #include <stdio.h>
  11. //////////////////////////////////////////////////////////////////////////////////
  12. // Public Class Functions
  13. //////////////////////////////////////////////////////////////////////////////////
  14. ///////////////////////////////////////////////////////////////////////
  15. /*
  16. DSITimer::DSITimer()
  17. {
  18. }
  19. */
  20. DSITimer::DSITimer(DSI_THREAD_RETURN (*fnTimerFunc_)(void *), void *pvTimerFuncParameter_, ULONG ulInterval_, BOOL bRecurring_)
  21. {
  22. fnTimerFunc = fnTimerFunc_;
  23. pvTimerFuncParameter = pvTimerFuncParameter_;
  24. ulInterval = ulInterval_;
  25. bRecurring = bRecurring_;
  26. bClosing = FALSE;
  27. hTimerThread = (DSI_THREAD_ID)NULL;
  28. if (DSIThread_MutexInit(&stMutexCriticalSection) != DSI_THREAD_ENONE)
  29. {
  30. fnTimerFunc = (void*(*)(void*))NULL;
  31. return;
  32. }
  33. if (DSIThread_CondInit(&stCondTimerThreadExit) != DSI_THREAD_ENONE)
  34. {
  35. DSIThread_MutexDestroy(&stMutexCriticalSection);
  36. fnTimerFunc = (void*(*)(void*))NULL;
  37. return;
  38. }
  39. if (DSIThread_CondInit(&stCondTimerWait) != DSI_THREAD_ENONE)
  40. {
  41. DSIThread_MutexDestroy(&stMutexCriticalSection);
  42. DSIThread_CondDestroy(&stCondTimerThreadExit);
  43. fnTimerFunc = (void*(*)(void*))NULL;
  44. return;
  45. }
  46. hTimerThread = DSIThread_CreateThread(&DSITimer::TimerThreadStart, this);
  47. if (hTimerThread == NULL)
  48. {
  49. DSIThread_MutexDestroy(&stMutexCriticalSection);
  50. DSIThread_CondDestroy(&stCondTimerThreadExit);
  51. DSIThread_CondDestroy(&stCondTimerWait);
  52. fnTimerFunc = (void*(*)(void*))NULL;
  53. }
  54. }
  55. ///////////////////////////////////////////////////////////////////////
  56. DSITimer::~DSITimer()
  57. {
  58. if (hTimerThread)
  59. {
  60. DSIThread_MutexLock(&stMutexCriticalSection);
  61. bClosing = TRUE; //Set the exit flag
  62. DSIThread_CondSignal(&stCondTimerWait); //Wake up the timer thread early if it is "sleeping"
  63. if (fnTimerFunc != NULL) //This means the timer thread is still active
  64. {
  65. if (DSIThread_CondTimedWait(&stCondTimerThreadExit, &stMutexCriticalSection, 3000) != DSI_THREAD_ENONE)
  66. {
  67. // We were unable to stop the thread normally, so kill it.
  68. DSIThread_DestroyThread(hTimerThread);
  69. }
  70. }
  71. DSIThread_MutexUnlock(&stMutexCriticalSection);
  72. DSIThread_ReleaseThreadID(hTimerThread);
  73. hTimerThread = (DSI_THREAD_ID)NULL;
  74. DSIThread_MutexDestroy(&stMutexCriticalSection);
  75. DSIThread_CondDestroy(&stCondTimerThreadExit);
  76. DSIThread_CondDestroy(&stCondTimerWait);
  77. }
  78. }
  79. ///////////////////////////////////////////////////////////////////////
  80. BOOL DSITimer::NoError()
  81. {
  82. if ((fnTimerFunc != NULL) && (bClosing == FALSE)) //There was an error if the function pointer is set to NULL and we havent tried to close yet.
  83. return TRUE;
  84. return FALSE;
  85. }
  86. ///////////////////////////////////////////////////////////////////////
  87. DSI_THREAD_RETURN DSITimer::TimerThreadStart(void *pvParameter_)
  88. {
  89. DSITimer *This = (DSITimer *) pvParameter_;
  90. This->TimerThread();
  91. return 0;
  92. }
  93. ///////////////////////////////////////////////////////////////////////
  94. void DSITimer::TimerThread(void)
  95. {
  96. ULONG ulWaitTime;
  97. ULONG ulTargetTime = DSIThread_GetSystemTime();
  98. while(1) //We break on bClosing, but need to check it within the critical section
  99. {
  100. DSIThread_MutexLock(&stMutexCriticalSection);
  101. if (bClosing)
  102. {
  103. DSIThread_MutexUnlock(&stMutexCriticalSection);
  104. break;
  105. }
  106. ulTargetTime += ulInterval; //set the new target time
  107. ulWaitTime = ulTargetTime - DSIThread_GetSystemTime(); //figure out how long it is from now
  108. if (ulWaitTime && ulWaitTime < MAX_ULONG/2) //check if it we need to wait
  109. {
  110. if (DSIThread_CondTimedWait(&stCondTimerWait, &stMutexCriticalSection, ulWaitTime) != DSI_THREAD_ETIMEDOUT) //wait till our next interval
  111. {
  112. //If we get anything other than a timeout we will exit right away
  113. bClosing = TRUE;
  114. DSIThread_MutexUnlock(&stMutexCriticalSection);
  115. break;
  116. }
  117. }
  118. DSIThread_MutexUnlock(&stMutexCriticalSection);
  119. fnTimerFunc(pvTimerFuncParameter); //Call the timer interval function
  120. if (bRecurring == FALSE)
  121. bClosing = TRUE;
  122. }
  123. DSIThread_MutexLock(&stMutexCriticalSection);
  124. fnTimerFunc = (void*(*)(void*))NULL;
  125. DSIThread_CondSignal(&stCondTimerThreadExit); // Set an event to alert the main process that the timer thread is finished.
  126. DSIThread_MutexUnlock(&stMutexCriticalSection);
  127. }