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.

622 lines
19 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. timeract.c
  5. Abstract:
  6. Provides the timer activity functions.
  7. Author:
  8. Sunita Shrivastava (sunitas) 10-Nov-1995
  9. Revision History:
  10. --*/
  11. #include "service.h"
  12. #include "lmp.h"
  13. //global data
  14. static LIST_ENTRY gActivityHead;
  15. static HANDLE ghTimerCtrlEvent=NULL;
  16. static HANDLE ghTimerCtrlDoneEvent = NULL;
  17. static HANDLE ghTimerThread=NULL;
  18. static CRITICAL_SECTION gActivityCritSec;
  19. static HANDLE grghWaitHandles[MAX_TIMER_ACTIVITIES];
  20. static PTIMER_ACTIVITY grgpActivity[MAX_TIMER_ACTIVITIES];
  21. static DWORD gdwNumHandles;
  22. static DWORD gdwTimerCtrl;
  23. //internal prototypes
  24. DWORD WINAPI ClTimerThread(PVOID pContext);
  25. void ReSyncTimerHandles();
  26. /****
  27. @doc EXTERNAL INTERFACES CLUSSVC LM
  28. ****/
  29. /****
  30. @func DWORD | TimerActInitialize| It initializes structures for log file
  31. management and creates a timer thread to process timer activities.
  32. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  33. @comm This function is called when the cluster components are initialized.
  34. @xref <f TimerActShutdown> <f ClTimerThread>
  35. ****/
  36. DWORD
  37. TimerActInitialize()
  38. {
  39. DWORD dwError = ERROR_SUCCESS;
  40. DWORD dwThreadId;
  41. //we need to create a thread to general log management
  42. //later this may be used by other clussvc client components
  43. ClRtlLogPrint(LOG_NOISE,
  44. "[LM] TimerActInitialize Entry. \r\n");
  45. InitializeCriticalSection(&gActivityCritSec);
  46. //initialize the activity structures
  47. //when a log file is created, an activity structure
  48. //will be added to this list
  49. InitializeListHead(&gActivityHead);
  50. //create an auto-reset event to signal changes to the timer list
  51. ghTimerCtrlEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  52. if (!ghTimerCtrlEvent)
  53. {
  54. dwError = GetLastError();
  55. CL_LOGFAILURE(dwError);
  56. goto FnExit;
  57. }
  58. //create a manual reset event for the timer thread to signal
  59. //when it is done syncing the activitity list
  60. ghTimerCtrlDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  61. if (!ghTimerCtrlDoneEvent)
  62. {
  63. dwError = GetLastError();
  64. CL_LOGFAILURE(dwError);
  65. goto FnExit;
  66. }
  67. gdwNumHandles = 1;
  68. grghWaitHandles[0] = ghTimerCtrlEvent;
  69. //create a thread to do the periodic management
  70. ghTimerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ClTimerThread,
  71. NULL, 0, &dwThreadId);
  72. if (!ghTimerThread)
  73. {
  74. dwError = GetLastError();
  75. CL_LOGFAILURE(dwError);
  76. }
  77. FnExit:
  78. if (dwError != ERROR_SUCCESS)
  79. {
  80. //free up resources
  81. if (ghTimerCtrlEvent)
  82. {
  83. CloseHandle(ghTimerCtrlEvent);
  84. ghTimerCtrlEvent = NULL;
  85. }
  86. //free up resources
  87. if (ghTimerCtrlDoneEvent)
  88. {
  89. CloseHandle(ghTimerCtrlDoneEvent);
  90. ghTimerCtrlDoneEvent = NULL;
  91. }
  92. DeleteCriticalSection(&gActivityCritSec);
  93. }
  94. return(dwError);
  95. }
  96. /****
  97. @func DWORD | ClTimerThread | This thread does a wait on all the
  98. waitable timers registered within the cluster service.
  99. @parm PVOID | pContext | Supplies the identifier of the log.
  100. @comm When any of the timers is signaled, it calls the activity callback
  101. function corresponding to that timer. When the timer control event
  102. is signaled, it either resyncs its wait handles or shuts down.
  103. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  104. @xref <f AddTimerActivity> <f RemoveTimerActivity>
  105. ****/
  106. DWORD WINAPI ClTimerThread(PVOID pContext)
  107. {
  108. HANDLE hClTimer;
  109. DWORD dwReturn;
  110. while (TRUE)
  111. {
  112. dwReturn = WaitForMultipleObjects(gdwNumHandles, grghWaitHandles, FALSE, INFINITE);
  113. //walk the activity list
  114. if (dwReturn == WAIT_FAILED)
  115. {
  116. //run down the activity lists and call the functions
  117. ClRtlLogPrint(LOG_UNUSUAL,
  118. "[LM] ClTimerThread: WaitformultipleObjects failed 0x%1!08lx!\r\n",
  119. GetLastError());
  120. }
  121. else if (dwReturn == 0)
  122. {
  123. //the first handle is the timer ctrl event
  124. if (gdwTimerCtrl == TIMER_ACTIVITY_SHUTDOWN)
  125. {
  126. ExitThread(0);
  127. }
  128. else if (gdwTimerCtrl == TIMER_ACTIVITY_CHANGE)
  129. {
  130. ReSyncTimerHandles();
  131. }
  132. }
  133. else
  134. {
  135. // SS::we got rid of holding the critsec by using the manual
  136. // reset event.
  137. if (dwReturn < gdwNumHandles)
  138. {
  139. //if the activity has been set up for delete, we cant rely
  140. //on the context and callback being there!
  141. if (grgpActivity[dwReturn]->dwState == ACTIVITY_STATE_READY)
  142. {
  143. //call the corresponding activity fn
  144. (*((grgpActivity[dwReturn])->pfnTimerCb))
  145. ((grgpActivity[dwReturn])->hWaitableTimer,
  146. (grgpActivity[dwReturn])->pContext);
  147. }
  148. }
  149. }
  150. }
  151. return(0);
  152. }
  153. /****
  154. @func DWORD | ReSyncTimerHandles | resyncs the wait handles,
  155. when the activity list changes.
  156. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  157. @comm This function is called by the timer thread to resync its
  158. wait handles according to the timer activities currently
  159. registered.
  160. @xref <f ClTimerThread>
  161. ****/
  162. void ReSyncTimerHandles()
  163. {
  164. PLIST_ENTRY pListEntry;
  165. PTIMER_ACTIVITY pActivity;
  166. int i = 1;
  167. ClRtlLogPrint(LOG_NOISE,
  168. "[LM] ReSyncTimerHandles Entry. \r\n");
  169. EnterCriticalSection(&gActivityCritSec);
  170. pListEntry = gActivityHead.Flink;
  171. gdwNumHandles = 1;
  172. //will resync the list of waitable timers and activities
  173. //depending on the activity list
  174. while ((pListEntry != &gActivityHead) && (i< MAX_TIMER_ACTIVITIES))
  175. {
  176. pActivity = CONTAINING_RECORD(pListEntry, TIMER_ACTIVITY, ListEntry);
  177. //goto the next link
  178. pListEntry = pListEntry->Flink;
  179. if (pActivity->dwState == ACTIVITY_STATE_DELETE)
  180. {
  181. ClRtlLogPrint(LOG_NOISE,
  182. "[LM] ResyncTimerHandles: removed Timer 0x%1!08lx!\r\n",
  183. pActivity->hWaitableTimer);
  184. RemoveEntryList(&pActivity->ListEntry);
  185. //close the timer handle here
  186. CloseHandle(pActivity->hWaitableTimer);
  187. LocalFree(pActivity);
  188. continue;
  189. }
  190. //call the fn
  191. grghWaitHandles[i] = pActivity->hWaitableTimer;
  192. grgpActivity[i] = pActivity;
  193. gdwNumHandles++;
  194. i++;
  195. }
  196. LeaveCriticalSection(&gActivityCritSec);
  197. //now if timer activities were resynced, we need to
  198. //signal all threads that might be waiting on this
  199. SetEvent(ghTimerCtrlDoneEvent);
  200. ClRtlLogPrint(LOG_NOISE,
  201. "[LM] ReSyncTimerHandles Exit gdwNumHandles=%1!u!\r\n",
  202. gdwNumHandles);
  203. }
  204. /****
  205. @func DWORD | AddTimerActivity | Adds a periodic Activity to the timer
  206. callback list.
  207. @parm HANDLE | hTimer | A handle to a waitaible timer object.
  208. @parm DWORD | dwInterval | The duration for this timer, in
  209. msecs.
  210. @parm LONG | lPeriod | If lPeriod is 0, the timer is signalled once
  211. if greater than 0, the timer is periodic. If less than zero, then
  212. error will be returned.
  213. @parm PFN_TIMER_CALLBACK | pfnTimerCb | A pointer to the callback function
  214. that will be called when this timer is signaled.
  215. @parm PVOID | pContext | A pointer to the callback data that will be
  216. passed to the callback function.
  217. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  218. @comm SetWaitableTimer() for the corresponding timer is called by this
  219. function for the given duration. CreateWaitableTimer() must be used to
  220. create this timer handle.
  221. @xref <f RemoveTimerActivity>
  222. ****/
  223. DWORD AddTimerActivity(IN HANDLE hTimer, IN DWORD dwInterval,
  224. IN LONG lPeriod, IN PFN_TIMER_CALLBACK pfnTimerCb, IN PVOID pContext)
  225. {
  226. PTIMER_ACTIVITY pActivity = NULL;
  227. DWORD dwError = ERROR_SUCCESS;
  228. LARGE_INTEGER Interval;
  229. ClRtlLogPrint(LOG_NOISE,
  230. "[LM] AddTimerActivity: hTimer = 0x%1!08lx! pfnTimerCb=0x%2!08lx! dwInterval(in msec)=%3!u!\r\n",
  231. hTimer, pfnTimerCb, dwInterval);
  232. pActivity =(PTIMER_ACTIVITY) LocalAlloc(LMEM_FIXED,sizeof(TIMER_ACTIVITY));
  233. if (!pActivity)
  234. {
  235. dwError = GetLastError();
  236. CL_UNEXPECTED_ERROR(dwError);
  237. goto FnExit;
  238. }
  239. Interval.QuadPart = -10 * 1000 * (_int64)dwInterval; //time in 100 nano secs
  240. ClRtlLogPrint(LOG_NOISE,
  241. "[LM] AddTimerActivity: Interval(high)=0x%1!08lx! Interval(low)=0x%2!08lx!\r\n",
  242. Interval.HighPart, Interval.LowPart);
  243. pActivity->hWaitableTimer = hTimer;
  244. memcpy(&(pActivity->Interval), (LPBYTE)&Interval, sizeof(LARGE_INTEGER));
  245. pActivity->pfnTimerCb = pfnTimerCb;
  246. pActivity->pContext = pContext;
  247. //set the timer
  248. if (lPeriod)
  249. {
  250. lPeriod = (LONG)dwInterval;
  251. }
  252. else
  253. {
  254. lPeriod = 0;
  255. }
  256. if (!SetWaitableTimer(hTimer, &Interval, lPeriod , NULL, NULL, FALSE))
  257. {
  258. CL_LOGFAILURE((dwError = GetLastError()));
  259. goto FnExit;
  260. };
  261. //add to the list of activities
  262. //and get the timer thread to resync
  263. EnterCriticalSection(&gActivityCritSec);
  264. pActivity->dwState = ACTIVITY_STATE_READY;
  265. InitializeListHead(&pActivity->ListEntry);
  266. InsertTailList(&gActivityHead, &pActivity->ListEntry);
  267. gdwTimerCtrl = TIMER_ACTIVITY_CHANGE;
  268. LeaveCriticalSection(&gActivityCritSec);
  269. SetEvent(ghTimerCtrlEvent);
  270. FnExit:
  271. if ( (dwError != ERROR_SUCCESS) &&
  272. pActivity ) {
  273. LocalFree(pActivity);
  274. }
  275. ClRtlLogPrint(LOG_NOISE,
  276. "[LM] AddTimerActivity: returns 0x%1!08lx!\r\n",
  277. dwError);
  278. return(dwError);
  279. }
  280. /****
  281. @func DWORD | RemoveTimerActivity | This functions removes the
  282. activity associated with a timer from the timer threads activity
  283. list.
  284. @parm HANDLE | hTimer | The handle to the timer whose related activity will
  285. be removed. The handle is closed.
  286. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  287. @comm This function cancels the waitable timer and removes the activity
  288. corresponding to it. The calling component must not close the handle
  289. to the timer. It is closed by the timer activity manager once this function is called.
  290. @xref <f AddTimerActivity>
  291. ****/
  292. DWORD RemoveTimerActivity(HANDLE hTimer)
  293. {
  294. PLIST_ENTRY pListEntry;
  295. PTIMER_ACTIVITY pActivity;
  296. PTIMER_ACTIVITY pActivityToDel = NULL;
  297. DWORD dwError = ERROR_SUCCESS;
  298. ClRtlLogPrint(LOG_NOISE,
  299. "[LM] LmRemoveTimerActivity: Entry 0x%1!08lx!\r\n",
  300. hTimer);
  301. EnterCriticalSection(&gActivityCritSec);
  302. pListEntry = gActivityHead.Flink;
  303. while (pListEntry != &gActivityHead) {
  304. pActivity = CONTAINING_RECORD(pListEntry, TIMER_ACTIVITY, ListEntry);
  305. if (pActivity->hWaitableTimer == hTimer)
  306. {
  307. pActivityToDel = pActivity;
  308. break;
  309. }
  310. pListEntry = pListEntry->Flink;
  311. }
  312. if (!pActivityToDel)
  313. {
  314. ClRtlLogPrint(LOG_UNUSUAL,
  315. "[LM] LmRemoveTimerActivity: didnt find activity correspondint to 0x%1!08lx!\r\n",
  316. hTimer);
  317. }
  318. else
  319. {
  320. //will be deleted by resynctimerhandles
  321. CancelWaitableTimer(pActivityToDel->hWaitableTimer);
  322. pActivityToDel->dwState = ACTIVITY_STATE_DELETE;
  323. }
  324. //signal the timer thread to resync its array of wait handles
  325. //from this list
  326. SetEvent(ghTimerCtrlEvent);
  327. //do a manual reset on the done event so that we will wait on it
  328. //until the timer thread has done a resync of its array of
  329. //wait handles from the list after this thread leaves the critsec
  330. //note that we do this holding the critsec
  331. //now we are guaranteed that timer thread will wake us up
  332. ResetEvent(ghTimerCtrlDoneEvent);
  333. LeaveCriticalSection(&gActivityCritSec);
  334. //wait till the timer thread signals that done event
  335. WaitForSingleObject(ghTimerCtrlDoneEvent, INFINITE);
  336. ClRtlLogPrint(LOG_NOISE,
  337. "[LM] LmRemoveTimerActivity: Exit\r\n");
  338. return(dwError);
  339. }
  340. /****
  341. @func DWORD | PauseTimerActivity | This functions pauses the
  342. activity associated with a timer in the timer threads activity
  343. list.
  344. @parm HANDLE | hTimer | The handle to the timer whose related activity will
  345. be removed.
  346. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  347. @comm This function sets the timer into a paused state so that the timer
  348. callbacks are not proccessed.
  349. @xref <f AddTimerActivity> <f
  350. ****/
  351. DWORD PauseTimerActivity(HANDLE hTimer)
  352. {
  353. PLIST_ENTRY pListEntry;
  354. PTIMER_ACTIVITY pActivity;
  355. PTIMER_ACTIVITY pActivityToDel = NULL;
  356. DWORD dwError = ERROR_SUCCESS;
  357. ClRtlLogPrint(LOG_NOISE,
  358. "[LM] PauseTimerActivity: Entry 0x%1!08lx!\r\n",
  359. hTimer);
  360. EnterCriticalSection(&gActivityCritSec);
  361. pListEntry = gActivityHead.Flink;
  362. while (pListEntry != &gActivityHead) {
  363. pActivity = CONTAINING_RECORD(pListEntry, TIMER_ACTIVITY, ListEntry);
  364. if (pActivity->hWaitableTimer == hTimer)
  365. {
  366. pActivityToDel = pActivity;
  367. break;
  368. }
  369. pListEntry = pListEntry->Flink;
  370. }
  371. if (!pActivityToDel)
  372. {
  373. ClRtlLogPrint(LOG_UNUSUAL,
  374. "[LM] PauseTimerActivity: didnt find activity correspondint to 0x%1!08lx!\r\n",
  375. hTimer);
  376. }
  377. else
  378. {
  379. CL_ASSERT(pActivity->dwState == ACTIVITY_STATE_READY);
  380. //set the state to be paused
  381. pActivityToDel->dwState = ACTIVITY_STATE_PAUSED;
  382. }
  383. //signal the timer thread to resync its array of wait handles
  384. //from this list
  385. SetEvent(ghTimerCtrlEvent);
  386. //do a manual reset on the done event so that we will wait on it
  387. //until the timer thread has done a resync of its array of
  388. //wait handles from the list after this thread leaves the critsec
  389. //note that we do this holding the critsec
  390. //now we are guaranteed that timer thread will wake us up
  391. ResetEvent(ghTimerCtrlDoneEvent);
  392. LeaveCriticalSection(&gActivityCritSec);
  393. //wait till the timer thread signals that done event
  394. WaitForSingleObject(ghTimerCtrlDoneEvent, INFINITE);
  395. ClRtlLogPrint(LOG_NOISE,
  396. "[LM] PauseTimerActivity: Exit\r\n");
  397. return(dwError);
  398. }
  399. /****
  400. @func DWORD | UnpauseTimerActivity | This functions unpauses the
  401. activity associated with a timer in the timer threads activity
  402. list.
  403. @parm HANDLE | hTimer | The handle to the timer whose related activity will
  404. be removed.
  405. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  406. @comm This function sets the activity into a ready state.
  407. @xref <f AddTimerActivity> <f
  408. ****/
  409. DWORD UnpauseTimerActivity(HANDLE hTimer)
  410. {
  411. PLIST_ENTRY pListEntry;
  412. PTIMER_ACTIVITY pActivity;
  413. PTIMER_ACTIVITY pActivityToDel = NULL;
  414. DWORD dwError = ERROR_SUCCESS;
  415. ClRtlLogPrint(LOG_NOISE,
  416. "[LM] UnpauseTimerActivity: Entry 0x%1!08lx!\r\n",
  417. hTimer);
  418. EnterCriticalSection(&gActivityCritSec);
  419. pListEntry = gActivityHead.Flink;
  420. while (pListEntry != &gActivityHead) {
  421. pActivity = CONTAINING_RECORD(pListEntry, TIMER_ACTIVITY, ListEntry);
  422. if (pActivity->hWaitableTimer == hTimer)
  423. {
  424. pActivityToDel = pActivity;
  425. break;
  426. }
  427. pListEntry = pListEntry->Flink;
  428. }
  429. if (!pActivityToDel)
  430. {
  431. ClRtlLogPrint(LOG_UNUSUAL,
  432. "[LM] PauseTimerActivity: didnt find activity correspondint to 0x%1!08lx!\r\n",
  433. hTimer);
  434. }
  435. else
  436. {
  437. CL_ASSERT(pActivity->dwState == ACTIVITY_STATE_PAUSED);
  438. //set the state to be paused
  439. pActivityToDel->dwState = ACTIVITY_STATE_READY;
  440. }
  441. LeaveCriticalSection(&gActivityCritSec);
  442. ClRtlLogPrint(LOG_NOISE,
  443. "[LM] UnpauseTimerActivity: Exit\r\n");
  444. return(dwError);
  445. }
  446. /****
  447. @func DWORD | TimerActShutdown | Deinitializes the TimerActivity manager.
  448. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  449. @comm This function notifies the timer thread to shutdown down and closes
  450. all resources associated with timer activity management.
  451. @xref <f TimerActInitialize>
  452. ****/
  453. DWORD
  454. TimerActShutdown(
  455. )
  456. {
  457. PLIST_ENTRY pListEntry;
  458. PTIMER_ACTIVITY pActivity;
  459. ClRtlLogPrint(LOG_NOISE,
  460. "[LM] TimerActShutDown : Entry \r\n");
  461. //check if we were initialized before
  462. if (ghTimerThread && ghTimerCtrlEvent)
  463. {
  464. //signal the timer thread to kill itself
  465. gdwTimerCtrl = TIMER_ACTIVITY_SHUTDOWN;
  466. SetEvent(ghTimerCtrlEvent);
  467. //wait for the thread to exit
  468. WaitForSingleObject(ghTimerThread,INFINITE);
  469. //close the timer thread control event
  470. CloseHandle(ghTimerCtrlEvent);
  471. ghTimerCtrlEvent = NULL;
  472. //close the timer thread control done event
  473. CloseHandle(ghTimerCtrlDoneEvent);
  474. ghTimerCtrlDoneEvent = NULL;
  475. CloseHandle(ghTimerThread);
  476. ghTimerThread = NULL;
  477. //clean up the activity structures, if there any left
  478. pListEntry = gActivityHead.Flink;
  479. while (pListEntry != &gActivityHead)
  480. {
  481. pActivity = CONTAINING_RECORD(pListEntry, TIMER_ACTIVITY, ListEntry);
  482. CloseHandle(pActivity->hWaitableTimer);
  483. LocalFree(pActivity);
  484. pListEntry = pListEntry->Flink;
  485. }
  486. //reset the activity head structure
  487. InitializeListHead(&gActivityHead);
  488. DeleteCriticalSection(&gActivityCritSec);
  489. }
  490. ClRtlLogPrint(LOG_NOISE,
  491. "[LM] TimerActShutDown : Exit\r\n");
  492. return(ERROR_SUCCESS);
  493. }