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.

3098 lines
64 KiB

  1. #ifndef __THREAD_CPP
  2. #define __THREAD_CPP
  3. /*++
  4. Copyright (C) 1996-2001 Microsoft Corporation
  5. Module Name:
  6. Thread.cpp
  7. Abstract:
  8. Enhancements to current functionality:
  9. Timeout mechanism should track across waits.
  10. AddRef/Release on task when scheduling.
  11. Enhancement Ticker logic.
  12. History:
  13. --*/
  14. #include <HelperFuncs.h>
  15. /******************************************************************************
  16. *
  17. * Name:
  18. *
  19. *
  20. * Description:
  21. *
  22. *
  23. *****************************************************************************/
  24. template <class WmiKey>
  25. __TYPENAME WmiThread <WmiKey> :: ThreadContainer *WmiThread <WmiKey> :: s_ThreadContainer = NULL ;
  26. template <class WmiKey>
  27. __TYPENAME WmiThread <WmiKey> :: TaskContainer *WmiThread <WmiKey> :: s_TaskContainer = NULL ;
  28. template <class WmiKey>
  29. CriticalSection WmiThread <WmiKey> :: s_CriticalSection(FALSE) ;
  30. template <class WmiKey>
  31. LONG WmiThread <WmiKey> :: s_InitializeReferenceCount = 0 ;
  32. /******************************************************************************
  33. *
  34. * Name:
  35. *
  36. *
  37. * Description:
  38. *
  39. *
  40. *****************************************************************************/
  41. template <class WmiKey>
  42. WmiStatusCode WmiThread <WmiKey> :: Static_Initialize ( WmiAllocator &a_Allocator )
  43. {
  44. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  45. if ( InterlockedIncrement ( & s_InitializeReferenceCount ) == 1 )
  46. {
  47. t_StatusCode = WmiHelper :: InitializeCriticalSection ( & s_CriticalSection ) ;
  48. if ( t_StatusCode == e_StatusCode_Success )
  49. {
  50. if ( s_ThreadContainer == NULL )
  51. {
  52. t_StatusCode = a_Allocator.New (
  53. ( void ** ) & s_ThreadContainer ,
  54. sizeof ( ThreadContainer )
  55. ) ;
  56. if ( t_StatusCode == e_StatusCode_Success )
  57. {
  58. :: new ( ( void * ) s_ThreadContainer ) WmiThread <WmiKey> :: ThreadContainer ( a_Allocator ) ;
  59. }
  60. }
  61. else
  62. {
  63. }
  64. if ( s_TaskContainer == NULL )
  65. {
  66. t_StatusCode = a_Allocator.New (
  67. ( void ** ) & s_TaskContainer ,
  68. sizeof ( TaskContainer )
  69. ) ;
  70. if ( t_StatusCode == e_StatusCode_Success )
  71. {
  72. :: new ( ( void * ) s_TaskContainer ) WmiThread <WmiKey> :: TaskContainer ( a_Allocator ) ;
  73. }
  74. }
  75. else
  76. {
  77. }
  78. }
  79. }
  80. return t_StatusCode ;
  81. }
  82. /******************************************************************************
  83. *
  84. * Name:
  85. *
  86. *
  87. * Description:
  88. *
  89. *
  90. *****************************************************************************/
  91. template <class WmiKey>
  92. WmiStatusCode WmiThread <WmiKey> :: Static_UnInitialize ( WmiAllocator &a_Allocator )
  93. {
  94. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  95. if ( InterlockedDecrement ( & s_InitializeReferenceCount ) == 0 )
  96. {
  97. if ( s_ThreadContainer )
  98. {
  99. s_ThreadContainer->~WmiBasicTree () ;
  100. t_StatusCode = a_Allocator.Delete (
  101. ( void * ) s_ThreadContainer
  102. ) ;
  103. s_ThreadContainer = NULL ;
  104. }
  105. if ( s_TaskContainer )
  106. {
  107. s_TaskContainer->~WmiBasicTree () ;
  108. t_StatusCode = a_Allocator.Delete (
  109. ( void * ) s_TaskContainer
  110. ) ;
  111. s_TaskContainer = NULL ;
  112. }
  113. WmiHelper :: DeleteCriticalSection ( & s_CriticalSection );
  114. }
  115. return t_StatusCode ;
  116. }
  117. /******************************************************************************
  118. *
  119. * Name:
  120. *
  121. *
  122. * Description:
  123. *
  124. *
  125. *****************************************************************************/
  126. template <class WmiKey>
  127. ULONG WmiTask <WmiKey> :: AddRef ()
  128. {
  129. return InterlockedIncrement ( & m_ReferenceCount ) ;
  130. }
  131. /******************************************************************************
  132. *
  133. * Name:
  134. *
  135. *
  136. * Description:
  137. *
  138. *
  139. *****************************************************************************/
  140. template <class WmiKey>
  141. ULONG WmiTask <WmiKey> :: Release ()
  142. {
  143. ULONG t_ReferenceCount = InterlockedDecrement ( & m_ReferenceCount ) ;
  144. if ( t_ReferenceCount == 0 )
  145. {
  146. delete this ;
  147. }
  148. return t_ReferenceCount ;
  149. }
  150. /******************************************************************************
  151. *
  152. * Name:
  153. *
  154. *
  155. * Description:
  156. *
  157. *
  158. *****************************************************************************/
  159. template <class WmiKey>
  160. WmiTask <WmiKey> :: WmiTask (
  161. WmiAllocator &a_Allocator ,
  162. const wchar_t *a_Name ,
  163. const wchar_t *a_CompletionName
  164. ) : m_Allocator ( a_Allocator ) ,
  165. m_ReferenceCount ( 0 ) ,
  166. m_Event ( NULL ) ,
  167. m_CompletionEvent ( NULL ) ,
  168. m_Name ( NULL ) ,
  169. m_CompletionName ( NULL ) ,
  170. m_InitializationStatusCode ( e_StatusCode_Success ) ,
  171. m_TaskState ( e_WmiTask_UnInitialized )
  172. {
  173. if ( a_Name )
  174. {
  175. m_InitializationStatusCode = WmiHelper :: DuplicateString ( m_Allocator , a_Name , m_Name ) ;
  176. }
  177. if ( m_InitializationStatusCode == e_StatusCode_Success )
  178. {
  179. if ( a_CompletionName )
  180. {
  181. m_InitializationStatusCode = WmiHelper :: DuplicateString ( m_Allocator , a_CompletionName , m_CompletionName ) ;
  182. }
  183. }
  184. if ( m_InitializationStatusCode == e_StatusCode_Success )
  185. {
  186. m_InitializationStatusCode = WmiHelper :: CreateNamedEvent ( m_Name , m_Event ) ;
  187. }
  188. if ( m_InitializationStatusCode == e_StatusCode_Success )
  189. {
  190. m_InitializationStatusCode = WmiHelper :: CreateNamedEvent ( m_CompletionName , m_CompletionEvent ) ;
  191. }
  192. }
  193. /******************************************************************************
  194. *
  195. * Name:
  196. *
  197. *
  198. * Description:
  199. *
  200. *
  201. *****************************************************************************/
  202. template <class WmiKey>
  203. WmiTask <WmiKey> :: WmiTask (
  204. WmiAllocator &a_Allocator ,
  205. HANDLE a_Event ,
  206. HANDLE a_CompletionEvent ,
  207. const wchar_t *a_Name ,
  208. const wchar_t *a_CompletionName
  209. ) : m_Allocator ( a_Allocator ) ,
  210. m_ReferenceCount ( 0 ) ,
  211. m_Event ( NULL ) ,
  212. m_CompletionEvent ( NULL ) ,
  213. m_Name ( NULL ) ,
  214. m_CompletionName ( NULL ) ,
  215. m_InitializationStatusCode ( e_StatusCode_Success ) ,
  216. m_TaskState ( e_WmiTask_UnInitialized )
  217. {
  218. if ( a_Name )
  219. {
  220. m_InitializationStatusCode = WmiHelper :: DuplicateString ( m_Allocator , a_Name , m_Name ) ;
  221. }
  222. if ( m_InitializationStatusCode == e_StatusCode_Success )
  223. {
  224. if ( a_CompletionName )
  225. {
  226. m_InitializationStatusCode = WmiHelper :: DuplicateString ( m_Allocator , a_CompletionName , m_CompletionName ) ;
  227. }
  228. }
  229. if ( m_InitializationStatusCode == e_StatusCode_Success )
  230. {
  231. if ( a_Event )
  232. {
  233. m_InitializationStatusCode = WmiHelper :: DuplicateHandle ( a_Event , m_Event ) ;
  234. }
  235. }
  236. if ( m_InitializationStatusCode == e_StatusCode_Success )
  237. {
  238. if ( a_CompletionEvent )
  239. {
  240. m_InitializationStatusCode = WmiHelper :: DuplicateHandle ( a_CompletionEvent , m_CompletionEvent ) ;
  241. }
  242. }
  243. }
  244. /******************************************************************************
  245. *
  246. * Name:
  247. *
  248. *
  249. * Description:
  250. *
  251. *
  252. *****************************************************************************/
  253. template <class WmiKey>
  254. WmiTask <WmiKey> :: ~WmiTask ()
  255. {
  256. if ( m_Name )
  257. {
  258. m_Allocator.Delete ( ( void * ) m_Name ) ;
  259. }
  260. if ( m_CompletionName )
  261. {
  262. m_Allocator.Delete ( ( void * ) m_CompletionName ) ;
  263. }
  264. if ( m_Event )
  265. {
  266. CloseHandle ( m_Event ) ;
  267. }
  268. if ( m_CompletionEvent )
  269. {
  270. CloseHandle ( m_CompletionEvent ) ;
  271. }
  272. }
  273. /******************************************************************************
  274. *
  275. * Name:
  276. *
  277. *
  278. * Description:
  279. *
  280. *
  281. *****************************************************************************/
  282. template <class WmiKey>
  283. WmiStatusCode WmiTask <WmiKey> :: Initialize ()
  284. {
  285. m_TaskState = e_WmiTask_Initialized ;
  286. return m_InitializationStatusCode ;
  287. }
  288. /******************************************************************************
  289. *
  290. * Name:
  291. *
  292. *
  293. * Description:
  294. *
  295. *
  296. *****************************************************************************/
  297. template <class WmiKey>
  298. WmiStatusCode WmiTask <WmiKey> :: UnInitialize ()
  299. {
  300. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  301. return t_StatusCode ;
  302. }
  303. /******************************************************************************
  304. *
  305. * Name:
  306. *
  307. *
  308. * Description:
  309. *
  310. *
  311. *****************************************************************************/
  312. template <class WmiKey>
  313. WmiStatusCode WmiTask <WmiKey> :: Process ( WmiThread <WmiKey> &a_Thread )
  314. {
  315. if ( m_InitializationStatusCode == e_StatusCode_Success )
  316. {
  317. return Complete () ;
  318. }
  319. return e_StatusCode_NotInitialized ;
  320. }
  321. /******************************************************************************
  322. *
  323. * Name:
  324. *
  325. *
  326. * Description:
  327. *
  328. *
  329. *****************************************************************************/
  330. template <class WmiKey>
  331. WmiStatusCode WmiTask <WmiKey> :: Exec ()
  332. {
  333. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  334. if ( m_InitializationStatusCode == e_StatusCode_Success )
  335. {
  336. if ( m_Event )
  337. {
  338. BOOL t_Status = SetEvent ( m_Event ) ;
  339. if ( ! t_Status )
  340. {
  341. t_StatusCode = e_StatusCode_Unknown ;
  342. }
  343. }
  344. }
  345. else
  346. {
  347. t_StatusCode = e_StatusCode_NotInitialized ;
  348. }
  349. return t_StatusCode ;
  350. }
  351. /******************************************************************************
  352. *
  353. * Name:
  354. *
  355. *
  356. * Description:
  357. *
  358. *
  359. *****************************************************************************/
  360. template <class WmiKey>
  361. WmiStatusCode WmiTask <WmiKey> :: Complete ()
  362. {
  363. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  364. if ( m_InitializationStatusCode == e_StatusCode_Success )
  365. {
  366. BOOL t_Status = SetEvent ( m_CompletionEvent ) ;
  367. if ( ! t_Status )
  368. {
  369. t_StatusCode = e_StatusCode_Unknown ;
  370. }
  371. }
  372. else
  373. {
  374. t_StatusCode = e_StatusCode_NotInitialized ;
  375. }
  376. return t_StatusCode ;
  377. }
  378. /******************************************************************************
  379. *
  380. * Name:
  381. *
  382. *
  383. * Description:
  384. *
  385. *
  386. *****************************************************************************/
  387. template <class WmiKey>
  388. WmiStatusCode WmiTask <WmiKey> :: Wait ( const ULONG &a_Timeout )
  389. {
  390. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  391. if ( m_InitializationStatusCode == e_StatusCode_Success )
  392. {
  393. t_StatusCode = WmiThread <WmiKey> :: Static_Dispatch (
  394. *this ,
  395. a_Timeout
  396. ) ;
  397. }
  398. else
  399. {
  400. t_StatusCode = e_StatusCode_NotInitialized ;
  401. }
  402. return t_StatusCode ;
  403. }
  404. /******************************************************************************
  405. *
  406. * Name:
  407. *
  408. *
  409. * Description:
  410. *
  411. *
  412. *****************************************************************************/
  413. // call static GetEvents on WmiThread to determine list of tasks to execute.
  414. template <class WmiKey>
  415. WmiStatusCode WmiTask <WmiKey> :: WaitAlertable ( const ULONG &a_Timeout )
  416. {
  417. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  418. if ( m_InitializationStatusCode == e_StatusCode_Success )
  419. {
  420. t_StatusCode = WmiThread <WmiKey> :: Static_AlertableDispatch (
  421. *this ,
  422. a_Timeout
  423. ) ;
  424. }
  425. else
  426. {
  427. t_StatusCode = e_StatusCode_NotInitialized ;
  428. }
  429. return t_StatusCode ;
  430. }
  431. /******************************************************************************
  432. *
  433. * Name:
  434. *
  435. *
  436. * Description:
  437. *
  438. *
  439. *****************************************************************************/
  440. template <class WmiKey>
  441. WmiStatusCode WmiTask <WmiKey> :: WaitInterruptable ( const ULONG &a_Timeout )
  442. {
  443. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  444. if ( m_InitializationStatusCode == e_StatusCode_Success )
  445. {
  446. t_StatusCode = WmiThread <WmiKey> :: Static_InterruptableDispatch (
  447. *this ,
  448. a_Timeout
  449. ) ;
  450. }
  451. else
  452. {
  453. t_StatusCode = e_StatusCode_NotInitialized ;
  454. }
  455. return t_StatusCode ;
  456. }
  457. #if 0
  458. "WmiKey" below is non-deducible because the actual supplied
  459. is a nested type [ISO 14.8.2.4 para 4]. I'm moving these operator
  460. functions to class WmiThread<WmiKey>::QueueKey itself.
  461. [TGani]
  462. /******************************************************************************
  463. *
  464. * Name:
  465. *
  466. *
  467. * Description:
  468. *
  469. *
  470. *****************************************************************************/
  471. template <class WmiKey>
  472. bool operator == ( const typename WmiThread <WmiKey> :: QueueKey &a_Arg1 , const typename WmiThread <WmiKey> :: QueueKey &a_Arg2 )
  473. {
  474. LONG t_Compare ;
  475. if ( ( t_Compare = CompareElement ( a_Arg1.m_Key , a_Arg2.m_Key ) ) == 0 )
  476. {
  477. t_Compare = CompareElement ( a_Arg1.m_Tick , a_Arg2.m_Tick ) ;
  478. }
  479. return t_Compare == 0 ? true : false ;
  480. }
  481. template <class WmiKey>
  482. bool operator < ( const typename WmiThread <WmiKey> :: QueueKey &a_Arg1 , const typename WmiThread <WmiKey> :: QueueKey &a_Arg2 )
  483. {
  484. LONG t_Compare ;
  485. if ( ( t_Compare = CompareElement ( a_Arg1.m_Key , a_Arg2.m_Key ) ) == 0 )
  486. {
  487. t_Compare = CompareElement ( a_Arg1.m_Tick , a_Arg2.m_Tick ) ;
  488. }
  489. return t_Compare < 0 ? true : false ;
  490. }
  491. #endif //0
  492. /******************************************************************************
  493. *
  494. * Name:
  495. *
  496. *
  497. * Description:
  498. *
  499. *
  500. *****************************************************************************/
  501. template <class WmiKey>
  502. WmiStatusCode WmiThread <WmiKey> :: PostShutdown ()
  503. {
  504. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  505. SetEvent ( m_Terminate ) ;
  506. return t_StatusCode ;
  507. }
  508. /******************************************************************************
  509. *
  510. * Name:
  511. *
  512. *
  513. * Description:
  514. *
  515. *
  516. *****************************************************************************/
  517. template <class WmiKey>
  518. ULONG WmiThread <WmiKey> :: ThreadProc ( void *a_Thread )
  519. {
  520. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  521. WmiThread *t_Thread = ( WmiThread * ) a_Thread ;
  522. if ( t_Thread )
  523. {
  524. t_StatusCode = t_Thread->Initialize_Callback () ;
  525. if ( t_StatusCode == e_StatusCode_Success )
  526. {
  527. SetEvent ( t_Thread->m_Initialized ) ;
  528. t_StatusCode = t_Thread->ThreadDispatch () ;
  529. }
  530. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  531. t_StatusCode = t_Thread->UnInitialize_Callback () ;
  532. t_Thread->InternalRelease () ;
  533. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  534. }
  535. return ( ULONG ) t_StatusCode ;
  536. }
  537. /******************************************************************************
  538. *
  539. * Name:
  540. *
  541. *
  542. * Description:
  543. *
  544. *
  545. *****************************************************************************/
  546. template <class WmiKey>
  547. ULONG WmiThread <WmiKey> :: AddRef ()
  548. {
  549. ULONG t_ReferenceCount = InterlockedIncrement ( & m_ReferenceCount ) ;
  550. if ( t_ReferenceCount == 1 )
  551. {
  552. InternalAddRef () ;
  553. }
  554. return t_ReferenceCount ;
  555. }
  556. /******************************************************************************
  557. *
  558. * Name:
  559. *
  560. *
  561. * Description:
  562. *
  563. *
  564. *****************************************************************************/
  565. template <class WmiKey>
  566. ULONG WmiThread <WmiKey> :: Release ()
  567. {
  568. ULONG t_ReferenceCount = InterlockedDecrement ( & m_ReferenceCount ) ;
  569. if ( t_ReferenceCount == 0 )
  570. {
  571. CallBackRelease () ;
  572. PostShutdown () ;
  573. return InternalRelease () ;
  574. }
  575. else
  576. {
  577. return t_ReferenceCount ;
  578. }
  579. }
  580. /******************************************************************************
  581. *
  582. * Name:
  583. *
  584. *
  585. * Description:
  586. *
  587. *
  588. *****************************************************************************/
  589. template <class WmiKey>
  590. ULONG WmiThread <WmiKey> :: InternalAddRef ()
  591. {
  592. return InterlockedIncrement ( & m_InternalReferenceCount ) ;
  593. }
  594. /******************************************************************************
  595. *
  596. * Name:
  597. *
  598. *
  599. * Description:
  600. *
  601. *
  602. *****************************************************************************/
  603. template <class WmiKey>
  604. ULONG WmiThread <WmiKey> :: InternalRelease ()
  605. {
  606. ULONG t_ReferenceCount = InterlockedDecrement ( & m_InternalReferenceCount ) ;
  607. if ( t_ReferenceCount == 0 )
  608. {
  609. WmiStatusCode t_StatusCode = s_ThreadContainer->Delete ( m_Identifier ) ;
  610. delete this ;
  611. return 0 ;
  612. }
  613. else
  614. {
  615. return t_ReferenceCount ;
  616. }
  617. }
  618. /******************************************************************************
  619. *
  620. * Name:
  621. *
  622. *
  623. * Description:
  624. *
  625. *
  626. *****************************************************************************/
  627. template <class WmiKey>
  628. WmiStatusCode WmiThread <WmiKey> :: CreateThread ()
  629. {
  630. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  631. InternalAddRef () ;
  632. m_Thread = :: CreateThread (
  633. NULL ,
  634. m_StackSize ,
  635. ( LPTHREAD_START_ROUTINE ) ThreadProc ,
  636. ( void * ) this ,
  637. 0 ,
  638. & m_Identifier
  639. ) ;
  640. if ( m_Thread )
  641. {
  642. ThreadContainerIterator t_Iterator ;
  643. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  644. if ( ( t_StatusCode = s_ThreadContainer->Insert ( m_Identifier , this , t_Iterator ) ) == e_StatusCode_Success )
  645. {
  646. }
  647. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  648. }
  649. else
  650. {
  651. InternalRelease () ;
  652. t_StatusCode = e_StatusCode_OutOfResources ;
  653. }
  654. return t_StatusCode ;
  655. }
  656. /******************************************************************************
  657. *
  658. * Name:
  659. *
  660. *
  661. * Description:
  662. *
  663. *
  664. *****************************************************************************/
  665. template <class WmiKey>
  666. WmiThread <WmiKey> :: WmiThread (
  667. WmiAllocator &a_Allocator ,
  668. const wchar_t *a_Name ,
  669. ULONG a_Timeout ,
  670. DWORD a_StackSize
  671. ) : m_Allocator ( a_Allocator ) ,
  672. m_TaskQueue ( a_Allocator ) ,
  673. m_AlertableTaskQueue ( a_Allocator ) ,
  674. m_InterruptableTaskQueue ( a_Allocator ) ,
  675. m_Thread ( NULL ) ,
  676. m_Initialized ( NULL ) ,
  677. m_Terminate ( NULL ) ,
  678. m_QueueChange ( NULL ) ,
  679. m_Identifier ( 0 ) ,
  680. m_Name ( NULL ) ,
  681. m_Timeout ( a_Timeout ) ,
  682. m_StackSize ( a_StackSize ) ,
  683. m_ReferenceCount ( 0 ) ,
  684. m_InternalReferenceCount ( 0 ) ,
  685. m_InitializationStatusCode ( e_StatusCode_Success ),
  686. m_CriticalSection(NOTHROW_LOCK)
  687. {
  688. m_InitializationStatusCode = WmiHelper :: InitializeCriticalSection ( & m_CriticalSection ) ;
  689. if ( m_InitializationStatusCode == e_StatusCode_Success )
  690. {
  691. m_InitializationStatusCode = m_TaskQueue.Initialize () ;
  692. }
  693. if ( m_InitializationStatusCode == e_StatusCode_Success )
  694. {
  695. m_InitializationStatusCode = m_InterruptableTaskQueue.Initialize () ;
  696. }
  697. if ( m_InitializationStatusCode == e_StatusCode_Success )
  698. {
  699. m_InitializationStatusCode = m_AlertableTaskQueue.Initialize () ;
  700. }
  701. if ( a_Name )
  702. {
  703. m_InitializationStatusCode = WmiHelper :: DuplicateString ( m_Allocator , a_Name , m_Name ) ;
  704. }
  705. if ( m_InitializationStatusCode == e_StatusCode_Success )
  706. {
  707. m_InitializationStatusCode = WmiHelper :: CreateUnNamedEvent ( m_Terminate ) ;
  708. }
  709. if ( m_InitializationStatusCode == e_StatusCode_Success )
  710. {
  711. m_InitializationStatusCode = WmiHelper :: CreateUnNamedEvent ( m_Initialized ) ;
  712. }
  713. if ( m_InitializationStatusCode == e_StatusCode_Success )
  714. {
  715. m_InitializationStatusCode = WmiHelper :: CreateUnNamedEvent ( m_QueueChange ) ;
  716. }
  717. }
  718. /******************************************************************************
  719. *
  720. * Name:
  721. *
  722. *
  723. * Description:
  724. *
  725. *
  726. *****************************************************************************/
  727. template <class WmiKey>
  728. WmiThread <WmiKey> :: ~WmiThread ()
  729. {
  730. if ( m_Name )
  731. {
  732. m_Allocator.Delete ( ( void * ) m_Name ) ;
  733. }
  734. if ( m_Initialized )
  735. {
  736. CloseHandle ( m_Initialized ) ;
  737. }
  738. if ( m_Terminate )
  739. {
  740. CloseHandle ( m_Terminate ) ;
  741. }
  742. if ( m_QueueChange )
  743. {
  744. CloseHandle ( m_QueueChange ) ;
  745. }
  746. if ( m_Thread )
  747. {
  748. CloseHandle ( m_Thread ) ;
  749. }
  750. WmiHelper :: DeleteCriticalSection ( & m_CriticalSection ) ;
  751. }
  752. /******************************************************************************
  753. *
  754. * Name:
  755. *
  756. *
  757. * Description:
  758. *
  759. *
  760. *****************************************************************************/
  761. template <class WmiKey>
  762. WmiStatusCode WmiThread <WmiKey> :: Initialize ( const ULONG &a_Timeout )
  763. {
  764. if ( m_InitializationStatusCode == e_StatusCode_Success )
  765. {
  766. m_InitializationStatusCode = CreateThread () ;
  767. }
  768. if ( m_InitializationStatusCode == e_StatusCode_Success )
  769. {
  770. ULONG t_Status = WaitForSingleObject ( m_Initialized , a_Timeout ) ;
  771. switch ( t_Status )
  772. {
  773. case WAIT_TIMEOUT:
  774. {
  775. m_InitializationStatusCode = e_StatusCode_Success_Timeout ;
  776. }
  777. break ;
  778. case WAIT_OBJECT_0:
  779. {
  780. m_InitializationStatusCode = e_StatusCode_Success ;
  781. }
  782. break ;
  783. default :
  784. {
  785. m_InitializationStatusCode = e_StatusCode_Unknown ;
  786. }
  787. break ;
  788. }
  789. }
  790. return m_InitializationStatusCode ;
  791. }
  792. /******************************************************************************
  793. *
  794. * Name:
  795. *
  796. *
  797. * Description:
  798. *
  799. *
  800. *****************************************************************************/
  801. template <class WmiKey>
  802. WmiStatusCode WmiThread <WmiKey> :: UnInitialize ()
  803. {
  804. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  805. t_StatusCode = m_TaskQueue.UnInitialize () ;
  806. if ( t_StatusCode == e_StatusCode_Success )
  807. {
  808. t_StatusCode = m_InterruptableTaskQueue.UnInitialize () ;
  809. }
  810. if ( t_StatusCode == e_StatusCode_Success )
  811. {
  812. t_StatusCode = m_AlertableTaskQueue.UnInitialize () ;
  813. }
  814. return t_StatusCode ;
  815. }
  816. /******************************************************************************
  817. *
  818. * Name:
  819. *
  820. *
  821. * Description:
  822. *
  823. *
  824. *****************************************************************************/
  825. template <class WmiKey>
  826. WmiStatusCode WmiThread <WmiKey> :: TimedOut ()
  827. {
  828. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  829. return t_StatusCode ;
  830. }
  831. /******************************************************************************
  832. *
  833. * Name:
  834. *
  835. *
  836. * Description:
  837. *
  838. *
  839. *****************************************************************************/
  840. // Queue a task to be executed immediately, a thread that calls a task procedure that
  841. // executes a Wait or MsgWait will receive an indication in Queue status will not execute
  842. // newly queued tasks.
  843. template <class WmiKey>
  844. WmiStatusCode WmiThread <WmiKey> :: EnQueue (
  845. const WmiKey &a_Key ,
  846. WmiTask <WmiKey> &a_Task
  847. )
  848. {
  849. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  850. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  851. TaskContainerIterator t_Iterator ;
  852. if ( ( t_StatusCode = s_TaskContainer->Insert ( &a_Task , this , t_Iterator ) ) == e_StatusCode_Success )
  853. {
  854. a_Task.SetTaskState ( WmiTask < WmiKey > :: e_WmiTask_EnQueued ) ;
  855. a_Task.AddRef () ;
  856. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  857. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  858. QueueKey t_QueueKey ( m_Key++ , a_Key ) ;
  859. t_StatusCode = m_TaskQueue.EnQueue ( t_QueueKey , & a_Task ) ;
  860. if ( t_StatusCode == e_StatusCode_Success )
  861. {
  862. a_Task.EnqueueAs ( WmiTask <WmiKey> :: e_WmiTask_Enqueue ) ;
  863. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  864. BOOL t_Status = SetEvent ( m_QueueChange ) ;
  865. if ( ! t_Status )
  866. {
  867. t_StatusCode = e_StatusCode_Failed ;
  868. }
  869. }
  870. else
  871. {
  872. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  873. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  874. t_StatusCode = s_TaskContainer->Delete ( &a_Task ) ;
  875. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  876. a_Task.Release () ;
  877. }
  878. }
  879. else
  880. {
  881. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  882. }
  883. return t_StatusCode ;
  884. }
  885. /******************************************************************************
  886. *
  887. * Name:
  888. *
  889. *
  890. * Description:
  891. *
  892. *
  893. *****************************************************************************/
  894. template <class WmiKey>
  895. WmiStatusCode WmiThread <WmiKey> :: EnQueueAlertable (
  896. const WmiKey &a_Key ,
  897. WmiTask <WmiKey> &a_Task
  898. )
  899. {
  900. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  901. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  902. TaskContainerIterator t_Iterator ;
  903. if ( ( t_StatusCode = s_TaskContainer->Insert ( &a_Task , this , t_Iterator ) ) == e_StatusCode_Success )
  904. {
  905. a_Task.SetTaskState ( WmiTask < WmiKey > :: e_WmiTask_EnQueued ) ;
  906. a_Task.AddRef () ;
  907. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  908. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  909. QueueKey t_QueueKey ( m_Key++ , a_Key ) ;
  910. t_StatusCode = m_AlertableTaskQueue.EnQueue ( t_QueueKey , & a_Task ) ;
  911. if ( t_StatusCode == e_StatusCode_Success )
  912. {
  913. a_Task.EnqueueAs ( WmiTask <WmiKey> :: e_WmiTask_EnqueueAlertable ) ;
  914. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  915. BOOL t_Status = SetEvent ( m_QueueChange ) ;
  916. if ( ! t_Status )
  917. {
  918. t_StatusCode = e_StatusCode_Failed ;
  919. }
  920. }
  921. else
  922. {
  923. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  924. WmiHelper :: EnterCriticalSection ( & s_CriticalSection , TRUE ) ;
  925. t_StatusCode = s_TaskContainer->Delete ( &a_Task ) ;
  926. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  927. a_Task.Release () ;
  928. }
  929. }
  930. else
  931. {
  932. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  933. }
  934. return t_StatusCode ;
  935. }
  936. /******************************************************************************
  937. *
  938. * Name:
  939. *
  940. *
  941. * Description:
  942. *
  943. *
  944. *****************************************************************************/
  945. // Queue a task to be executed immediately, a thread that calls a task procedure that
  946. // executes a Wait or MsgWait will receive an indication of Queue status change will execute
  947. // newly queued tasks. This is used for STA based execution where we need to interrupt the wait
  948. // to execute a dependant request.
  949. //
  950. template <class WmiKey>
  951. WmiStatusCode WmiThread <WmiKey> :: EnQueueInterruptable (
  952. const WmiKey &a_Key ,
  953. WmiTask <WmiKey> &a_Task
  954. )
  955. {
  956. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  957. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  958. TaskContainerIterator t_Iterator ;
  959. if ( ( t_StatusCode = s_TaskContainer->Insert ( &a_Task , this , t_Iterator ) ) == e_StatusCode_Success )
  960. {
  961. a_Task.SetTaskState ( WmiTask < WmiKey > :: e_WmiTask_EnQueued ) ;
  962. a_Task.AddRef () ;
  963. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  964. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  965. QueueKey t_QueueKey ( m_Key++ , a_Key ) ;
  966. t_StatusCode = m_InterruptableTaskQueue.EnQueue ( t_QueueKey , & a_Task ) ;
  967. if ( t_StatusCode == e_StatusCode_Success )
  968. {
  969. a_Task.EnqueueAs ( WmiTask <WmiKey> :: e_WmiTask_EnqueueInterruptable ) ;
  970. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  971. BOOL t_Status = SetEvent ( m_QueueChange ) ;
  972. if ( ! t_Status )
  973. {
  974. t_StatusCode = e_StatusCode_Failed ;
  975. }
  976. }
  977. else
  978. {
  979. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  980. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  981. t_StatusCode = s_TaskContainer->Delete ( &a_Task ) ;
  982. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  983. a_Task.Release () ;
  984. }
  985. }
  986. else
  987. {
  988. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  989. }
  990. return t_StatusCode ;
  991. }
  992. /******************************************************************************
  993. *
  994. * Name:
  995. *
  996. *
  997. * Description:
  998. *
  999. *
  1000. *****************************************************************************/
  1001. template <class WmiKey>
  1002. WmiStatusCode WmiThread <WmiKey> :: DeQueue (
  1003. const WmiKey &a_Key ,
  1004. WmiTask <WmiKey> &a_Task
  1005. )
  1006. {
  1007. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1008. a_Task.SetTaskState ( WmiTask < WmiKey > :: e_WmiTask_DeQueued ) ;
  1009. return t_StatusCode ;
  1010. }
  1011. /******************************************************************************
  1012. *
  1013. * Name:
  1014. *
  1015. *
  1016. * Description:
  1017. *
  1018. *
  1019. *****************************************************************************/
  1020. template <class WmiKey>
  1021. WmiStatusCode WmiThread <WmiKey> :: DeQueueAlertable (
  1022. const WmiKey &a_Key ,
  1023. WmiTask <WmiKey> &a_Task
  1024. )
  1025. {
  1026. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1027. a_Task.SetTaskState ( WmiTask < WmiKey > :: e_WmiTask_DeQueued ) ;
  1028. return t_StatusCode ;
  1029. }
  1030. /******************************************************************************
  1031. *
  1032. * Name:
  1033. *
  1034. *
  1035. * Description:
  1036. *
  1037. *
  1038. *****************************************************************************/
  1039. template <class WmiKey>
  1040. WmiStatusCode WmiThread <WmiKey> :: DeQueueInterruptable (
  1041. const WmiKey &a_Key ,
  1042. WmiTask <WmiKey> &a_Task
  1043. )
  1044. {
  1045. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1046. a_Task.SetTaskState ( WmiTask < WmiKey > :: e_WmiTask_DeQueued ) ;
  1047. return t_StatusCode ;
  1048. }
  1049. /******************************************************************************
  1050. *
  1051. * Name:
  1052. *
  1053. *
  1054. * Description:
  1055. *
  1056. *
  1057. *****************************************************************************/
  1058. template <class WmiKey>
  1059. WmiThread <WmiKey> *WmiThread <WmiKey> :: GetThread ()
  1060. {
  1061. WmiThread *t_Thread = NULL ;
  1062. ULONG t_CurrentThreadId = GetCurrentThreadId () ;
  1063. ThreadContainerIterator t_Iterator ;
  1064. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  1065. WmiStatusCode t_StatusCode = s_ThreadContainer->Find ( t_CurrentThreadId , t_Iterator ) ;
  1066. if ( t_StatusCode == e_StatusCode_Success )
  1067. {
  1068. t_Thread = t_Iterator.GetElement () ;
  1069. }
  1070. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  1071. return t_Thread ;
  1072. }
  1073. /******************************************************************************
  1074. *
  1075. * Name:
  1076. *
  1077. *
  1078. * Description:
  1079. *
  1080. *
  1081. *****************************************************************************/
  1082. template <class WmiKey>
  1083. WmiThread <WmiKey> *WmiThread <WmiKey> :: GetServicingThread ( WmiTask <WmiKey> &a_Task )
  1084. {
  1085. WmiThread *t_Thread = NULL ;
  1086. TaskContainerIterator t_Iterator ;
  1087. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  1088. WmiStatusCode t_StatusCode = s_TaskContainer->Find ( &a_Task, t_Iterator ) ;
  1089. if ( t_StatusCode == e_StatusCode_Success )
  1090. {
  1091. t_Thread = t_Iterator.GetElement () ;
  1092. }
  1093. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  1094. return t_Thread ;
  1095. }
  1096. /*
  1097. Scheduling Action
  1098. Task None
  1099. Dispatch nothing
  1100. On Thread
  1101. Wait on Completion
  1102. Wait on Thread Termination
  1103. Wait on Servicing Thread Termination
  1104. Off Thread
  1105. Wait on Completion
  1106. Wait on Servicing Thread Termination
  1107. Task Altertable
  1108. Dispatch Alertable Queue
  1109. On Thread
  1110. MsgWait on Completion
  1111. MsgWait on Thread Termination
  1112. MsgWait on Servicing Thread Termination
  1113. Off Thread
  1114. MsgWait on Completion
  1115. MsgWait on Servicing Thread Termination
  1116. Task Interruptable
  1117. Dispatch Alertable Queue
  1118. Dispatch Normal Queue
  1119. On Thread
  1120. MsgWait on Completion
  1121. MsgWait on Thread Termination
  1122. MsgWait on Servicing Thread Termination
  1123. MsgWait on Alertables
  1124. Off Thread
  1125. MsgWait on Completion
  1126. MsgWait on Servicing Thread Termination
  1127. Thread Alertable
  1128. Dispatch Alertable Queue
  1129. Dispatch Normal Queue
  1130. MsgWait on Thread Termination
  1131. MsgWait on Alertables
  1132. */
  1133. /******************************************************************************
  1134. *
  1135. * Name:
  1136. *
  1137. *
  1138. * Description:
  1139. *
  1140. *
  1141. *****************************************************************************/
  1142. template <class WmiKey>
  1143. WmiStatusCode WmiThread <WmiKey> :: Static_Dispatch (
  1144. WmiTask <WmiKey> &a_Task ,
  1145. WmiThread <WmiKey> &a_Thread ,
  1146. const ULONG &a_Timeout
  1147. )
  1148. {
  1149. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1150. HANDLE t_Handles [ 3 ] ;
  1151. t_Handles [ 0 ] = a_Task.GetCompletionEvent () ;
  1152. t_Handles [ 1 ] = a_Thread.GetHandle () ;
  1153. t_Handles [ 2 ] = a_Thread.GetTerminationEvent () ;
  1154. ULONG t_Event = WaitForMultipleObjects (
  1155. 3 ,
  1156. t_Handles ,
  1157. FALSE ,
  1158. a_Timeout
  1159. ) ;
  1160. switch ( t_Event )
  1161. {
  1162. case WAIT_TIMEOUT:
  1163. {
  1164. t_StatusCode = e_StatusCode_Success_Timeout ;
  1165. }
  1166. break ;
  1167. case WAIT_OBJECT_0:
  1168. {
  1169. t_StatusCode = e_StatusCode_Success ;
  1170. }
  1171. break ;
  1172. case WAIT_OBJECT_0+1:
  1173. case WAIT_OBJECT_0+2:
  1174. {
  1175. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  1176. #if DBG
  1177. DebugBreak();
  1178. #endif
  1179. }
  1180. break ;
  1181. case WAIT_FAILED:
  1182. {
  1183. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1184. {
  1185. t_StatusCode = e_StatusCode_OutOfMemory;
  1186. break;
  1187. }
  1188. }
  1189. default:
  1190. {
  1191. t_StatusCode = e_StatusCode_Unknown ;
  1192. #if DBG
  1193. DebugBreak();
  1194. #endif
  1195. }
  1196. break ;
  1197. }
  1198. return t_StatusCode ;
  1199. }
  1200. /******************************************************************************
  1201. *
  1202. * Name:
  1203. *
  1204. *
  1205. * Description:
  1206. *
  1207. *
  1208. *****************************************************************************/
  1209. template <class WmiKey>
  1210. WmiStatusCode WmiThread <WmiKey> :: Static_Dispatch (
  1211. WmiTask <WmiKey> &a_Task ,
  1212. const ULONG &a_Timeout
  1213. )
  1214. {
  1215. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1216. WmiThread *t_Thread = GetThread () ;
  1217. if ( t_Thread )
  1218. {
  1219. t_StatusCode = t_Thread->Dispatch ( a_Task , a_Timeout ) ;
  1220. }
  1221. else
  1222. {
  1223. WmiThread *t_ServicingThread = GetServicingThread ( a_Task ) ;
  1224. if ( t_ServicingThread )
  1225. {
  1226. t_StatusCode = Static_Dispatch ( a_Task , *t_ServicingThread , a_Timeout ) ;
  1227. }
  1228. else
  1229. {
  1230. t_StatusCode = e_StatusCode_Success ;
  1231. }
  1232. }
  1233. return t_StatusCode ;
  1234. }
  1235. /******************************************************************************
  1236. *
  1237. * Name:
  1238. *
  1239. *
  1240. * Description:
  1241. *
  1242. *
  1243. *****************************************************************************/
  1244. template <class WmiKey>
  1245. WmiStatusCode WmiThread <WmiKey> :: Dispatch (
  1246. WmiTask <WmiKey> &a_Task ,
  1247. const ULONG &a_Timeout
  1248. )
  1249. {
  1250. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1251. do
  1252. {
  1253. }
  1254. while ( ( t_StatusCode = Wait ( a_Task , a_Timeout ) ) == e_StatusCode_Success ) ;
  1255. return t_StatusCode ;
  1256. }
  1257. /******************************************************************************
  1258. *
  1259. * Name:
  1260. *
  1261. *
  1262. * Description:
  1263. *
  1264. *
  1265. *****************************************************************************/
  1266. template <class WmiKey>
  1267. WmiStatusCode WmiThread <WmiKey> :: Wait (
  1268. WmiTask <WmiKey> &a_Task ,
  1269. const ULONG &a_Timeout
  1270. )
  1271. {
  1272. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1273. WmiThread *t_ServicingThread = GetServicingThread ( a_Task ) ;
  1274. if ( t_ServicingThread )
  1275. {
  1276. HANDLE t_Handles [ 4 ] ;
  1277. t_Handles [ 0 ] = a_Task.GetCompletionEvent () ;
  1278. t_Handles [ 1 ] = GetTerminationEvent () ;
  1279. t_Handles [ 2 ] = t_ServicingThread->GetHandle () ;
  1280. t_Handles [ 3 ] = t_ServicingThread->GetTerminationEvent () ;
  1281. ULONG t_Event = WaitForMultipleObjects (
  1282. 4 ,
  1283. t_Handles ,
  1284. FALSE ,
  1285. a_Timeout
  1286. ) ;
  1287. switch ( t_Event )
  1288. {
  1289. case WAIT_TIMEOUT:
  1290. {
  1291. t_StatusCode = e_StatusCode_Success_Timeout ;
  1292. }
  1293. break ;
  1294. case WAIT_OBJECT_0:
  1295. {
  1296. t_StatusCode = e_StatusCode_Success ;
  1297. }
  1298. break ;
  1299. case WAIT_OBJECT_0+1:
  1300. {
  1301. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  1302. #if DBG
  1303. DebugBreak();
  1304. #endif
  1305. }
  1306. break ;
  1307. case WAIT_OBJECT_0+2:
  1308. case WAIT_OBJECT_0+3:
  1309. {
  1310. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  1311. #if DBG
  1312. DebugBreak();
  1313. #endif
  1314. }
  1315. break ;
  1316. case WAIT_FAILED:
  1317. {
  1318. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1319. {
  1320. t_StatusCode = e_StatusCode_OutOfMemory;
  1321. break;
  1322. }
  1323. }
  1324. default:
  1325. {
  1326. t_StatusCode = e_StatusCode_Unknown ;
  1327. #if DBG
  1328. DebugBreak();
  1329. #endif
  1330. }
  1331. break ;
  1332. }
  1333. }
  1334. else
  1335. {
  1336. t_StatusCode = e_StatusCode_Success ;
  1337. }
  1338. return t_StatusCode ;
  1339. }
  1340. /******************************************************************************
  1341. *
  1342. * Name:
  1343. *
  1344. *
  1345. * Description:
  1346. *
  1347. *
  1348. *****************************************************************************/
  1349. template <class WmiKey>
  1350. WmiStatusCode WmiThread <WmiKey> :: Static_InterruptableDispatch (
  1351. WmiTask <WmiKey> &a_Task ,
  1352. WmiThread <WmiKey> &a_Thread ,
  1353. const ULONG &a_Timeout
  1354. )
  1355. {
  1356. int sleep_duration = 0;
  1357. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1358. HANDLE t_Handles [ 3 ] ;
  1359. t_Handles [ 0 ] = a_Task.GetCompletionEvent () ;
  1360. t_Handles [ 1 ] = a_Thread.GetHandle () ;
  1361. t_Handles [ 2 ] = a_Thread.GetTerminationEvent () ;
  1362. bool t_Continuing = true ;
  1363. while ( t_Continuing && t_StatusCode == e_StatusCode_Success )
  1364. {
  1365. ULONG t_Event = MsgWaitForMultipleObjects (
  1366. 3 ,
  1367. t_Handles ,
  1368. FALSE ,
  1369. a_Timeout ,
  1370. QS_ALLINPUT
  1371. ) ;
  1372. switch ( t_Event )
  1373. {
  1374. case WAIT_TIMEOUT:
  1375. {
  1376. t_StatusCode = e_StatusCode_Success_Timeout ;
  1377. }
  1378. break ;
  1379. case WAIT_OBJECT_0:
  1380. {
  1381. t_StatusCode = e_StatusCode_Success ;
  1382. t_Continuing = false ;
  1383. }
  1384. break ;
  1385. case WAIT_OBJECT_0+1:
  1386. case WAIT_OBJECT_0+2:
  1387. {
  1388. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  1389. #if DBG
  1390. DebugBreak();
  1391. #endif
  1392. }
  1393. break ;
  1394. case WAIT_OBJECT_0+3:
  1395. {
  1396. BOOL t_DispatchStatus ;
  1397. MSG t_Msg ;
  1398. while ( ( t_DispatchStatus = PeekMessage ( & t_Msg , NULL , 0 , 0 , PM_NOREMOVE ) ) == TRUE )
  1399. {
  1400. if ( ( t_DispatchStatus = GetMessage ( & t_Msg , NULL , 0 , 0 ) ) == TRUE )
  1401. {
  1402. TranslateMessage ( & t_Msg ) ;
  1403. DispatchMessage ( & t_Msg ) ;
  1404. }
  1405. }
  1406. ULONG t_Event = WaitForMultipleObjects (
  1407. 3 ,
  1408. t_Handles ,
  1409. FALSE ,
  1410. 0
  1411. ) ;
  1412. switch ( t_Event )
  1413. {
  1414. case WAIT_TIMEOUT:
  1415. {
  1416. t_StatusCode = e_StatusCode_Success_Timeout ;
  1417. }
  1418. break ;
  1419. case WAIT_OBJECT_0:
  1420. {
  1421. t_StatusCode = e_StatusCode_Success ;
  1422. t_Continuing = true ;
  1423. }
  1424. break ;
  1425. case WAIT_OBJECT_0+1:
  1426. case WAIT_OBJECT_0+2:
  1427. {
  1428. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  1429. #if DBG
  1430. DebugBreak();
  1431. #endif
  1432. }
  1433. break ;
  1434. case WAIT_FAILED:
  1435. {
  1436. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1437. {
  1438. Sleep(sleep_duration?10:0);
  1439. sleep_duration^=1;
  1440. continue;
  1441. }
  1442. }
  1443. default:
  1444. {
  1445. t_StatusCode = e_StatusCode_Unknown ;
  1446. #if DBG
  1447. DebugBreak();
  1448. #endif
  1449. }
  1450. break ;
  1451. }
  1452. }
  1453. break ;
  1454. case WAIT_FAILED:
  1455. {
  1456. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1457. {
  1458. Sleep(sleep_duration?10:0);
  1459. sleep_duration^=1;
  1460. continue;
  1461. }
  1462. }
  1463. default:
  1464. {
  1465. t_StatusCode = e_StatusCode_Unknown ;
  1466. #if DBG
  1467. DebugBreak();
  1468. #endif
  1469. }
  1470. break ;
  1471. }
  1472. }
  1473. return t_StatusCode ;
  1474. }
  1475. /******************************************************************************
  1476. *
  1477. * Name:
  1478. *
  1479. *
  1480. * Description:
  1481. *
  1482. *
  1483. *****************************************************************************/
  1484. template <class WmiKey>
  1485. WmiStatusCode WmiThread <WmiKey> :: Static_InterruptableDispatch (
  1486. WmiTask <WmiKey> &a_Task ,
  1487. const ULONG &a_Timeout
  1488. )
  1489. {
  1490. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1491. WmiThread *t_Thread = GetThread () ;
  1492. if ( t_Thread )
  1493. {
  1494. t_StatusCode = t_Thread->InterruptableDispatch ( a_Task , a_Timeout ) ;
  1495. }
  1496. else
  1497. {
  1498. WmiThread *t_ServicingThread = GetServicingThread ( a_Task ) ;
  1499. if ( t_ServicingThread )
  1500. {
  1501. t_StatusCode = Static_InterruptableDispatch ( a_Task , *t_ServicingThread , a_Timeout ) ;
  1502. }
  1503. else
  1504. {
  1505. t_StatusCode = e_StatusCode_Success ;
  1506. }
  1507. }
  1508. return t_StatusCode ;
  1509. }
  1510. /******************************************************************************
  1511. *
  1512. * Name:
  1513. *
  1514. *
  1515. * Description:
  1516. *
  1517. *
  1518. *****************************************************************************/
  1519. template <class WmiKey>
  1520. WmiStatusCode WmiThread <WmiKey> :: InterruptableDispatch (
  1521. WmiTask <WmiKey> &a_Task ,
  1522. const ULONG &a_Timeout
  1523. )
  1524. {
  1525. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1526. QueueContainer t_EnQueue ( m_Allocator ) ;
  1527. t_StatusCode = t_EnQueue.Initialize () ;
  1528. if ( t_StatusCode == e_StatusCode_Success )
  1529. {
  1530. do
  1531. {
  1532. do
  1533. {
  1534. t_StatusCode = Execute ( m_InterruptableTaskQueue , t_EnQueue ) ;
  1535. } while ( t_StatusCode == e_StatusCode_Success ) ;
  1536. if ( t_StatusCode == e_StatusCode_NotInitialized )
  1537. {
  1538. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  1539. t_StatusCode = m_InterruptableTaskQueue.Merge ( t_EnQueue ) ;
  1540. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  1541. if ( t_StatusCode == e_StatusCode_Success )
  1542. {
  1543. t_StatusCode = InterruptableWait ( a_Task , a_Timeout ) ;
  1544. }
  1545. }
  1546. }
  1547. while ( t_StatusCode == e_StatusCode_Success || t_StatusCode == e_StatusCode_Change ) ;
  1548. }
  1549. return t_StatusCode ;
  1550. }
  1551. /******************************************************************************
  1552. *
  1553. * Name:
  1554. *
  1555. *
  1556. * Description:
  1557. *
  1558. *
  1559. *****************************************************************************/
  1560. template <class WmiKey>
  1561. WmiStatusCode WmiThread <WmiKey> :: InterruptableWait (
  1562. WmiTask <WmiKey> &a_Task ,
  1563. const ULONG &a_Timeout
  1564. )
  1565. {
  1566. int sleep_duration = 0;
  1567. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1568. WmiThread *t_ServicingThread = GetServicingThread ( a_Task ) ;
  1569. if ( t_ServicingThread )
  1570. {
  1571. HANDLE t_Handles [ 5 ] ;
  1572. t_Handles [ 0 ] = a_Task.GetCompletionEvent () ;
  1573. t_Handles [ 1 ] = GetTerminationEvent () ;
  1574. t_Handles [ 2 ] = t_ServicingThread->GetHandle () ;
  1575. t_Handles [ 3 ] = t_ServicingThread->GetTerminationEvent () ;
  1576. t_Handles [ 4 ] = t_ServicingThread->GetQueueChangeEvent () ;
  1577. bool t_Continuing = true ;
  1578. while ( t_Continuing && t_StatusCode == e_StatusCode_Success )
  1579. {
  1580. ULONG t_Event = MsgWaitForMultipleObjects (
  1581. 5 ,
  1582. t_Handles ,
  1583. FALSE ,
  1584. a_Timeout ,
  1585. QS_ALLINPUT
  1586. ) ;
  1587. switch ( t_Event )
  1588. {
  1589. case WAIT_TIMEOUT:
  1590. {
  1591. t_StatusCode = e_StatusCode_Success_Timeout ;
  1592. }
  1593. break ;
  1594. case WAIT_OBJECT_0:
  1595. {
  1596. t_StatusCode = e_StatusCode_Success ;
  1597. t_Continuing = false ;
  1598. }
  1599. break ;
  1600. case WAIT_OBJECT_0+1:
  1601. {
  1602. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  1603. #if DBG
  1604. DebugBreak();
  1605. #endif
  1606. }
  1607. break ;
  1608. case WAIT_OBJECT_0+2:
  1609. case WAIT_OBJECT_0+3:
  1610. {
  1611. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  1612. #if DBG
  1613. DebugBreak();
  1614. #endif
  1615. }
  1616. break ;
  1617. case WAIT_OBJECT_0+4:
  1618. {
  1619. t_StatusCode = e_StatusCode_Change ;
  1620. }
  1621. break ;
  1622. case WAIT_OBJECT_0+5:
  1623. {
  1624. BOOL t_DispatchStatus ;
  1625. MSG t_Msg ;
  1626. while ( ( t_DispatchStatus = PeekMessage ( & t_Msg , NULL , 0 , 0 , PM_NOREMOVE ) ) == TRUE )
  1627. {
  1628. if ( ( t_DispatchStatus = GetMessage ( & t_Msg , NULL , 0 , 0 ) ) == TRUE )
  1629. {
  1630. TranslateMessage ( & t_Msg ) ;
  1631. DispatchMessage ( & t_Msg ) ;
  1632. }
  1633. }
  1634. ULONG t_Event = WaitForMultipleObjects (
  1635. 5 ,
  1636. t_Handles ,
  1637. FALSE ,
  1638. 0
  1639. ) ;
  1640. switch ( t_Event )
  1641. {
  1642. case WAIT_TIMEOUT:
  1643. {
  1644. t_StatusCode = e_StatusCode_Success_Timeout ;
  1645. }
  1646. break ;
  1647. case WAIT_OBJECT_0:
  1648. {
  1649. t_StatusCode = e_StatusCode_Success ;
  1650. t_Continuing = false ;
  1651. }
  1652. break ;
  1653. case WAIT_OBJECT_0+1:
  1654. {
  1655. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  1656. #if DBG
  1657. DebugBreak();
  1658. #endif
  1659. }
  1660. break ;
  1661. case WAIT_OBJECT_0+2:
  1662. case WAIT_OBJECT_0+3:
  1663. {
  1664. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  1665. #if DBG
  1666. DebugBreak();
  1667. #endif
  1668. }
  1669. break ;
  1670. case WAIT_OBJECT_0+4:
  1671. {
  1672. t_StatusCode = e_StatusCode_Change ;
  1673. }
  1674. break ;
  1675. case WAIT_FAILED:
  1676. {
  1677. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1678. {
  1679. Sleep(sleep_duration?10:0);
  1680. sleep_duration^=1;
  1681. continue;
  1682. }
  1683. }
  1684. default:
  1685. {
  1686. t_StatusCode = e_StatusCode_Unknown ;
  1687. #if DBG
  1688. DebugBreak();
  1689. #endif
  1690. }
  1691. break ;
  1692. }
  1693. }
  1694. break ;
  1695. case WAIT_FAILED:
  1696. {
  1697. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1698. {
  1699. Sleep(sleep_duration?10:0);
  1700. sleep_duration^=1;
  1701. continue;
  1702. }
  1703. }
  1704. default:
  1705. {
  1706. t_StatusCode = e_StatusCode_Unknown ;
  1707. #if DBG
  1708. DebugBreak();
  1709. #endif
  1710. }
  1711. break ;
  1712. }
  1713. }
  1714. }
  1715. else
  1716. {
  1717. t_StatusCode = e_StatusCode_Success ;
  1718. }
  1719. return t_StatusCode ;
  1720. }
  1721. /******************************************************************************
  1722. *
  1723. * Name:
  1724. *
  1725. *
  1726. * Description:
  1727. *
  1728. *
  1729. *****************************************************************************/
  1730. template <class WmiKey>
  1731. WmiStatusCode WmiThread <WmiKey> :: Static_AlertableDispatch (
  1732. WmiTask <WmiKey> &a_Task ,
  1733. WmiThread <WmiKey> &a_Thread ,
  1734. const ULONG &a_Timeout
  1735. )
  1736. {
  1737. int sleep_duration = 0;
  1738. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1739. HANDLE t_Handles [ 3 ] ;
  1740. t_Handles [ 0 ] = a_Task.GetCompletionEvent () ;
  1741. t_Handles [ 1 ] = a_Thread.GetHandle () ;
  1742. t_Handles [ 2 ] = a_Thread.GetTerminationEvent () ;
  1743. bool t_Continuing = true ;
  1744. while ( t_StatusCode == e_StatusCode_Success && t_Continuing )
  1745. {
  1746. ULONG t_Event = MsgWaitForMultipleObjects (
  1747. 3 ,
  1748. t_Handles ,
  1749. FALSE ,
  1750. a_Timeout ,
  1751. QS_ALLINPUT
  1752. ) ;
  1753. switch ( t_Event )
  1754. {
  1755. case WAIT_TIMEOUT:
  1756. {
  1757. t_StatusCode = e_StatusCode_Success_Timeout ;
  1758. }
  1759. break ;
  1760. case WAIT_OBJECT_0:
  1761. {
  1762. t_StatusCode = e_StatusCode_Success ;
  1763. t_Continuing = false ;
  1764. }
  1765. break ;
  1766. case WAIT_OBJECT_0+1:
  1767. case WAIT_OBJECT_0+2:
  1768. {
  1769. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  1770. #if DBG
  1771. DebugBreak();
  1772. #endif
  1773. }
  1774. break ;
  1775. case WAIT_OBJECT_0+3:
  1776. {
  1777. BOOL t_DispatchStatus ;
  1778. MSG t_Msg ;
  1779. while ( ( t_DispatchStatus = PeekMessage ( & t_Msg , NULL , 0 , 0 , PM_NOREMOVE ) ) == TRUE )
  1780. {
  1781. if ( ( t_DispatchStatus = GetMessage ( & t_Msg , NULL , 0 , 0 ) ) == TRUE )
  1782. {
  1783. TranslateMessage ( & t_Msg ) ;
  1784. DispatchMessage ( & t_Msg ) ;
  1785. }
  1786. }
  1787. ULONG t_Event = WaitForMultipleObjects (
  1788. 3 ,
  1789. t_Handles ,
  1790. FALSE ,
  1791. 0
  1792. ) ;
  1793. switch ( t_Event )
  1794. {
  1795. case WAIT_TIMEOUT:
  1796. {
  1797. t_StatusCode = e_StatusCode_Success_Timeout ;
  1798. }
  1799. break ;
  1800. case WAIT_OBJECT_0:
  1801. {
  1802. t_StatusCode = e_StatusCode_Success ;
  1803. t_Continuing = false ;
  1804. }
  1805. break ;
  1806. case WAIT_OBJECT_0+1:
  1807. case WAIT_OBJECT_0+2:
  1808. {
  1809. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  1810. }
  1811. break ;
  1812. case WAIT_FAILED:
  1813. {
  1814. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1815. {
  1816. Sleep(sleep_duration?10:0);
  1817. sleep_duration^=1;
  1818. continue;
  1819. }
  1820. }
  1821. default:
  1822. {
  1823. t_StatusCode = e_StatusCode_Unknown ;
  1824. #if DBG
  1825. DebugBreak();
  1826. #endif
  1827. }
  1828. break ;
  1829. }
  1830. }
  1831. break ;
  1832. case WAIT_FAILED:
  1833. {
  1834. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  1835. {
  1836. Sleep(sleep_duration?10:0);
  1837. sleep_duration^=1;
  1838. continue;
  1839. }
  1840. }
  1841. default:
  1842. {
  1843. t_StatusCode = e_StatusCode_Unknown ;
  1844. #if DBG
  1845. DebugBreak();
  1846. #endif
  1847. }
  1848. break ;
  1849. }
  1850. }
  1851. return t_StatusCode ;
  1852. }
  1853. /******************************************************************************
  1854. *
  1855. * Name:
  1856. *
  1857. *
  1858. * Description:
  1859. *
  1860. *
  1861. *****************************************************************************/
  1862. template <class WmiKey>
  1863. WmiStatusCode WmiThread <WmiKey> :: Static_AlertableDispatch (
  1864. WmiTask <WmiKey> &a_Task ,
  1865. const ULONG &a_Timeout
  1866. )
  1867. {
  1868. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1869. WmiThread *t_Thread = GetThread () ;
  1870. if ( t_Thread )
  1871. {
  1872. t_StatusCode = t_Thread->AlertableDispatch ( a_Task , a_Timeout ) ;
  1873. }
  1874. else
  1875. {
  1876. WmiThread *t_ServicingThread = GetServicingThread ( a_Task ) ;
  1877. if ( t_ServicingThread )
  1878. {
  1879. t_StatusCode = Static_AlertableDispatch ( a_Task , *t_ServicingThread , a_Timeout ) ;
  1880. }
  1881. else
  1882. {
  1883. t_StatusCode = e_StatusCode_Success ;
  1884. }
  1885. }
  1886. return t_StatusCode ;
  1887. }
  1888. /******************************************************************************
  1889. *
  1890. * Name:
  1891. *
  1892. *
  1893. * Description:
  1894. *
  1895. *
  1896. *****************************************************************************/
  1897. template <class WmiKey>
  1898. WmiStatusCode WmiThread <WmiKey> :: AlertableDispatch (
  1899. WmiTask <WmiKey> &a_Task ,
  1900. const ULONG &a_Timeout
  1901. )
  1902. {
  1903. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  1904. QueueContainer t_EnQueue ( m_Allocator ) ;
  1905. t_StatusCode = t_EnQueue.Initialize () ;
  1906. if ( t_StatusCode == e_StatusCode_Success )
  1907. {
  1908. do
  1909. {
  1910. do
  1911. {
  1912. t_StatusCode = Execute ( m_InterruptableTaskQueue , t_EnQueue ) ;
  1913. } while ( t_StatusCode == e_StatusCode_Success ) ;
  1914. if ( t_StatusCode == e_StatusCode_NotInitialized )
  1915. {
  1916. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  1917. t_StatusCode = m_InterruptableTaskQueue.Merge ( t_EnQueue ) ;
  1918. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  1919. if ( t_StatusCode == e_StatusCode_Success )
  1920. {
  1921. do
  1922. {
  1923. t_StatusCode = Execute ( m_TaskQueue , t_EnQueue ) ;
  1924. } while ( t_StatusCode == e_StatusCode_Success ) ;
  1925. }
  1926. }
  1927. if ( t_StatusCode == e_StatusCode_NotInitialized )
  1928. {
  1929. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  1930. t_StatusCode = m_TaskQueue.Merge ( t_EnQueue ) ;
  1931. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  1932. if ( t_StatusCode == e_StatusCode_Success )
  1933. {
  1934. t_StatusCode = AlertableWait ( a_Task , a_Timeout ) ;
  1935. }
  1936. }
  1937. }
  1938. while ( t_StatusCode == e_StatusCode_Success || t_StatusCode == e_StatusCode_Change ) ;
  1939. }
  1940. return t_StatusCode ;
  1941. }
  1942. /******************************************************************************
  1943. *
  1944. * Name:
  1945. *
  1946. *
  1947. * Description:
  1948. *
  1949. *
  1950. *****************************************************************************/
  1951. template <class WmiKey>
  1952. WmiStatusCode WmiThread <WmiKey> :: Execute ( QueueContainer &a_Queue , QueueContainer &a_EnQueue )
  1953. {
  1954. QueueKey t_TopKey ;
  1955. WmiTask < WmiKey > *t_TopTask ;
  1956. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  1957. WmiStatusCode t_StatusCode = a_Queue.Top ( t_TopKey , t_TopTask ) ;
  1958. if ( t_StatusCode == e_StatusCode_Success )
  1959. {
  1960. t_StatusCode = a_Queue.DeQueue () ;
  1961. if ( t_StatusCode == e_StatusCode_Success )
  1962. {
  1963. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  1964. if ( t_TopTask->TaskState () == WmiTask < WmiKey > :: e_WmiTask_EnQueued )
  1965. {
  1966. t_StatusCode = t_TopTask->Process ( *this ) ;
  1967. if ( t_StatusCode != e_StatusCode_EnQueue )
  1968. {
  1969. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  1970. if ( ( t_StatusCode = s_TaskContainer->Delete ( t_TopTask ) ) == e_StatusCode_NotFound )
  1971. {
  1972. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  1973. t_StatusCode = e_StatusCode_Success ;
  1974. }
  1975. else
  1976. {
  1977. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  1978. t_TopTask->Release () ;
  1979. }
  1980. }
  1981. else
  1982. {
  1983. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  1984. switch ( t_TopTask->EnqueuedAs () )
  1985. {
  1986. case WmiTask <WmiKey> :: e_WmiTask_Enqueue:
  1987. {
  1988. t_StatusCode = a_EnQueue.EnQueue ( t_TopKey , t_TopTask ) ;
  1989. }
  1990. break ;
  1991. case WmiTask <WmiKey> :: e_WmiTask_EnqueueAlertable:
  1992. {
  1993. t_StatusCode = m_AlertableTaskQueue.EnQueue ( t_TopKey , t_TopTask ) ;
  1994. }
  1995. break ;
  1996. case WmiTask <WmiKey> :: e_WmiTask_EnqueueInterruptable:
  1997. {
  1998. t_StatusCode = m_InterruptableTaskQueue.EnQueue ( t_TopKey , t_TopTask ) ;
  1999. }
  2000. break ;
  2001. default:
  2002. {
  2003. }
  2004. break ;
  2005. }
  2006. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  2007. SetEvent ( m_QueueChange ) ;
  2008. }
  2009. }
  2010. else
  2011. {
  2012. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  2013. if ( ( t_StatusCode = s_TaskContainer->Delete ( t_TopTask ) ) == e_StatusCode_NotFound )
  2014. {
  2015. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  2016. t_StatusCode = e_StatusCode_Success ;
  2017. }
  2018. else
  2019. {
  2020. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  2021. }
  2022. t_TopTask->Complete () ;
  2023. t_TopTask->Release () ;
  2024. }
  2025. }
  2026. else
  2027. {
  2028. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  2029. }
  2030. }
  2031. else
  2032. {
  2033. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  2034. }
  2035. return t_StatusCode ;
  2036. }
  2037. /******************************************************************************
  2038. *
  2039. * Name:
  2040. *
  2041. *
  2042. * Description:
  2043. *
  2044. *
  2045. *****************************************************************************/
  2046. template <class WmiKey>
  2047. WmiStatusCode WmiThread <WmiKey> :: ShuffleTask (
  2048. const HANDLE &a_Event
  2049. )
  2050. {
  2051. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  2052. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  2053. ULONG t_Index = m_AlertableTaskQueue.Size () ;
  2054. while ( ( t_StatusCode == e_StatusCode_Success ) && ( t_Index ) )
  2055. {
  2056. QueueKey t_TopKey ;
  2057. WmiTask < WmiKey > *t_TopTask ;
  2058. t_StatusCode = m_AlertableTaskQueue.Top ( t_TopKey , t_TopTask ) ;
  2059. if ( t_StatusCode == e_StatusCode_Success )
  2060. {
  2061. t_StatusCode = m_AlertableTaskQueue.DeQueue () ;
  2062. if ( t_StatusCode == e_StatusCode_Success )
  2063. {
  2064. if ( t_TopTask->GetEvent () == a_Event )
  2065. {
  2066. if ( t_TopTask->TaskState () == WmiTask < WmiKey > :: e_WmiTask_EnQueued )
  2067. {
  2068. t_StatusCode = m_TaskQueue.EnQueue ( t_TopKey , t_TopTask ) ;
  2069. if ( t_StatusCode == e_StatusCode_Success )
  2070. {
  2071. SetEvent ( m_QueueChange ) ;
  2072. break ;
  2073. }
  2074. }
  2075. else
  2076. {
  2077. WmiHelper :: EnterCriticalSection ( & s_CriticalSection ) ;
  2078. if ( ( t_StatusCode = s_TaskContainer->Delete ( t_TopTask ) ) == e_StatusCode_NotFound )
  2079. {
  2080. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  2081. t_StatusCode = e_StatusCode_Success ;
  2082. }
  2083. else
  2084. {
  2085. WmiHelper :: LeaveCriticalSection ( & s_CriticalSection ) ;
  2086. }
  2087. t_TopTask->Complete () ;
  2088. t_TopTask->Release () ;
  2089. }
  2090. }
  2091. else
  2092. {
  2093. t_TopKey.SetTick ( m_Key++ ) ;
  2094. t_StatusCode = m_AlertableTaskQueue.EnQueue ( t_TopKey , t_TopTask ) ;
  2095. if ( t_StatusCode == e_StatusCode_Success )
  2096. {
  2097. }
  2098. }
  2099. }
  2100. }
  2101. t_Index -- ;
  2102. }
  2103. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  2104. return t_StatusCode ;
  2105. }
  2106. /******************************************************************************
  2107. *
  2108. * Name:
  2109. *
  2110. *
  2111. * Description:
  2112. *
  2113. *
  2114. *****************************************************************************/
  2115. template <class WmiKey>
  2116. WmiStatusCode WmiThread <WmiKey> :: FillHandleTable (
  2117. HANDLE *a_HandleTable ,
  2118. ULONG &a_Capacity
  2119. )
  2120. {
  2121. ULONG t_Index = 0 ;
  2122. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  2123. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  2124. QueueContainerIterator t_Iterator ;
  2125. t_Iterator = m_AlertableTaskQueue.End () ;
  2126. while ( ( t_StatusCode == e_StatusCode_Success ) && ( t_Index < a_Capacity ) && ! t_Iterator.Null () )
  2127. {
  2128. if ( t_Iterator.GetElement ()->GetEvent () )
  2129. {
  2130. a_HandleTable [ t_Index ] = t_Iterator.GetElement ()->GetEvent () ;
  2131. }
  2132. else
  2133. {
  2134. t_StatusCode = e_StatusCode_InvalidArgs ;
  2135. }
  2136. t_Iterator.Decrement () ;
  2137. t_Index ++ ;
  2138. }
  2139. if ( t_StatusCode == e_StatusCode_NotInitialized )
  2140. {
  2141. t_StatusCode = e_StatusCode_Success ;
  2142. }
  2143. a_Capacity = t_Index ;
  2144. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  2145. return t_StatusCode ;
  2146. }
  2147. /******************************************************************************
  2148. *
  2149. * Name:
  2150. *
  2151. *
  2152. * Description:
  2153. *
  2154. *
  2155. *****************************************************************************/
  2156. template <class WmiKey>
  2157. WmiStatusCode WmiThread <WmiKey> :: AlertableWait (
  2158. WmiTask <WmiKey> &a_Task ,
  2159. const ULONG &a_Timeout
  2160. )
  2161. {
  2162. int sleep_duration = 0;
  2163. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  2164. WmiThread *t_ServicingThread = GetServicingThread ( a_Task ) ;
  2165. if ( t_ServicingThread )
  2166. {
  2167. HANDLE t_Handles [ MAXIMUM_WAIT_OBJECTS - 1 ] ;
  2168. t_Handles [ 0 ] = a_Task.GetCompletionEvent () ;
  2169. t_Handles [ 1 ] = GetTerminationEvent () ;
  2170. t_Handles [ 2 ] = t_ServicingThread->GetHandle () ;
  2171. t_Handles [ 3 ] = t_ServicingThread->GetTerminationEvent () ;
  2172. t_Handles [ 4 ] = t_ServicingThread->GetQueueChangeEvent () ;
  2173. ULONG t_Capacity = MAXIMUM_WAIT_OBJECTS - 6 ;
  2174. t_StatusCode = FillHandleTable ( & t_Handles [ 5 ] , t_Capacity ) ;
  2175. bool t_Continuing = true ;
  2176. while ( t_Continuing && t_StatusCode == e_StatusCode_Success )
  2177. {
  2178. ULONG t_Event = MsgWaitForMultipleObjects (
  2179. 5 + t_Capacity ,
  2180. t_Handles ,
  2181. FALSE ,
  2182. a_Timeout ,
  2183. QS_ALLINPUT
  2184. ) ;
  2185. switch ( t_Event )
  2186. {
  2187. case WAIT_TIMEOUT:
  2188. {
  2189. t_StatusCode = e_StatusCode_Success_Timeout ;
  2190. }
  2191. break ;
  2192. case WAIT_OBJECT_0:
  2193. {
  2194. t_StatusCode = e_StatusCode_Success ;
  2195. t_Continuing = false ;
  2196. }
  2197. break ;
  2198. case WAIT_OBJECT_0+1:
  2199. {
  2200. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  2201. #if DBG
  2202. DebugBreak();
  2203. #endif
  2204. }
  2205. break ;
  2206. case WAIT_OBJECT_0+2:
  2207. case WAIT_OBJECT_0+3:
  2208. {
  2209. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  2210. #if DBG
  2211. DebugBreak();
  2212. #endif
  2213. }
  2214. break ;
  2215. case WAIT_OBJECT_0+4:
  2216. {
  2217. t_StatusCode = e_StatusCode_Change ;
  2218. }
  2219. break ;
  2220. case WAIT_FAILED:
  2221. {
  2222. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  2223. {
  2224. Sleep(sleep_duration?10:0);
  2225. sleep_duration^=1;
  2226. continue;
  2227. }
  2228. }
  2229. default:
  2230. {
  2231. if ( t_Event == t_Capacity + 5 )
  2232. {
  2233. BOOL t_DispatchStatus ;
  2234. MSG t_Msg ;
  2235. while ( ( t_DispatchStatus = PeekMessage ( & t_Msg , NULL , 0 , 0 , PM_NOREMOVE ) ) == TRUE )
  2236. {
  2237. if ( ( t_DispatchStatus = GetMessage ( & t_Msg , NULL , 0 , 0 ) ) == TRUE )
  2238. {
  2239. TranslateMessage ( & t_Msg ) ;
  2240. DispatchMessage ( & t_Msg ) ;
  2241. }
  2242. }
  2243. ULONG t_Event = WaitForMultipleObjects (
  2244. 5 + t_Capacity ,
  2245. t_Handles ,
  2246. FALSE ,
  2247. 0
  2248. ) ;
  2249. switch ( t_Event )
  2250. {
  2251. case WAIT_TIMEOUT:
  2252. {
  2253. t_StatusCode = e_StatusCode_Success_Timeout ;
  2254. }
  2255. break ;
  2256. case WAIT_OBJECT_0:
  2257. {
  2258. t_StatusCode = e_StatusCode_Success ;
  2259. t_Continuing = false ;
  2260. }
  2261. break ;
  2262. case WAIT_OBJECT_0+1:
  2263. {
  2264. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  2265. #if DBG
  2266. DebugBreak();
  2267. #endif
  2268. }
  2269. break ;
  2270. case WAIT_OBJECT_0+2:
  2271. case WAIT_OBJECT_0+3:
  2272. {
  2273. t_StatusCode = e_StatusCode_ServicingThreadTerminated ;
  2274. #if DBG
  2275. DebugBreak();
  2276. #endif
  2277. }
  2278. break ;
  2279. case WAIT_OBJECT_0+4:
  2280. {
  2281. t_StatusCode = e_StatusCode_Change ;
  2282. }
  2283. break ;
  2284. case WAIT_FAILED:
  2285. {
  2286. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  2287. {
  2288. Sleep(sleep_duration?10:0);
  2289. sleep_duration^=1;
  2290. continue;
  2291. }
  2292. }
  2293. default:
  2294. {
  2295. if ( t_Event < t_Capacity + 5 )
  2296. {
  2297. t_StatusCode = ShuffleTask ( t_Handles [ t_Event ] ) ;
  2298. }
  2299. else
  2300. {
  2301. t_StatusCode = e_StatusCode_InvalidArgs ;
  2302. #if DBG
  2303. DebugBreak();
  2304. #endif
  2305. }
  2306. }
  2307. }
  2308. }
  2309. else if ( t_Event < t_Capacity + 5 )
  2310. {
  2311. t_StatusCode = ShuffleTask ( t_Handles [ t_Event ] ) ;
  2312. }
  2313. else
  2314. {
  2315. t_StatusCode = e_StatusCode_InvalidArgs ;
  2316. #if DBG
  2317. DebugBreak();
  2318. #endif
  2319. }
  2320. }
  2321. break ;
  2322. }
  2323. }
  2324. }
  2325. else
  2326. {
  2327. t_StatusCode = e_StatusCode_Success ;
  2328. }
  2329. return t_StatusCode ;
  2330. }
  2331. /******************************************************************************
  2332. *
  2333. * Name:
  2334. *
  2335. *
  2336. * Description:
  2337. *
  2338. *
  2339. *****************************************************************************/
  2340. template <class WmiKey>
  2341. WmiStatusCode WmiThread <WmiKey> :: ThreadDispatch ()
  2342. {
  2343. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  2344. QueueContainer t_EnQueue ( m_Allocator ) ;
  2345. t_StatusCode = t_EnQueue.Initialize () ;
  2346. if ( t_StatusCode == e_StatusCode_Success )
  2347. {
  2348. do
  2349. {
  2350. do
  2351. {
  2352. t_StatusCode = Execute ( m_InterruptableTaskQueue , t_EnQueue ) ;
  2353. } while ( t_StatusCode == e_StatusCode_Success ) ;
  2354. if ( t_StatusCode == e_StatusCode_NotInitialized )
  2355. {
  2356. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  2357. t_StatusCode = m_InterruptableTaskQueue.Merge ( t_EnQueue ) ;
  2358. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  2359. if ( t_StatusCode == e_StatusCode_Success )
  2360. {
  2361. do
  2362. {
  2363. t_StatusCode = Execute ( m_TaskQueue , t_EnQueue ) ;
  2364. } while ( t_StatusCode == e_StatusCode_Success ) ;
  2365. }
  2366. }
  2367. if ( t_StatusCode == e_StatusCode_NotInitialized )
  2368. {
  2369. WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
  2370. t_StatusCode = m_TaskQueue.Merge ( t_EnQueue ) ;
  2371. WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
  2372. if ( t_StatusCode == e_StatusCode_Success )
  2373. {
  2374. t_StatusCode = ThreadWait () ;
  2375. }
  2376. }
  2377. }
  2378. while ( t_StatusCode == e_StatusCode_Success || t_StatusCode == e_StatusCode_Change ) ;
  2379. }
  2380. return t_StatusCode ;
  2381. }
  2382. /******************************************************************************
  2383. *
  2384. * Name:
  2385. *
  2386. *
  2387. * Description:
  2388. *
  2389. *
  2390. *****************************************************************************/
  2391. template <class WmiKey>
  2392. WmiStatusCode WmiThread <WmiKey> :: ThreadWait ()
  2393. {
  2394. int sleep_duration = 0;
  2395. WmiStatusCode t_StatusCode = e_StatusCode_Success ;
  2396. HANDLE t_Handles [ MAXIMUM_WAIT_OBJECTS - 1 ] ;
  2397. t_Handles [ 0 ] = GetTerminationEvent () ;
  2398. t_Handles [ 1 ] = GetQueueChangeEvent () ;
  2399. ULONG t_Capacity = MAXIMUM_WAIT_OBJECTS - 3 ;
  2400. t_StatusCode = FillHandleTable ( & t_Handles [ 2 ] , t_Capacity ) ;
  2401. bool t_Continuing = true ;
  2402. while ( t_Continuing && t_StatusCode == e_StatusCode_Success )
  2403. {
  2404. ULONG t_Event = MsgWaitForMultipleObjectsEx (
  2405. 2 + t_Capacity ,
  2406. t_Handles ,
  2407. m_Timeout ,
  2408. QS_ALLINPUT ,
  2409. MWMO_ALERTABLE
  2410. ) ;
  2411. switch ( t_Event )
  2412. {
  2413. case WAIT_TIMEOUT:
  2414. {
  2415. t_StatusCode = TimedOut () ;
  2416. }
  2417. break ;
  2418. case WAIT_OBJECT_0:
  2419. {
  2420. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  2421. #if DBG
  2422. OutputDebugStringA ("\nWmiThread - Thread Terminating") ;
  2423. #endif
  2424. }
  2425. break ;
  2426. case WAIT_OBJECT_0+1:
  2427. {
  2428. t_StatusCode = e_StatusCode_Change ;
  2429. }
  2430. break ;
  2431. case WAIT_IO_COMPLETION:
  2432. {
  2433. t_StatusCode = e_StatusCode_Success;
  2434. }
  2435. break ;
  2436. case WAIT_FAILED:
  2437. {
  2438. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  2439. {
  2440. Sleep(sleep_duration?10:0);
  2441. sleep_duration^=1;
  2442. continue;
  2443. }
  2444. }
  2445. default:
  2446. {
  2447. if ( t_Event == t_Capacity + 2 )
  2448. {
  2449. BOOL t_DispatchStatus ;
  2450. MSG t_Msg ;
  2451. while ( ( t_DispatchStatus = PeekMessage ( & t_Msg , NULL , 0 , 0 , PM_NOREMOVE ) ) == TRUE )
  2452. {
  2453. if ( ( t_DispatchStatus = GetMessage ( & t_Msg , NULL , 0 , 0 ) ) == TRUE )
  2454. {
  2455. TranslateMessage ( & t_Msg ) ;
  2456. DispatchMessage ( & t_Msg ) ;
  2457. }
  2458. }
  2459. ULONG t_Event = WaitForMultipleObjects (
  2460. 2 + t_Capacity ,
  2461. t_Handles ,
  2462. FALSE ,
  2463. 0
  2464. ) ;
  2465. switch ( t_Event )
  2466. {
  2467. case WAIT_TIMEOUT:
  2468. {
  2469. t_StatusCode = TimedOut () ;
  2470. }
  2471. break ;
  2472. case WAIT_OBJECT_0:
  2473. {
  2474. t_StatusCode = e_StatusCode_HostingThreadTerminated ;
  2475. #if DBG
  2476. OutputDebugStringA ( "\nWmiThread - Thread Terminating") ;
  2477. #endif
  2478. }
  2479. break ;
  2480. case WAIT_OBJECT_0+1:
  2481. {
  2482. t_StatusCode = e_StatusCode_Change ;
  2483. }
  2484. break ;
  2485. case WAIT_FAILED:
  2486. {
  2487. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  2488. {
  2489. Sleep(sleep_duration?10:0);
  2490. sleep_duration^=1;
  2491. continue;
  2492. }
  2493. }
  2494. default:
  2495. {
  2496. if ( t_Event < t_Capacity + 2 )
  2497. {
  2498. t_StatusCode = ShuffleTask ( t_Handles [ t_Event ] ) ;
  2499. }
  2500. else
  2501. {
  2502. t_StatusCode = e_StatusCode_InvalidArgs ;
  2503. #if DBG
  2504. DebugBreak();
  2505. #endif
  2506. }
  2507. }
  2508. }
  2509. }
  2510. else if ( t_Event < t_Capacity + 2 )
  2511. {
  2512. t_StatusCode = ShuffleTask ( t_Handles [ t_Event ] ) ;
  2513. }
  2514. else
  2515. {
  2516. t_StatusCode = e_StatusCode_InvalidArgs ;
  2517. #if DBG
  2518. DebugBreak();
  2519. #endif
  2520. }
  2521. }
  2522. break ;
  2523. }
  2524. }
  2525. return t_StatusCode ;
  2526. }
  2527. #endif __THREAD_CPP