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.

380 lines
9.8 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 <stdlib.h>
  18. #include <string.h>
  19. #include <wchar.h>
  20. #include <lmcons.h>
  21. #include <rasman.h>
  22. #include <mprlog.h>
  23. #include <rasppp.h>
  24. #include <pppcp.h>
  25. #include <ppp.h>
  26. #include <util.h>
  27. #include <worker.h>
  28. #include <timer.h>
  29. //**
  30. //
  31. // Call: MakeTimeoutWorkItem
  32. //
  33. // Returns: PCB_WORK_ITEM * - Pointer to the timeout work item
  34. // NULL - On any error.
  35. //
  36. // Description:
  37. //
  38. PCB_WORK_ITEM *
  39. MakeTimeoutWorkItem(
  40. IN DWORD dwPortId,
  41. IN HPORT hPort,
  42. IN DWORD Protocol,
  43. IN DWORD Id,
  44. IN BOOL fAuthenticator,
  45. IN TIMER_EVENT_TYPE EventType
  46. )
  47. {
  48. PCB_WORK_ITEM * pWorkItem = (PCB_WORK_ITEM *)
  49. LOCAL_ALLOC( LPTR, sizeof( PCB_WORK_ITEM ) );
  50. if ( pWorkItem == (PCB_WORK_ITEM *)NULL )
  51. {
  52. LogPPPEvent( ROUTERLOG_NOT_ENOUGH_MEMORY, 0 );
  53. return( NULL );
  54. }
  55. pWorkItem->dwPortId = dwPortId;
  56. pWorkItem->Id = Id;
  57. pWorkItem->hPort = hPort;
  58. pWorkItem->Protocol = Protocol;
  59. pWorkItem->fAuthenticator = fAuthenticator;
  60. pWorkItem->TimerEventType = EventType;
  61. pWorkItem->Process = ProcessTimeout;
  62. return( pWorkItem );
  63. }
  64. //**
  65. //
  66. // Call: TimerTick
  67. //
  68. // Returns: None.
  69. //
  70. // Description: Called each second if there are elements in the timeout queue.
  71. //
  72. VOID
  73. TimerTick(
  74. OUT BOOL * pfQueueEmpty
  75. )
  76. {
  77. TIMER_EVENT * pTimerEvent;
  78. TIMER_EVENT * pTimerEventTmp;
  79. if ( ( pTimerEvent = TimerQ.pQHead ) == (TIMER_EVENT*)NULL )
  80. {
  81. *pfQueueEmpty = TRUE;
  82. return;
  83. }
  84. *pfQueueEmpty = FALSE;
  85. //
  86. // Decrement time on the first element
  87. //
  88. if ( pTimerEvent->Delta > 0 )
  89. {
  90. (pTimerEvent->Delta)--;
  91. return;
  92. }
  93. //
  94. // Now run through and remove all completed (delta 0) elements.
  95. //
  96. while ( (pTimerEvent != (TIMER_EVENT*)NULL) && (pTimerEvent->Delta == 0) )
  97. {
  98. pTimerEvent = pTimerEvent->pNext;
  99. }
  100. if ( pTimerEvent == (TIMER_EVENT*)NULL )
  101. {
  102. pTimerEvent = TimerQ.pQHead;
  103. TimerQ.pQHead = (TIMER_EVENT*)NULL;
  104. }
  105. else
  106. {
  107. pTimerEvent->pPrev->pNext = (TIMER_EVENT*)NULL;
  108. pTimerEvent->pPrev = (TIMER_EVENT*)NULL;
  109. pTimerEventTmp = TimerQ.pQHead;
  110. TimerQ.pQHead = pTimerEvent;
  111. pTimerEvent = pTimerEventTmp;
  112. }
  113. //
  114. // Now make a timeout work item and put it in the work item Q for all the
  115. // items with delta == 0
  116. //
  117. while( pTimerEvent != (TIMER_EVENT*)NULL )
  118. {
  119. PCB_WORK_ITEM * pWorkItem = MakeTimeoutWorkItem(
  120. pTimerEvent->dwPortId,
  121. pTimerEvent->hPort,
  122. pTimerEvent->Protocol,
  123. pTimerEvent->Id,
  124. pTimerEvent->fAuthenticator,
  125. pTimerEvent->EventType );
  126. if ( pWorkItem == ( PCB_WORK_ITEM *)NULL )
  127. {
  128. LogPPPEvent( ROUTERLOG_NOT_ENOUGH_MEMORY, GetLastError() );
  129. }
  130. else
  131. {
  132. InsertWorkItemInQ( pWorkItem );
  133. }
  134. if ( pTimerEvent->pNext == (TIMER_EVENT *)NULL )
  135. {
  136. LOCAL_FREE( pTimerEvent );
  137. pTimerEvent = (TIMER_EVENT*)NULL;
  138. }
  139. else
  140. {
  141. pTimerEvent = pTimerEvent->pNext;
  142. LOCAL_FREE( pTimerEvent->pPrev );
  143. }
  144. }
  145. }
  146. //**
  147. //
  148. // Call: InsertInTimerQ
  149. //
  150. // Returns: NO_ERROR - Success
  151. // return from GetLastError() - Failure
  152. //
  153. // Description: Adds a timeout element into the delta queue. If the Timer is not
  154. // started it is started. Since there is a LocalAlloc() call here -
  155. // this may fail in which case it will simply not insert it in the
  156. // queue and the request will never timeout. BAP passes in an HCONN in
  157. // hPort.
  158. //
  159. DWORD
  160. InsertInTimerQ(
  161. IN DWORD dwPortId,
  162. IN HPORT hPort,
  163. IN DWORD Id,
  164. IN DWORD Protocol,
  165. IN BOOL fAuthenticator,
  166. IN TIMER_EVENT_TYPE EventType,
  167. IN DWORD Timeout
  168. )
  169. {
  170. TIMER_EVENT * pLastEvent;
  171. TIMER_EVENT * pTimerEventWalker;
  172. TIMER_EVENT * pTimerEvent = (TIMER_EVENT *)LOCAL_ALLOC( LPTR,
  173. sizeof(TIMER_EVENT));
  174. if ( pTimerEvent == (TIMER_EVENT *)NULL )
  175. {
  176. PppLog( 1, "InsertInTimerQ failed: out of memory" );
  177. return( GetLastError() );
  178. }
  179. PppLog( 2,
  180. "InsertInTimerQ called portid=%d,Id=%d,Protocol=%x,"
  181. "EventType=%d,fAuth=%d",
  182. dwPortId, Id, Protocol, EventType, fAuthenticator );
  183. pTimerEvent->dwPortId = dwPortId;
  184. pTimerEvent->Id = Id;
  185. pTimerEvent->Protocol = Protocol;
  186. pTimerEvent->hPort = hPort;
  187. pTimerEvent->EventType = EventType;
  188. pTimerEvent->fAuthenticator = fAuthenticator;
  189. for ( pTimerEventWalker = TimerQ.pQHead,
  190. pLastEvent = pTimerEventWalker;
  191. ( pTimerEventWalker != NULL ) &&
  192. ( pTimerEventWalker->Delta < Timeout );
  193. pLastEvent = pTimerEventWalker,
  194. pTimerEventWalker = pTimerEventWalker->pNext
  195. )
  196. {
  197. Timeout -= pTimerEventWalker->Delta;
  198. }
  199. //
  200. // Insert before pTimerEventWalker. If pTimerEventWalker is NULL then
  201. // we insert at the end of the list.
  202. //
  203. if ( pTimerEventWalker == (TIMER_EVENT*)NULL )
  204. {
  205. //
  206. // If the list was empty
  207. //
  208. if ( TimerQ.pQHead == (TIMER_EVENT*)NULL )
  209. {
  210. TimerQ.pQHead = pTimerEvent;
  211. pTimerEvent->pNext = (TIMER_EVENT *)NULL;
  212. pTimerEvent->pPrev = (TIMER_EVENT *)NULL;
  213. //
  214. // Wake up thread since the Q is not empty any longer
  215. //
  216. SetEvent( TimerQ.hEventNonEmpty );
  217. }
  218. else
  219. {
  220. pLastEvent->pNext = pTimerEvent;
  221. pTimerEvent->pPrev = pLastEvent;
  222. pTimerEvent->pNext = (TIMER_EVENT*)NULL;
  223. }
  224. }
  225. else if ( pTimerEventWalker == TimerQ.pQHead )
  226. {
  227. //
  228. // Insert before the first element
  229. //
  230. pTimerEvent->pNext = TimerQ.pQHead;
  231. TimerQ.pQHead->pPrev = pTimerEvent;
  232. TimerQ.pQHead->Delta -= Timeout;
  233. pTimerEvent->pPrev = (TIMER_EVENT*)NULL;
  234. TimerQ.pQHead = pTimerEvent;
  235. }
  236. else
  237. {
  238. //
  239. // Insert middle element
  240. //
  241. pTimerEvent->pNext = pLastEvent->pNext;
  242. pLastEvent->pNext = pTimerEvent;
  243. pTimerEvent->pPrev = pLastEvent;
  244. pTimerEventWalker->pPrev = pTimerEvent;
  245. pTimerEventWalker->Delta -= Timeout;
  246. }
  247. pTimerEvent->Delta = Timeout;
  248. return( NO_ERROR );
  249. }
  250. //**
  251. //
  252. // Call: RemoveFromTimerQ
  253. //
  254. // Returns: None.
  255. //
  256. // Description: Will remove a timeout event for a certain Id,hPort combination
  257. // from the delta Q.
  258. //
  259. VOID
  260. RemoveFromTimerQ(
  261. IN DWORD dwPortId,
  262. IN DWORD Id,
  263. IN DWORD Protocol,
  264. IN BOOL fAuthenticator,
  265. IN TIMER_EVENT_TYPE EventType
  266. )
  267. {
  268. TIMER_EVENT * pTimerEvent;
  269. PppLog( 2,
  270. "RemoveFromTimerQ called portid=%d,Id=%d,Protocol=%x,"
  271. "EventType=%d,fAuth=%d",
  272. dwPortId, Id, Protocol, EventType, fAuthenticator );
  273. for ( pTimerEvent = TimerQ.pQHead;
  274. ( pTimerEvent != (TIMER_EVENT *)NULL ) &&
  275. ( ( pTimerEvent->EventType != EventType ) ||
  276. ( pTimerEvent->dwPortId != dwPortId ) ||
  277. ( ( pTimerEvent->EventType == TIMER_EVENT_TIMEOUT ) &&
  278. ( ( pTimerEvent->Id != Id ) ||
  279. ( pTimerEvent->Protocol != Protocol ) ||
  280. ( pTimerEvent->fAuthenticator != fAuthenticator ) ) ) );
  281. pTimerEvent = pTimerEvent->pNext
  282. );
  283. //
  284. // If event was not found simply return.
  285. //
  286. if ( pTimerEvent == (TIMER_EVENT *)NULL )
  287. {
  288. return;
  289. }
  290. //
  291. // If this is the first element to be removed
  292. //
  293. if ( pTimerEvent == TimerQ.pQHead )
  294. {
  295. TimerQ.pQHead = pTimerEvent->pNext;
  296. if ( TimerQ.pQHead != (TIMER_EVENT *)NULL )
  297. {
  298. TimerQ.pQHead->pPrev = (TIMER_EVENT*)NULL;
  299. TimerQ.pQHead->Delta += pTimerEvent->Delta;
  300. }
  301. }
  302. else if ( pTimerEvent->pNext == (TIMER_EVENT*)NULL )
  303. {
  304. //
  305. // If this was the last element to be removed
  306. //
  307. pTimerEvent->pPrev->pNext = (TIMER_EVENT*)NULL;
  308. }
  309. else
  310. {
  311. pTimerEvent->pNext->Delta += pTimerEvent->Delta;
  312. pTimerEvent->pPrev->pNext = pTimerEvent->pNext;
  313. pTimerEvent->pNext->pPrev = pTimerEvent->pPrev;
  314. }
  315. LOCAL_FREE( pTimerEvent );
  316. }