Leaked source code of windows server 2003
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.

412 lines
9.2 KiB

  1. /********************************************************************/
  2. /** Copyright(c) 1989 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: timer.c
  7. //
  8. // Description: All timer queue related funtions live here.
  9. //
  10. // History:
  11. // Nov 11,1993. NarenG Created original version.
  12. //
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h> // needed for winbase.h
  16. #include <windows.h> // Win32 base API's
  17. #include "ddm.h"
  18. #include "timer.h"
  19. #include <rasppp.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <wchar.h>
  23. //
  24. //
  25. // Timer queue item
  26. //
  27. typedef struct _TIMER_EVENT_OBJECT
  28. {
  29. struct _TIMER_EVENT_OBJECT * pNext;
  30. struct _TIMER_EVENT_OBJECT * pPrev;
  31. TIMEOUT_HANDLER pfuncTimeoutHandler;
  32. HANDLE hObject;
  33. DWORD dwDelta; // # of secs. to wait after prev. item
  34. } TIMER_EVENT_OBJECT, *PTIMER_EVENT_OBJECT;
  35. //
  36. // Head of timer queue.
  37. //
  38. typedef struct _TIMER_Q
  39. {
  40. TIMER_EVENT_OBJECT * pQHead;
  41. CRITICAL_SECTION CriticalSection; // Mutual exclusion around timer Q
  42. } TIMER_Q, *PTIMER_Q;
  43. static TIMER_Q gblTimerQ; // Timer Queue
  44. //**
  45. //
  46. // Call: TimerQInitialize
  47. //
  48. // Returns: NO_ERROR - Success
  49. // Non-zero returns - Failure
  50. //
  51. // Description: Initializes the gblTimerQ structure
  52. //
  53. DWORD
  54. TimerQInitialize(
  55. VOID
  56. )
  57. {
  58. //
  59. // Initialize the global timer queue
  60. //
  61. InitializeCriticalSection( &(gblTimerQ.CriticalSection) );
  62. return( NO_ERROR );
  63. }
  64. //**
  65. //
  66. // Call: TimerQDelete
  67. //
  68. // Returns: NO_ERROR - Success
  69. // Non-zero returns - Failure
  70. //
  71. // Description: Deinitializes the TimerQ
  72. //
  73. VOID
  74. TimerQDelete(
  75. VOID
  76. )
  77. {
  78. DeleteCriticalSection( &(gblTimerQ.CriticalSection) );
  79. ZeroMemory( &gblTimerQ, sizeof( gblTimerQ ) );
  80. }
  81. //**
  82. //
  83. // Call: TimerQTick
  84. //
  85. // Returns: None.
  86. //
  87. // Description: Called each second if there are elements in the timeout queue.
  88. //
  89. VOID
  90. TimerQTick(
  91. VOID
  92. )
  93. {
  94. TIMER_EVENT_OBJECT * pTimerEvent;
  95. TIMER_EVENT_OBJECT * pTimerEventTmp;
  96. //
  97. // **** Exclusion Begin ****
  98. //
  99. EnterCriticalSection( &(gblTimerQ.CriticalSection) );
  100. if ( ( pTimerEvent = gblTimerQ.pQHead ) == (TIMER_EVENT_OBJECT*)NULL )
  101. {
  102. //
  103. // *** Exclusion End ***
  104. //
  105. LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
  106. return;
  107. }
  108. //
  109. // Decrement time on the first element
  110. //
  111. if ( pTimerEvent->dwDelta > 0 )
  112. {
  113. (pTimerEvent->dwDelta)--;
  114. //
  115. // *** Exclusion End ***
  116. //
  117. LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
  118. return;
  119. }
  120. //
  121. // Now run through and remove all completed (delta 0) elements.
  122. //
  123. while ( ( pTimerEvent != (TIMER_EVENT_OBJECT*)NULL ) &&
  124. ( pTimerEvent->dwDelta == 0 ) )
  125. {
  126. pTimerEvent = pTimerEvent->pNext;
  127. }
  128. if ( pTimerEvent == (TIMER_EVENT_OBJECT*)NULL )
  129. {
  130. pTimerEvent = gblTimerQ.pQHead;
  131. gblTimerQ.pQHead = (TIMER_EVENT_OBJECT*)NULL;
  132. }
  133. else
  134. {
  135. pTimerEvent->pPrev->pNext = (TIMER_EVENT_OBJECT*)NULL;
  136. pTimerEvent->pPrev = (TIMER_EVENT_OBJECT*)NULL;
  137. pTimerEventTmp = gblTimerQ.pQHead;
  138. gblTimerQ.pQHead = pTimerEvent;
  139. pTimerEvent = pTimerEventTmp;
  140. }
  141. //
  142. // *** Exclusion End ***
  143. //
  144. LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
  145. //
  146. // Process all the timeout event objects items with delta == 0
  147. //
  148. while( pTimerEvent != (TIMER_EVENT_OBJECT*)NULL )
  149. {
  150. pTimerEvent->pfuncTimeoutHandler( pTimerEvent->hObject );
  151. if ( pTimerEvent->pNext == (TIMER_EVENT_OBJECT *)NULL )
  152. {
  153. LOCAL_FREE( pTimerEvent );
  154. pTimerEvent = (TIMER_EVENT_OBJECT*)NULL;
  155. }
  156. else
  157. {
  158. pTimerEvent = pTimerEvent->pNext;
  159. LOCAL_FREE( pTimerEvent->pPrev );
  160. }
  161. }
  162. }
  163. //**
  164. //
  165. // Call: TimerQInsert
  166. //
  167. // Returns: NO_ERROR - Success
  168. // return from GetLastError() - Failure
  169. //
  170. // Description: Adds a timeout element into the delta queue. If the Timer is not
  171. // started it is started. Since there is a LocalAlloc() call here -
  172. // this may fail in which case it will simply not insert it in the
  173. // queue and the request will never timeout.
  174. //
  175. DWORD
  176. TimerQInsert(
  177. IN HANDLE hObject,
  178. IN DWORD dwTimeout,
  179. IN TIMEOUT_HANDLER pfuncTimeoutHandler
  180. )
  181. {
  182. TIMER_EVENT_OBJECT * pLastEvent;
  183. TIMER_EVENT_OBJECT * pTimerEventWalker;
  184. TIMER_EVENT_OBJECT * pTimerEvent;
  185. pTimerEvent = (TIMER_EVENT_OBJECT *)LOCAL_ALLOC( LPTR,
  186. sizeof(TIMER_EVENT_OBJECT));
  187. if ( pTimerEvent == (TIMER_EVENT_OBJECT *)NULL )
  188. {
  189. return( GetLastError() );
  190. }
  191. pTimerEvent->hObject = hObject;
  192. pTimerEvent->pfuncTimeoutHandler = pfuncTimeoutHandler;
  193. //
  194. // **** Exclusion Begin ****
  195. //
  196. EnterCriticalSection( &(gblTimerQ.CriticalSection) );
  197. for ( pTimerEventWalker = gblTimerQ.pQHead,
  198. pLastEvent = pTimerEventWalker;
  199. ( pTimerEventWalker != NULL ) &&
  200. ( pTimerEventWalker->dwDelta < dwTimeout );
  201. pLastEvent = pTimerEventWalker,
  202. pTimerEventWalker = pTimerEventWalker->pNext
  203. )
  204. {
  205. dwTimeout -= pTimerEventWalker->dwDelta;
  206. }
  207. //
  208. // Insert before pTimerEventWalker. If pTimerEventWalker is NULL then
  209. // we insert at the end of the list.
  210. //
  211. if ( pTimerEventWalker == (TIMER_EVENT_OBJECT*)NULL )
  212. {
  213. //
  214. // If the list was empty
  215. //
  216. if ( gblTimerQ.pQHead == (TIMER_EVENT_OBJECT*)NULL )
  217. {
  218. gblTimerQ.pQHead = pTimerEvent;
  219. pTimerEvent->pNext = (TIMER_EVENT_OBJECT *)NULL;
  220. pTimerEvent->pPrev = (TIMER_EVENT_OBJECT *)NULL;
  221. }
  222. else
  223. {
  224. pLastEvent->pNext = pTimerEvent;
  225. pTimerEvent->pPrev = pLastEvent;
  226. pTimerEvent->pNext = (TIMER_EVENT_OBJECT*)NULL;
  227. }
  228. }
  229. else if ( pTimerEventWalker == gblTimerQ.pQHead )
  230. {
  231. //
  232. // Insert before the first element
  233. //
  234. pTimerEvent->pNext = gblTimerQ.pQHead;
  235. gblTimerQ.pQHead->pPrev = pTimerEvent;
  236. gblTimerQ.pQHead->dwDelta -= dwTimeout;
  237. pTimerEvent->pPrev = (TIMER_EVENT_OBJECT*)NULL;
  238. gblTimerQ.pQHead = pTimerEvent;
  239. }
  240. else
  241. {
  242. //
  243. // Insert middle element
  244. //
  245. pTimerEvent->pNext = pLastEvent->pNext;
  246. pLastEvent->pNext = pTimerEvent;
  247. pTimerEvent->pPrev = pLastEvent;
  248. pTimerEventWalker->pPrev = pTimerEvent;
  249. pTimerEventWalker->dwDelta -= dwTimeout;
  250. }
  251. pTimerEvent->dwDelta = dwTimeout;
  252. //
  253. // *** Exclusion End ***
  254. //
  255. LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
  256. return( NO_ERROR );
  257. }
  258. //**
  259. //
  260. // Call: TimerQRemove
  261. //
  262. // Returns: None.
  263. //
  264. // Description: Will remove a timeout event for a certain Id,hPort combination
  265. // from the delta Q.
  266. //
  267. VOID
  268. TimerQRemove(
  269. IN HANDLE hObject,
  270. IN TIMEOUT_HANDLER pfuncTimeoutHandler
  271. )
  272. {
  273. TIMER_EVENT_OBJECT * pTimerEvent;
  274. DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_TIMER,
  275. "TimerQRemove called");
  276. //
  277. // **** Exclusion Begin ****
  278. //
  279. EnterCriticalSection( &(gblTimerQ.CriticalSection) );
  280. for ( pTimerEvent = gblTimerQ.pQHead;
  281. ( pTimerEvent != (TIMER_EVENT_OBJECT *)NULL ) &&
  282. ( ( pTimerEvent->pfuncTimeoutHandler != pfuncTimeoutHandler ) ||
  283. ( pTimerEvent->hObject != hObject ) );
  284. pTimerEvent = pTimerEvent->pNext
  285. );
  286. //
  287. // If event was not found simply return.
  288. //
  289. if ( pTimerEvent == (TIMER_EVENT_OBJECT *)NULL )
  290. {
  291. //
  292. // *** Exclusion End ***
  293. //
  294. LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
  295. return;
  296. }
  297. //
  298. // If this is the first element to be removed
  299. //
  300. if ( pTimerEvent == gblTimerQ.pQHead )
  301. {
  302. gblTimerQ.pQHead = pTimerEvent->pNext;
  303. if ( gblTimerQ.pQHead != (TIMER_EVENT_OBJECT *)NULL )
  304. {
  305. gblTimerQ.pQHead->pPrev = (TIMER_EVENT_OBJECT*)NULL;
  306. gblTimerQ.pQHead->dwDelta += pTimerEvent->dwDelta;
  307. }
  308. }
  309. else if ( pTimerEvent->pNext == (TIMER_EVENT_OBJECT*)NULL )
  310. {
  311. //
  312. // If this was the last element to be removed
  313. //
  314. pTimerEvent->pPrev->pNext = (TIMER_EVENT_OBJECT*)NULL;
  315. }
  316. else
  317. {
  318. pTimerEvent->pNext->dwDelta += pTimerEvent->dwDelta;
  319. pTimerEvent->pPrev->pNext = pTimerEvent->pNext;
  320. pTimerEvent->pNext->pPrev = pTimerEvent->pPrev;
  321. }
  322. //
  323. // *** Exclusion End ***
  324. //
  325. LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
  326. LOCAL_FREE( pTimerEvent );
  327. }