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.

965 lines
22 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. tpstimer.cpp
  5. Abstract:
  6. Contains Win32 thread pool services timer functions
  7. Contents:
  8. TerminateTimers
  9. SHCreateTimerQueue
  10. (IECreateTimerQueue)
  11. SHDeleteTimerQueue
  12. (IEDeleteTimerQueue)
  13. SHSetTimerQueueTimer
  14. (IESetTimerQueueTimer)
  15. (NTSetTimerQueueTimer)
  16. SHChangeTimerQueueTimer
  17. (IEChangeTimerQueueTimer)
  18. SHCancelTimerQueueTimer
  19. (IECancelTimerQueueTimer)
  20. (NTCancelTimerQueueTimer)
  21. (InitializeTimerThread)
  22. (TimerCleanup)
  23. (CreateDefaultTimerQueue)
  24. (DeleteDefaultTimerQueue)
  25. (CleanupDefaultTimerQueue)
  26. (TimerThread)
  27. (DeleteTimerQueue)
  28. (AddTimer)
  29. (ChangeTimer)
  30. (CancelTimer)
  31. Author:
  32. Richard L Firth (rfirth) 10-Feb-1998
  33. Environment:
  34. Win32 user-mode
  35. Notes:
  36. Code reworked in C++ from NT-specific C code written by Gurdeep Singh Pall
  37. (gurdeep)
  38. Revision History:
  39. 10-Feb-1998 rfirth
  40. Created
  41. --*/
  42. #include "priv.h"
  43. #include "threads.h"
  44. #include "tpsclass.h"
  45. #include "tpstimer.h"
  46. //
  47. // private prototypes
  48. //
  49. typedef HANDLE (WINAPI * t_CreateTimerQueue)(VOID);
  50. typedef BOOL (WINAPI * t_DeleteTimerQueue)(HANDLE);
  51. typedef HANDLE (WINAPI * t_SetTimerQueueTimer)(HANDLE,
  52. WAITORTIMERCALLBACKFUNC,
  53. LPVOID,
  54. DWORD,
  55. DWORD,
  56. LPCSTR,
  57. DWORD
  58. );
  59. typedef BOOL (WINAPI * t_ChangeTimerQueueTimer)(HANDLE, HANDLE, DWORD, DWORD);
  60. typedef BOOL (WINAPI * t_CancelTimerQueueTimer)(HANDLE, HANDLE);
  61. // These are KERNEL32 functions that do not match our SHLWAPI APIs
  62. typedef BOOL (WINAPI * t_CreateTimerQueueTimer)(PHANDLE,
  63. HANDLE,
  64. WAITORTIMERCALLBACKFUNC,
  65. LPVOID,
  66. DWORD,
  67. DWORD,
  68. ULONG
  69. );
  70. typedef BOOL (WINAPI * t_DeleteTimerQueueTimer)(HANDLE, HANDLE, HANDLE);
  71. PRIVATE
  72. DWORD
  73. InitializeTimerThread(
  74. VOID
  75. );
  76. PRIVATE
  77. VOID
  78. TimerCleanup(
  79. VOID
  80. );
  81. PRIVATE
  82. HANDLE
  83. CreateDefaultTimerQueue(
  84. VOID
  85. );
  86. PRIVATE
  87. VOID
  88. DeleteDefaultTimerQueue(
  89. VOID
  90. );
  91. PRIVATE
  92. VOID
  93. CleanupDefaultTimerQueue(
  94. VOID
  95. );
  96. PRIVATE
  97. VOID
  98. TimerThread(
  99. VOID
  100. );
  101. PRIVATE
  102. VOID
  103. DeleteTimerQueue(
  104. IN CTimerQueueDeleteRequest * pRequest
  105. );
  106. PRIVATE
  107. VOID
  108. AddTimer(
  109. IN CTimerAddRequest * pRequest
  110. );
  111. PRIVATE
  112. VOID
  113. ChangeTimer(
  114. IN CTimerChangeRequest * pRequest
  115. );
  116. PRIVATE
  117. VOID
  118. CancelTimer(
  119. IN CTimerCancelRequest * pRequest
  120. );
  121. //
  122. // global data
  123. //
  124. CTimerQueueList g_TimerQueueList;
  125. HANDLE g_hDefaultTimerQueue = NULL;
  126. HANDLE g_hTimerThread = NULL;
  127. DWORD g_dwTimerId = 0;
  128. LONG g_UID = 0;
  129. BOOL g_bTimerInit = FALSE;
  130. BOOL g_bTimerInitDone = FALSE;
  131. BOOL g_bDeferredTimerTermination = FALSE;
  132. //
  133. // Forward-declared data.
  134. //
  135. extern t_CreateTimerQueue _I_CreateTimerQueue;
  136. extern t_DeleteTimerQueue _I_DeleteTimerQueue;
  137. extern t_SetTimerQueueTimer _I_SetTimerQueueTimer;
  138. extern t_ChangeTimerQueueTimer _I_ChangeTimerQueueTimer;
  139. extern t_CancelTimerQueueTimer _I_CancelTimerQueueTimer;
  140. extern t_CreateTimerQueueTimer _I_CreateTimerQueueTimer;
  141. extern t_DeleteTimerQueueTimer _I_DeleteTimerQueueTimer;
  142. //
  143. // Wrappers for NT5 because the Shlwapi version differs slightly from the
  144. // NT version.
  145. //
  146. LWSTDAPI_(HANDLE)
  147. NTSetTimerQueueTimer(
  148. IN HANDLE hQueue,
  149. IN WAITORTIMERCALLBACKFUNC pfnCallback,
  150. IN LPVOID pContext,
  151. IN DWORD dwDueTime,
  152. IN DWORD dwPeriod,
  153. IN LPCSTR lpszLibrary OPTIONAL,
  154. IN DWORD dwFlags
  155. )
  156. {
  157. //
  158. // Translate the flags from TPS flags to WT flags.
  159. //
  160. DWORD dwWTFlags = 0;
  161. if (dwFlags & TPS_EXECUTEIO) dwWTFlags |= WT_EXECUTEINIOTHREAD;
  162. if (dwFlags & TPS_LONGEXECTIME) dwWTFlags |= WT_EXECUTELONGFUNCTION;
  163. HANDLE hTimer;
  164. if (_I_CreateTimerQueueTimer(&hTimer, hQueue, pfnCallback, pContext, dwDueTime, dwPeriod, dwWTFlags))
  165. {
  166. return hTimer;
  167. }
  168. return NULL;
  169. }
  170. LWSTDAPI_(BOOL)
  171. NTCancelTimerQueueTimer(
  172. IN HANDLE hQueue,
  173. IN HANDLE hTimer
  174. )
  175. {
  176. return _I_DeleteTimerQueueTimer(hQueue, hTimer, INVALID_HANDLE_VALUE);
  177. }
  178. STDAPI_(void) InitTimerQueue()
  179. {
  180. if (IsOS(OS_WHISTLERORGREATER))
  181. {
  182. HMODULE hKernel32 = GetModuleHandle("KERNEL32.DLL");
  183. if (hKernel32)
  184. {
  185. t_CreateTimerQueue NTCreateTimerQueue;
  186. t_DeleteTimerQueue NTDeleteTimerQueue;
  187. t_CreateTimerQueueTimer NTCreateTimerQueueTimer;
  188. t_ChangeTimerQueueTimer NTChangeTimerQueueTimer;
  189. t_DeleteTimerQueueTimer NTDeleteTimerQueueTimer;
  190. #define GetKernelProc(fn) \
  191. ((NT##fn = (t_##fn)GetProcAddress(hKernel32, #fn)) != NULL)
  192. if (GetKernelProc(CreateTimerQueue) &&
  193. GetKernelProc(DeleteTimerQueue) &&
  194. GetKernelProc(CreateTimerQueueTimer) &&
  195. GetKernelProc(ChangeTimerQueueTimer) &&
  196. GetKernelProc(DeleteTimerQueueTimer))
  197. {
  198. #define SwitchToNTVersion(fn) (_I_##fn = NT##fn)
  199. // Redirect the SHLWAPI APIs to the NT versions
  200. // (They either point directly to the KERNEL API
  201. // or to our stub functions.)
  202. SwitchToNTVersion(CreateTimerQueue);
  203. SwitchToNTVersion(DeleteTimerQueue);
  204. SwitchToNTVersion(ChangeTimerQueueTimer);
  205. SwitchToNTVersion(SetTimerQueueTimer);
  206. SwitchToNTVersion(CancelTimerQueueTimer);
  207. // Save these values so our stub functions can
  208. // call the KERNEL API after they do their translation.
  209. SwitchToNTVersion(CreateTimerQueueTimer);
  210. SwitchToNTVersion(DeleteTimerQueueTimer);
  211. }
  212. #undef GetKernelProc
  213. #undef SwitchToNTVersion
  214. }
  215. }
  216. }
  217. //
  218. // functions
  219. //
  220. VOID
  221. TerminateTimers(
  222. VOID
  223. )
  224. /*++
  225. Routine Description:
  226. Terminate timer thread and global variables
  227. Arguments:
  228. None.
  229. Return Value:
  230. None.
  231. --*/
  232. {
  233. if (g_bTimerInitDone) {
  234. DWORD threadId = GetCurrentThreadId();
  235. if ((g_hTimerThread != NULL) && (threadId != g_dwTimerId)) {
  236. QueueNullFunc(g_hTimerThread);
  237. DWORD ticks = GetTickCount();
  238. while (g_hTimerThread != NULL) {
  239. SleepEx(0, TRUE);
  240. if (GetTickCount() - ticks > 10000) {
  241. CloseHandle(g_hTimerThread);
  242. g_hTimerThread = NULL;
  243. break;
  244. }
  245. }
  246. }
  247. if (g_dwTimerId == threadId) {
  248. g_bDeferredTimerTermination = TRUE;
  249. } else {
  250. TimerCleanup();
  251. }
  252. }
  253. }
  254. LWSTDAPI_(HANDLE)
  255. SHCreateTimerQueue(
  256. VOID
  257. )
  258. {
  259. return _I_CreateTimerQueue();
  260. }
  261. LWSTDAPI_(HANDLE)
  262. IECreateTimerQueue(
  263. VOID
  264. )
  265. /*++
  266. Routine Description:
  267. Creates a timer queue
  268. Arguments:
  269. None.
  270. Return Value:
  271. HANDLE
  272. Success - non-NULL pointer to CTimerQueue object
  273. Failure - NULL. GetLastError() for more info
  274. --*/
  275. {
  276. InterlockedIncrement((LPLONG)&g_ActiveRequests);
  277. HANDLE hResult = NULL;
  278. DWORD error = ERROR_SUCCESS;
  279. if (!g_bTpsTerminating) {
  280. if (g_hTimerThread == NULL) {
  281. error = InitializeTimerThread();
  282. }
  283. if (error == ERROR_SUCCESS) {
  284. //
  285. // timer queue handle is just pointer to timer queue object
  286. //
  287. hResult = (HANDLE) new CTimerQueue(&g_TimerQueueList);
  288. } else {
  289. SetLastError(error);
  290. }
  291. } else {
  292. SetLastError(ERROR_SHUTDOWN_IN_PROGRESS); // error code? looks valid -justmann
  293. }
  294. InterlockedDecrement((LPLONG)&g_ActiveRequests);
  295. return hResult;
  296. }
  297. LWSTDAPI_(BOOL)
  298. SHDeleteTimerQueue(
  299. IN HANDLE hQueue
  300. )
  301. {
  302. return _I_DeleteTimerQueue(hQueue);
  303. }
  304. LWSTDAPI_(BOOL)
  305. IEDeleteTimerQueue(
  306. IN HANDLE hQueue
  307. )
  308. /*++
  309. Routine Description:
  310. Deletes the specified timer queue
  311. Arguments:
  312. hQueue - handle of queue to delete; NULL for default timer queue
  313. Return Value:
  314. BOOL
  315. Success - TRUE
  316. Failure - FALSE. Call GetLastError() for more info
  317. --*/
  318. {
  319. InterlockedIncrement((LPLONG)&g_ActiveRequests);
  320. BOOL bSuccess = FALSE;
  321. if (!g_bTpsTerminating) {
  322. if (hQueue == NULL) {
  323. hQueue = g_hDefaultTimerQueue;
  324. }
  325. if ((hQueue != NULL) && (g_hTimerThread != NULL)) {
  326. CTimerQueueDeleteRequest request(hQueue);
  327. if (QueueUserAPC((PAPCFUNC)DeleteTimerQueue,
  328. g_hTimerThread,
  329. (ULONG_PTR)&request)) {
  330. request.WaitForCompletion();
  331. bSuccess = request.SetThreadStatus();
  332. } else {
  333. #if DBG
  334. DWORD error = GetLastError();
  335. ASSERT(error == ERROR_SUCCESS);
  336. #endif
  337. }
  338. } else {
  339. SetLastError(ERROR_INVALID_PARAMETER); // correct error code? looks valid -justmann
  340. }
  341. } else {
  342. SetLastError(ERROR_SHUTDOWN_IN_PROGRESS); // error code? looks valid -justmann
  343. }
  344. InterlockedDecrement((LPLONG)&g_ActiveRequests);
  345. return bSuccess;
  346. }
  347. LWSTDAPI_(HANDLE)
  348. SHSetTimerQueueTimer(
  349. IN HANDLE hQueue,
  350. IN WAITORTIMERCALLBACKFUNC pfnCallback,
  351. IN LPVOID pContext,
  352. IN DWORD dwDueTime,
  353. IN DWORD dwPeriod,
  354. IN LPCSTR lpszLibrary OPTIONAL,
  355. IN DWORD dwFlags
  356. )
  357. {
  358. return _I_SetTimerQueueTimer(hQueue, pfnCallback, pContext, dwDueTime, dwPeriod, lpszLibrary, dwFlags);
  359. }
  360. LWSTDAPI_(HANDLE)
  361. IESetTimerQueueTimer(
  362. IN HANDLE hQueue,
  363. IN WAITORTIMERCALLBACKFUNC pfnCallback,
  364. IN LPVOID pContext,
  365. IN DWORD dwDueTime,
  366. IN DWORD dwPeriod,
  367. IN LPCSTR lpszLibrary OPTIONAL,
  368. IN DWORD dwFlags
  369. )
  370. /*++
  371. Routine Description:
  372. Add a timer to a queue
  373. Arguments:
  374. hQueue - handle of timer queue; NULL for default queue
  375. pfnCallback - function to call when timer triggers
  376. pContext - parameter to pfnCallback
  377. dwDueTime - initial firing time in milliseconds from now
  378. dwPeriod - repeating period. 0 for one-shot
  379. lpszLibrary - if specified, name of library (DLL) to reference
  380. dwFlags - flags controlling function:
  381. TPS_EXECUTEIO - Execute callback in I/O thread
  382. Return Value:
  383. HANDLE
  384. Success - non-NULL handle
  385. Failure - NULL. Call GetLastError() for more info
  386. --*/
  387. {
  388. InterlockedIncrement((LPLONG)&g_ActiveRequests);
  389. HANDLE hTimer = NULL;
  390. if (!g_bTpsTerminating) {
  391. DWORD error = ERROR_SUCCESS;
  392. if (g_hTimerThread == NULL) {
  393. error = InitializeTimerThread();
  394. }
  395. ASSERT(g_hTimerThread != NULL);
  396. if (error == ERROR_SUCCESS) {
  397. if (hQueue == NULL) {
  398. hQueue = CreateDefaultTimerQueue();
  399. }
  400. if (hQueue != NULL) {
  401. CTimerAddRequest * pRequest = new CTimerAddRequest(hQueue,
  402. pfnCallback,
  403. pContext,
  404. dwDueTime,
  405. dwPeriod,
  406. dwFlags
  407. );
  408. if (pRequest != NULL) {
  409. hTimer = pRequest->GetHandle();
  410. if (QueueUserAPC((PAPCFUNC)AddTimer,
  411. g_hTimerThread,
  412. (ULONG_PTR)pRequest
  413. )) {
  414. } else {
  415. #if DBG
  416. error = GetLastError();
  417. ASSERT(GetLastError() != ERROR_SUCCESS);
  418. #endif
  419. delete pRequest;
  420. hTimer = NULL;
  421. #if DBG
  422. SetLastError(error);
  423. #endif
  424. }
  425. }
  426. }
  427. } else {
  428. SetLastError(error);
  429. }
  430. } else {
  431. SetLastError(ERROR_SHUTDOWN_IN_PROGRESS); // error code? looks valid -justmann
  432. }
  433. InterlockedDecrement((LPLONG)&g_ActiveRequests);
  434. return hTimer;
  435. }
  436. LWSTDAPI_(BOOL)
  437. SHChangeTimerQueueTimer(
  438. IN HANDLE hQueue,
  439. IN HANDLE hTimer,
  440. IN DWORD dwDueTime,
  441. IN DWORD dwPeriod
  442. )
  443. {
  444. return _I_ChangeTimerQueueTimer(hQueue, hTimer, dwDueTime, dwPeriod);
  445. }
  446. LWSTDAPI_(BOOL)
  447. IEChangeTimerQueueTimer(
  448. IN HANDLE hQueue,
  449. IN HANDLE hTimer,
  450. IN DWORD dwDueTime,
  451. IN DWORD dwPeriod
  452. )
  453. /*++
  454. Routine Description:
  455. Change the due time or periodicity of a timer
  456. Arguments:
  457. hQueue - handle of queue on which timer resides. NULL for default queue
  458. hTimer - handle of timer to change
  459. dwDueTime - new due time
  460. dwPeriod - new period
  461. Return Value:
  462. BOOL
  463. Success - TRUE
  464. Failure - FALSE. Call GetLastError() for more info
  465. --*/
  466. {
  467. InterlockedIncrement((LPLONG)&g_ActiveRequests);
  468. BOOL bSuccess = FALSE;
  469. DWORD error = ERROR_SHUTDOWN_IN_PROGRESS; // error code? looks valid -justmann
  470. if (!g_bTpsTerminating) {
  471. error = ERROR_OBJECT_NOT_FOUND;
  472. if (g_hTimerThread != NULL) {
  473. if (hQueue == NULL) {
  474. hQueue = g_hDefaultTimerQueue;
  475. }
  476. if (hQueue != NULL) {
  477. CTimerChangeRequest request(hQueue, hTimer, dwDueTime, dwPeriod);
  478. error = ERROR_SUCCESS; // both paths call SetLastError() if reqd
  479. if (QueueUserAPC((PAPCFUNC)ChangeTimer,
  480. g_hTimerThread,
  481. (ULONG_PTR)&request
  482. )) {
  483. request.WaitForCompletion();
  484. bSuccess = request.SetThreadStatus();
  485. } else {
  486. #if DBG
  487. ASSERT(GetLastError() == ERROR_SUCCESS);
  488. #endif
  489. }
  490. }
  491. }
  492. }
  493. InterlockedDecrement((LPLONG)&g_ActiveRequests);
  494. if (error != ERROR_SUCCESS) {
  495. SetLastError(error);
  496. }
  497. return bSuccess;
  498. }
  499. LWSTDAPI_(BOOL)
  500. SHCancelTimerQueueTimer(
  501. IN HANDLE hQueue,
  502. IN HANDLE hTimer
  503. )
  504. {
  505. return _I_CancelTimerQueueTimer(hQueue, hTimer);
  506. }
  507. LWSTDAPI_(BOOL)
  508. IECancelTimerQueueTimer(
  509. IN HANDLE hQueue,
  510. IN HANDLE hTimer
  511. )
  512. /*++
  513. Routine Description:
  514. Cancels a timer
  515. Arguments:
  516. hQueue - handle to queue on which timer resides
  517. hTimer - handle of timer to cancel
  518. Return Value:
  519. BOOL
  520. Success - TRUE
  521. Failure - FALSE. Call GetLastError() for more info
  522. --*/
  523. {
  524. InterlockedIncrement((LPLONG)&g_ActiveRequests);
  525. BOOL bSuccess = FALSE;
  526. if (!g_bTpsTerminating) {
  527. if (hQueue == NULL) {
  528. hQueue = g_hDefaultTimerQueue;
  529. }
  530. if ((hQueue != NULL) && (g_hTimerThread != NULL)) {
  531. CTimerCancelRequest request(hQueue, hTimer);
  532. if (QueueUserAPC((PAPCFUNC)CancelTimer,
  533. g_hTimerThread,
  534. (ULONG_PTR)&request
  535. )) {
  536. request.WaitForCompletion();
  537. bSuccess = request.SetThreadStatus();
  538. } else {
  539. #if DBG
  540. DWORD error = GetLastError();
  541. ASSERT(error == ERROR_SUCCESS);
  542. #endif
  543. }
  544. } else {
  545. SetLastError(ERROR_INVALID_HANDLE);
  546. }
  547. } else {
  548. SetLastError(ERROR_SHUTDOWN_IN_PROGRESS); // error code? looks valid -justmann
  549. }
  550. InterlockedDecrement((LPLONG)&g_ActiveRequests);
  551. return bSuccess;
  552. }
  553. //
  554. // private functions
  555. //
  556. PRIVATE
  557. DWORD
  558. InitializeTimerThread(
  559. VOID
  560. )
  561. {
  562. DWORD error = ERROR_SUCCESS;
  563. while (!g_bTimerInitDone) {
  564. if (!InterlockedExchange((LPLONG)&g_bTimerInit, TRUE)) {
  565. //
  566. // N.B. if CTimerQueueList::Init() does anything more than just
  567. // initialize lists then add a Deinit()
  568. //
  569. g_TimerQueueList.Init();
  570. ASSERT(g_hTimerThread == NULL);
  571. error = StartThread((LPTHREAD_START_ROUTINE)TimerThread,
  572. &g_hTimerThread,
  573. FALSE
  574. );
  575. if (error == ERROR_SUCCESS) {
  576. g_bTimerInitDone = TRUE;
  577. } else {
  578. InterlockedExchange((LPLONG)&g_bTimerInit, FALSE);
  579. }
  580. break;
  581. } else {
  582. SleepEx(0, FALSE);
  583. }
  584. }
  585. return error;
  586. }
  587. PRIVATE
  588. VOID
  589. TimerCleanup(
  590. VOID
  591. )
  592. {
  593. while (!g_TimerQueueList.QueueListHead()->IsEmpty()) {
  594. CTimerQueueDeleteRequest request((CTimerQueue *)
  595. g_TimerQueueList.QueueListHead()->Next());
  596. DeleteTimerQueue(&request);
  597. }
  598. DeleteDefaultTimerQueue();
  599. g_UID = 0;
  600. g_bTimerInit = FALSE;
  601. g_bTimerInitDone = FALSE;
  602. }
  603. BOOL bDefaultQueueInit = FALSE;
  604. BOOL bDefaultQueueInitDone = FALSE;
  605. BOOL bDefaultQueueInitFailed = FALSE;
  606. PRIVATE
  607. HANDLE
  608. CreateDefaultTimerQueue(
  609. VOID
  610. )
  611. {
  612. do {
  613. if ((g_hDefaultTimerQueue != NULL) || bDefaultQueueInitFailed) {
  614. return g_hDefaultTimerQueue;
  615. }
  616. if (!InterlockedExchange((LPLONG)&bDefaultQueueInit, TRUE)) {
  617. InterlockedExchange((LPLONG)&bDefaultQueueInitDone, FALSE);
  618. g_hDefaultTimerQueue = SHCreateTimerQueue();
  619. if (g_hDefaultTimerQueue == NULL) {
  620. bDefaultQueueInitFailed = TRUE;
  621. InterlockedExchange((LPLONG)&bDefaultQueueInit, FALSE);
  622. }
  623. InterlockedExchange((LPLONG)&bDefaultQueueInitDone, TRUE);
  624. } else {
  625. do {
  626. SleepEx(0, FALSE);
  627. } while (!bDefaultQueueInitDone);
  628. }
  629. } while (TRUE);
  630. }
  631. PRIVATE
  632. VOID
  633. DeleteDefaultTimerQueue(
  634. VOID
  635. )
  636. {
  637. if (g_hDefaultTimerQueue != NULL) {
  638. CTimerQueueDeleteRequest request((CTimerQueue *)g_hDefaultTimerQueue);
  639. DeleteTimerQueue(&request);
  640. g_hDefaultTimerQueue = NULL;
  641. }
  642. CleanupDefaultTimerQueue();
  643. }
  644. PRIVATE
  645. VOID
  646. CleanupDefaultTimerQueue(
  647. VOID
  648. )
  649. {
  650. g_hDefaultTimerQueue = NULL;
  651. bDefaultQueueInit = FALSE;
  652. bDefaultQueueInitDone = FALSE;
  653. bDefaultQueueInitFailed = FALSE;
  654. }
  655. PRIVATE
  656. VOID
  657. TimerThread(
  658. VOID
  659. )
  660. {
  661. g_dwTimerId = GetCurrentThreadId();
  662. HMODULE hDll = LoadLibrary(g_cszShlwapi);
  663. ASSERT(hDll != NULL);
  664. ASSERT(g_TpsTls != 0xFFFFFFFF);
  665. TlsSetValue(g_TpsTls, (LPVOID)TPS_TIMER_SIGNATURE);
  666. while (!g_bTpsTerminating || (g_ActiveRequests != 0)) {
  667. if (g_TimerQueueList.Wait()) {
  668. if (g_bTpsTerminating && (g_ActiveRequests == 0)) {
  669. break;
  670. }
  671. g_TimerQueueList.ProcessCompletions();
  672. }
  673. }
  674. ASSERT(g_hTimerThread != NULL);
  675. CloseHandle(g_hTimerThread);
  676. g_hTimerThread = NULL;
  677. if (g_dwTimerId == g_dwTerminationThreadId) {
  678. TimerCleanup();
  679. g_bTpsTerminating = FALSE;
  680. g_dwTerminationThreadId = 0;
  681. g_bDeferredTimerTermination = FALSE;
  682. }
  683. g_dwTimerId = 0;
  684. FreeLibraryAndExitThread(hDll, ERROR_SUCCESS);
  685. }
  686. PRIVATE
  687. VOID
  688. DeleteTimerQueue(
  689. IN CTimerQueueDeleteRequest * pRequest
  690. )
  691. {
  692. CTimerQueue * pQueue = (CTimerQueue *)pRequest->GetQueue();
  693. DWORD dwStatus = ERROR_INVALID_PARAMETER;
  694. if (g_TimerQueueList.FindQueue((CDoubleLinkedListEntry *)pQueue) != NULL) {
  695. pQueue->DeleteTimers();
  696. if (pQueue == g_hDefaultTimerQueue) {
  697. CleanupDefaultTimerQueue();
  698. }
  699. delete pQueue;
  700. dwStatus = ERROR_SUCCESS;
  701. }
  702. pRequest->SetCompletionStatus(dwStatus);
  703. }
  704. PRIVATE
  705. VOID
  706. AddTimer(
  707. IN CTimerAddRequest * pRequest
  708. )
  709. {
  710. CTimerQueue * pQueue = pRequest->GetQueue();
  711. //
  712. // add timer object to global list of timer objects, in expiration time
  713. // order
  714. //
  715. pRequest->InsertBack(g_TimerQueueList.TimerListHead());
  716. //
  717. // add timer object to end of timer queue list in no particular order. Only
  718. // used to delete all objects belonging to queue when queue is deleted
  719. //
  720. pRequest->TimerListHead()->InsertTail(pQueue->TimerListHead());
  721. pRequest->SetComplete();
  722. }
  723. PRIVATE
  724. VOID
  725. ChangeTimer(
  726. IN CTimerChangeRequest * pRequest
  727. )
  728. {
  729. CTimerQueue * pQueue = (CTimerQueue *)pRequest->GetQueue();
  730. CTimerQueueEntry * pTimer = pQueue->FindTimer(pRequest->GetTimer());
  731. DWORD dwStatus = ERROR_INVALID_PARAMETER;
  732. if (pTimer != NULL) {
  733. pTimer->SetPeriod(pRequest->GetPeriod());
  734. pTimer->SetExpirationTime(pRequest->GetDueTime());
  735. dwStatus = ERROR_SUCCESS;
  736. }
  737. pRequest->SetCompletionStatus(dwStatus);
  738. }
  739. PRIVATE
  740. VOID
  741. CancelTimer(
  742. IN CTimerCancelRequest * pRequest
  743. )
  744. {
  745. CTimerQueue * pQueue = (CTimerQueue *)pRequest->GetQueue();
  746. CTimerQueueEntry * pTimer = pQueue->FindTimer(pRequest->GetTimer());
  747. DWORD dwStatus = ERROR_INVALID_PARAMETER;
  748. if (pTimer != NULL) {
  749. if (pTimer->IsInUse()) {
  750. pTimer->SetCancelled();
  751. } else {
  752. pTimer->Remove();
  753. delete pTimer;
  754. }
  755. dwStatus = ERROR_SUCCESS;
  756. }
  757. pRequest->SetCompletionStatus(dwStatus);
  758. }
  759. //
  760. // Definitions of forward-declared data.
  761. //
  762. t_CreateTimerQueue _I_CreateTimerQueue = IECreateTimerQueue;
  763. t_DeleteTimerQueue _I_DeleteTimerQueue = IEDeleteTimerQueue;
  764. t_SetTimerQueueTimer _I_SetTimerQueueTimer = IESetTimerQueueTimer;
  765. t_ChangeTimerQueueTimer _I_ChangeTimerQueueTimer = IEChangeTimerQueueTimer;
  766. t_CancelTimerQueueTimer _I_CancelTimerQueueTimer = IECancelTimerQueueTimer;
  767. //
  768. // KERNEL functions that our NT stubs use. Not used if in IE mode.
  769. //
  770. t_CreateTimerQueueTimer _I_CreateTimerQueueTimer = NULL;
  771. t_DeleteTimerQueueTimer _I_DeleteTimerQueueTimer = NULL;