Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
5.2 KiB

  1. /*
  2. Copyright (c) 1998, Microsoft Corporation, all rights reserved
  3. Description:
  4. History:
  5. */
  6. #include "timer_.h"
  7. LONG g_TimerLockUninit = 0;
  8. /*
  9. Returns:
  10. Win 32 error
  11. Notes:
  12. Its a good idea to always call RasDhcpTimerUninitialize after calling
  13. RasDhcpTimerInitialize, even if RasDhcpTimerInitialize failed.
  14. */
  15. DWORD
  16. RasDhcpTimerInitialize(
  17. VOID
  18. )
  19. {
  20. NTSTATUS Status;
  21. DWORD dwErr = NO_ERROR;
  22. g_TimerLockUninit = 0;
  23. RasDhcpTimerShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
  24. if (NULL == RasDhcpTimerShutdown)
  25. {
  26. dwErr = GetLastError();
  27. goto LEnd;
  28. }
  29. Status = RtlCreateTimerQueue(&RasDhcpTimerQueueHandle);
  30. if (STATUS_SUCCESS != Status)
  31. {
  32. RasDhcpTimerQueueHandle = NULL;
  33. dwErr = Status;
  34. TraceHlp("RtlCreateTimerQueue failed and returned %d", dwErr);
  35. goto LEnd;
  36. }
  37. RasDhcpTimerPrevTime = time(NULL);
  38. Status = RtlCreateTimer(RasDhcpTimerQueueHandle, &RasDhcpTimerHandle,
  39. RasDhcpTimerFunc, NULL, 0, TIMER_PERIOD,
  40. WT_EXECUTELONGFUNCTION);
  41. if (STATUS_SUCCESS != Status)
  42. {
  43. dwErr = Status;
  44. TraceHlp("RtlCreateTimer failed and returned %d", dwErr);
  45. goto LEnd;
  46. }
  47. LEnd:
  48. if (NO_ERROR != dwErr)
  49. {
  50. if (NULL != RasDhcpTimerQueueHandle)
  51. {
  52. Status = RtlDeleteTimerQueueEx(RasDhcpTimerQueueHandle, (HANDLE)-1);
  53. RTASSERT(STATUS_SUCCESS == Status);
  54. RasDhcpTimerQueueHandle = NULL;
  55. }
  56. if (NULL != RasDhcpTimerShutdown)
  57. {
  58. CloseHandle(RasDhcpTimerShutdown);
  59. RasDhcpTimerShutdown = NULL;
  60. }
  61. }
  62. return(dwErr);
  63. }
  64. /*
  65. Returns:
  66. VOID
  67. Notes:
  68. RasDhcpTimerUninitialize can be called even if RasDhcpTimerInitialize
  69. failed.
  70. */
  71. VOID
  72. RasDhcpTimerUninitialize(
  73. VOID
  74. )
  75. {
  76. NTSTATUS Status;
  77. DWORD dwRet;
  78. LONG lPrev = 1;
  79. // Signal the timer thread to shutdown.
  80. lPrev = InterlockedExchangeAdd(&g_TimerLockUninit, 1);
  81. if ( lPrev > 1 )
  82. return;
  83. if (NULL != RasDhcpTimerQueueHandle)
  84. {
  85. RTASSERT(NULL != RasDhcpTimerShutdown);
  86. SetEvent(RasDhcpTimerShutdown);
  87. Status = RtlDeleteTimerQueueEx(RasDhcpTimerQueueHandle, (HANDLE)-1);
  88. RTASSERT(STATUS_SUCCESS == Status);
  89. RasDhcpTimerQueueHandle = NULL;
  90. }
  91. if (NULL != RasDhcpTimerShutdown)
  92. {
  93. CloseHandle(RasDhcpTimerShutdown);
  94. RasDhcpTimerShutdown = NULL;
  95. }
  96. // timer.c didn't alloc the nodes in the linked list.
  97. // So we don't free them here.
  98. RasDhcpTimerListHead = NULL;
  99. }
  100. /*
  101. Returns:
  102. Notes:
  103. */
  104. VOID
  105. RasDhcpTimerFunc(
  106. IN VOID* pArg1,
  107. IN BOOLEAN fArg2
  108. )
  109. {
  110. TIMERLIST* pTimer;
  111. TIMERLIST* pTmp;
  112. TIMERFUNCTION TimerFunc;
  113. time_t now = time(NULL);
  114. LONG lElapsedTime;
  115. LONG lTime;
  116. if (0 == TryEnterCriticalSection(&RasTimrCriticalSection))
  117. {
  118. // Another thread already owns the critical section
  119. return;
  120. }
  121. lElapsedTime = (LONG)(now - RasDhcpTimerPrevTime);
  122. RasDhcpTimerPrevTime = now;
  123. pTimer = NULL;
  124. while (RasDhcpTimerListHead != NULL)
  125. {
  126. lTime = RasDhcpTimerListHead->tmr_Delta;
  127. if ( lTime > 0)
  128. {
  129. RasDhcpTimerListHead->tmr_Delta -= lElapsedTime;
  130. lElapsedTime -= lTime;
  131. }
  132. if (RasDhcpTimerListHead->tmr_Delta <= 0)
  133. {
  134. pTmp = pTimer;
  135. pTimer = RasDhcpTimerListHead;
  136. RasDhcpTimerListHead = pTimer->tmr_Next;
  137. pTimer->tmr_Next = pTmp;
  138. }
  139. else
  140. {
  141. break;
  142. }
  143. }
  144. while (pTimer != NULL)
  145. {
  146. pTmp = pTimer->tmr_Next;
  147. TimerFunc = pTimer->tmr_TimerFunc;
  148. pTimer->tmr_TimerFunc = NULL;
  149. (*TimerFunc)(RasDhcpTimerShutdown, pTimer);
  150. pTimer = pTmp;
  151. }
  152. LeaveCriticalSection(&RasTimrCriticalSection);
  153. }
  154. /*
  155. Returns:
  156. VOID
  157. Notes:
  158. Once the timer thread starts, only it can call RasDhcpTimerSchedule (to
  159. avoid race conditions). The timer thread will call rasDhcpMonitorAddresses
  160. (and hence rasDhcpAllocateAddress), and rasDhcpRenewLease. These functions
  161. will call RasDhcpTimerSchedule. No one else should call these functions or
  162. RasDhcpTimerSchedule. The only exception is RasDhcpInitialize, which can
  163. call RasDhcpTimerSchedule before it creates the timer thread.
  164. */
  165. VOID
  166. RasDhcpTimerSchedule(
  167. IN TIMERLIST* pNewTimer,
  168. IN LONG DeltaTime,
  169. IN TIMERFUNCTION TimerFunc
  170. )
  171. {
  172. TIMERLIST** ppTimer;
  173. TIMERLIST* pTimer;
  174. pNewTimer->tmr_TimerFunc = TimerFunc;
  175. for (ppTimer = &RasDhcpTimerListHead;
  176. (pTimer = *ppTimer) != NULL;
  177. ppTimer = &pTimer->tmr_Next)
  178. {
  179. if (DeltaTime <= pTimer->tmr_Delta)
  180. {
  181. pTimer->tmr_Delta -= DeltaTime;
  182. break;
  183. }
  184. DeltaTime -= pTimer->tmr_Delta;
  185. }
  186. pNewTimer->tmr_Delta = DeltaTime;
  187. pNewTimer->tmr_Next = *ppTimer;
  188. *ppTimer = pNewTimer;
  189. }
  190. /*
  191. Returns:
  192. Notes:
  193. */
  194. VOID
  195. RasDhcpTimerRunNow(
  196. VOID
  197. )
  198. {
  199. RtlUpdateTimer(RasDhcpTimerQueueHandle, RasDhcpTimerHandle, 0,
  200. TIMER_PERIOD);
  201. }