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.

468 lines
12 KiB

  1. // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
  2. /*---------------------------------------------------------
  3. Filename: timer.cpp
  4. Written By: B.Rajeev
  5. ----------------------------------------------------------*/
  6. #include "precomp.h"
  7. #include "common.h"
  8. #include "sync.h"
  9. #include "timer.h"
  10. #include "message.h"
  11. #include "dummy.h"
  12. #include "flow.h"
  13. #include "frame.h"
  14. #include "ssent.h"
  15. #include "idmap.h"
  16. #include "opreg.h"
  17. #include "session.h"
  18. SnmpClThreadObject *Timer :: g_timerThread = NULL ;
  19. UINT Timer :: g_SnmpWmTimer = SNMP_WM_TIMER ;
  20. // static CriticalSection and CMap
  21. CriticalSection Timer::timer_CriticalSection;
  22. TimerMapping Timer::timer_mapping;
  23. TimerEventId Timer :: next_timer_event_id = ILLEGAL_TIMER_EVENT_ID+1 ;
  24. Window *SnmpTimerObject :: window = NULL ;
  25. CMap <UINT_PTR,UINT_PTR,SnmpTimerObject *,SnmpTimerObject *> SnmpTimerObject :: timerMap ;
  26. SnmpClThreadObject :: SnmpClThreadObject () : SnmpThreadObject ( "SnmpCl" )
  27. {
  28. }
  29. void SnmpClThreadObject :: Initialise ()
  30. {
  31. }
  32. void SnmpClThreadObject :: Uninitialise ()
  33. {
  34. delete SnmpTimerObject :: window ;
  35. SnmpTimerObject :: window = NULL ;
  36. delete this ;
  37. }
  38. SnmpClTrapThreadObject :: SnmpClTrapThreadObject () : SnmpThreadObject ( "SnmpClTrapThread" )
  39. {
  40. }
  41. void SnmpClTrapThreadObject :: Initialise ()
  42. {
  43. DebugMacro4(
  44. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  45. __FILE__,__LINE__,
  46. L"SnmpClTrapThreadObject::Initialise: Initialised!!\n"
  47. ) ;
  48. )
  49. }
  50. void SnmpClTrapThreadObject :: Uninitialise ()
  51. {
  52. DebugMacro4(
  53. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  54. __FILE__,__LINE__,
  55. L"SnmpClTrapThreadObject::Uninitialise: About to destroy trap thread\n"
  56. ) ;
  57. )
  58. delete this ;
  59. DebugMacro4(
  60. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  61. __FILE__,__LINE__,
  62. L"SnmpClTrapThreadObject::Uninitialise: Trap thread destroyed!!\n"
  63. ) ;
  64. )
  65. }
  66. Timer::Timer(SnmpImpSession &session)
  67. {
  68. Timer::session = &session;
  69. }
  70. BOOL Timer::CreateCriticalSection()
  71. {
  72. return TRUE;
  73. }
  74. void Timer::DestroyCriticalSection()
  75. {
  76. }
  77. BOOL Timer::InitializeStaticComponents()
  78. {
  79. return CreateCriticalSection();
  80. }
  81. void Timer::DestroyStaticComponents()
  82. {
  83. DestroyCriticalSection();
  84. }
  85. // generates and returns a new event id
  86. // associates the pair (event_id, waiting_message)
  87. // creates the timer event
  88. TimerEventId Timer::SetTimerEvent(UINT timeout_value)
  89. {
  90. TimerEventId suggested_event_id = next_timer_event_id++;
  91. if ( suggested_event_id == ILLEGAL_TIMER_EVENT_ID )
  92. suggested_event_id = next_timer_event_id++;
  93. // let the dummy session receive the window messages for timer events
  94. TimerEventId event_id =
  95. SnmpSetTimer( session->m_SessionWindow.GetWindowHandle(), suggested_event_id,
  96. timeout_value, NULL );
  97. if ( (event_id == ILLEGAL_TIMER_EVENT_ID) ||
  98. (event_id != suggested_event_id) )
  99. throw GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__);
  100. return event_id;
  101. }
  102. // generates and returns a new event id
  103. // associates the pair (event_id, waiting_message)
  104. // creates the timer event
  105. void Timer::SetMessageTimerEvent(WaitingMessage &waiting_message)
  106. {
  107. CriticalSectionLock session_lock(session->session_CriticalSection);
  108. if ( !session_lock.GetLock(INFINITE) )
  109. return; // no use throwing exception
  110. TimerEventId event_id = session->timer_event_id;
  111. // register the timer event in both the instance CMap and the global CMap
  112. waiting_message_mapping.AddTail ( &waiting_message ) ;
  113. session_lock.UnLock();
  114. CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
  115. if ( !timer_lock.GetLock(INFINITE) )
  116. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  117. timer_mapping[event_id] = this;
  118. timer_lock.UnLock();
  119. }
  120. // Removes the association (event_id, waiting_message)
  121. // and also kills the registered timer event
  122. void Timer::CancelMessageTimer(WaitingMessage &waiting_message,TimerEventId event_id)
  123. {
  124. CriticalSectionLock session_lock(session->session_CriticalSection);
  125. if ( !session_lock.GetLock(INFINITE) )
  126. return; // no use throwing exception
  127. // remove the timer event from the instance CMap
  128. POSITION t_Position = waiting_message_mapping.GetHeadPosition () ;
  129. while ( t_Position )
  130. {
  131. POSITION t_OldPosition = t_Position ;
  132. WaitingMessage *t_Message = waiting_message_mapping.GetNext ( t_Position ) ;
  133. if ( t_Message == & waiting_message )
  134. {
  135. waiting_message_mapping.RemoveAt(t_OldPosition);
  136. break ;
  137. }
  138. }
  139. session_lock.UnLock();
  140. DebugMacro4(
  141. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  142. __FILE__,__LINE__,
  143. L"Cancelled Message TimerEvent %d\n", event_id
  144. ) ;
  145. )
  146. }
  147. // Removes the association (event_id, waiting_message)
  148. // and also kills the registered timer event
  149. void Timer::CancelTimer(TimerEventId event_id)
  150. {
  151. CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
  152. if ( !timer_lock.GetLock(INFINITE) )
  153. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  154. // remove the timer event from the global CMap
  155. timer_mapping.RemoveKey(event_id);
  156. timer_lock.UnLock();
  157. SnmpKillTimer(NULL, event_id);
  158. DebugMacro4(
  159. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  160. __FILE__,__LINE__,
  161. L"Cancelled TimerEvent %d\n", event_id
  162. ) ;
  163. )
  164. }
  165. // it determines the corresponding Timer and calls
  166. // its TimerEventNotification with the appropriate parameters
  167. void CALLBACK Timer::HandleGlobalEvent(HWND hWnd ,UINT message,
  168. UINT_PTR idEvent, DWORD dwTime)
  169. {
  170. CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
  171. if ( !timer_lock.GetLock(INFINITE) )
  172. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  173. Timer *timer;
  174. TimerEventId event_id = idEvent;
  175. BOOL found = timer_mapping.Lookup(event_id, timer);
  176. timer_lock.UnLock();
  177. // if no such timer event, return
  178. if ( !found )
  179. return;
  180. // let the timer handle the event
  181. timer->TimerEventNotification(event_id);
  182. return;
  183. }
  184. // used by the event handler to notify the timer event.
  185. // it must notify the corresponding waiting message
  186. void Timer::TimerEventNotification(TimerEventId event_id)
  187. {
  188. CriticalSectionLock session_lock(session->session_CriticalSection);
  189. if ( !session_lock.GetLock(INFINITE) )
  190. return; // no use throwing exception
  191. WaitingMessage *waiting_message;
  192. // identify the waiting message corresponding to
  193. // the event_id. if no such event, ignore it
  194. POSITION t_Position = waiting_message_mapping.GetHeadPosition () ;
  195. while ( t_Position )
  196. {
  197. waiting_message = waiting_message_mapping.GetNext ( t_Position ) ;
  198. // notify the waiting message of the event
  199. waiting_message->TimerNotification();
  200. }
  201. // session_lock.UnLock(); The lock may be released at this point
  202. }
  203. // remove all the (timer_event_id, timer) associations
  204. // from the static mapping data structure
  205. Timer::~Timer(void)
  206. {
  207. WaitingMessage *waiting_message;
  208. POSITION current = waiting_message_mapping.GetHeadPosition();
  209. while ( current != NULL )
  210. {
  211. waiting_message = waiting_message_mapping.GetNext(current);
  212. TimerEventId event_id = waiting_message->GetTimerEventId () ;
  213. CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
  214. if ( !timer_lock.GetLock(INFINITE) )
  215. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  216. timer_mapping.RemoveKey ( event_id );
  217. timer_lock.UnLock();
  218. SnmpKillTimer(NULL, event_id );
  219. }
  220. waiting_message_mapping.RemoveAll();
  221. }
  222. SnmpTimerObject :: SnmpTimerObject (
  223. HWND hWndArg, // handle of window for timer messages
  224. UINT_PTR timerIdArg, // timer identifier
  225. UINT elapsedArg, // time-out value
  226. TIMERPROC lpTimerFuncArg // address of timer procedure
  227. ) : hWnd ( hWndArg ) ,
  228. timerId ( timerIdArg ) ,
  229. lpTimerFunc ( lpTimerFuncArg )
  230. {
  231. if ( ! window )
  232. window = new Window ;
  233. timerId = SetTimer (
  234. window->GetWindowHandle(),
  235. timerId ,
  236. elapsedArg ,
  237. lpTimerFunc
  238. ) ;
  239. CriticalSectionLock session_lock(Timer::timer_CriticalSection);
  240. if ( !session_lock.GetLock(INFINITE) )
  241. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  242. if ( timerId )
  243. {
  244. timerMap [ timerId ] = this ;
  245. }
  246. else
  247. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  248. }
  249. SnmpTimerObject :: ~SnmpTimerObject ()
  250. {
  251. CriticalSectionLock session_lock(Timer::timer_CriticalSection);
  252. if ( !session_lock.GetLock(INFINITE) )
  253. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  254. timerMap.RemoveKey ( timerId );
  255. if (window)
  256. {
  257. KillTimer ( window->GetWindowHandle () , timerId ) ;
  258. }
  259. }
  260. void SnmpTimerObject :: TimerNotification ( HWND hWnd , UINT timerId )
  261. {
  262. :: WaitPostMessage ( hWnd , Timer :: g_SnmpWmTimer , timerId , 0 ) ;
  263. }
  264. SnmpSetTimerObject :: SnmpSetTimerObject (
  265. HWND hWndArg, // handle of window for timer messages
  266. UINT_PTR nIDEventArg, // timer identifier
  267. UINT uElapseArg, // time-out value
  268. TIMERPROC lpTimerFuncArg // address of timer procedure
  269. ) : hWnd ( hWndArg ) ,
  270. timerId ( nIDEventArg ) ,
  271. elapsedTime ( uElapseArg ) ,
  272. lpTimerFunc ( lpTimerFuncArg )
  273. {
  274. }
  275. SnmpSetTimerObject :: ~SnmpSetTimerObject ()
  276. {
  277. }
  278. void SnmpSetTimerObject :: Process ()
  279. {
  280. SnmpTimerObject *object = new SnmpTimerObject (
  281. hWnd ,
  282. timerId ,
  283. elapsedTime ,
  284. lpTimerFunc
  285. ) ;
  286. Complete () ;
  287. }
  288. SnmpKillTimerObject :: SnmpKillTimerObject (
  289. HWND hWndArg , // handle of window that installed timer
  290. UINT_PTR uIDEventArg // timer identifier
  291. ) : hWnd ( hWndArg ) ,
  292. timerId ( uIDEventArg ) ,
  293. status ( TRUE )
  294. {
  295. }
  296. void SnmpKillTimerObject :: Process ()
  297. {
  298. CriticalSectionLock session_lock(Timer::timer_CriticalSection);
  299. if ( !session_lock.GetLock(INFINITE) )
  300. throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
  301. SnmpTimerObject *object ;
  302. if ( SnmpTimerObject :: timerMap.Lookup ( timerId , object ) )
  303. {
  304. delete object ;
  305. }
  306. else
  307. {
  308. status = FALSE ;
  309. }
  310. Complete () ;
  311. }
  312. UINT_PTR SnmpSetTimer (
  313. HWND hWnd, // handle of window for timer messages
  314. UINT_PTR nIDEvent, // timer identifier
  315. UINT uElapse, // time-out value,
  316. TIMERPROC lpTimerFunc // address of timer procedure
  317. )
  318. {
  319. SnmpSetTimerObject object ( hWnd , nIDEvent , uElapse , lpTimerFunc ) ;
  320. Timer :: g_timerThread->ScheduleTask ( object ) ;
  321. object.Exec () ;
  322. if ( object.Wait () )
  323. {
  324. Timer :: g_timerThread->ReapTask ( object ) ;
  325. return object.GetTimerId () ;
  326. }
  327. else
  328. {
  329. Timer :: g_timerThread->ReapTask ( object ) ;
  330. return FALSE ;
  331. }
  332. }
  333. BOOL SnmpKillTimer (
  334. HWND hWnd, // handle of window that installed timer
  335. UINT_PTR uIDEvent // timer identifier
  336. )
  337. {
  338. SnmpKillTimerObject object ( hWnd , uIDEvent ) ;
  339. Timer :: g_timerThread->ScheduleTask ( object ) ;
  340. object.Exec () ;
  341. if ( object.Wait () )
  342. {
  343. Timer :: g_timerThread->ReapTask ( object ) ;
  344. return object.GetStatus () ;
  345. }
  346. else
  347. {
  348. Timer :: g_timerThread->ReapTask ( object ) ;
  349. return FALSE ;
  350. }
  351. }