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.

860 lines
24 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: QQueue.cxx
  7. //
  8. // Contents: Query queue
  9. //
  10. // History: 29-Dec-93 KyleP Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <worker.hxx>
  16. #include <ciregkey.hxx>
  17. #include <regacc.hxx>
  18. #include <imprsnat.hxx>
  19. //+-------------------------------------------------------------------------
  20. //
  21. // Member: CWorkQueue::GetWorkQueueRegParams, public
  22. //
  23. // Synopsis: Fetches registry params for the work queue
  24. //
  25. // History: 30-Dec-96 SrikantS Moved the code from RefreshRegParams
  26. //
  27. //--------------------------------------------------------------------------
  28. void CWorkQueue::GetWorkQueueRegParams( ULONG & cMaxActiveThreads,
  29. ULONG & cMinIdleThreads )
  30. {
  31. CRegAccess reg( RTL_REGISTRY_CONTROL, wcsRegAdmin );
  32. if ( CWorkQueue::workQueueQuery == _QueueType )
  33. {
  34. cMaxActiveThreads = reg.Read( wcsMaxActiveQueryThreads,
  35. CI_MAX_ACTIVE_QUERY_THREADS_DEFAULT,
  36. CI_MAX_ACTIVE_QUERY_THREADS_MIN,
  37. CI_MAX_ACTIVE_QUERY_THREADS_MAX );
  38. cMinIdleThreads = reg.Read( wcsMinIdleQueryThreads,
  39. CI_MIN_IDLE_QUERY_THREADS_DEFAULT,
  40. CI_MIN_IDLE_QUERY_THREADS_MIN,
  41. CI_MIN_IDLE_QUERY_THREADS_MAX );
  42. }
  43. else if ( CWorkQueue::workQueueRequest == _QueueType )
  44. {
  45. cMaxActiveThreads = reg.Read( wcsMaxActiveRequestThreads,
  46. CI_MAX_ACTIVE_REQUEST_THREADS_DEFAULT,
  47. CI_MAX_ACTIVE_REQUEST_THREADS_MIN,
  48. CI_MAX_ACTIVE_REQUEST_THREADS_MAX );
  49. cMinIdleThreads = reg.Read( wcsMinIdleRequestThreads,
  50. CI_MIN_IDLE_REQUEST_THREADS_DEFAULT,
  51. CI_MIN_IDLE_REQUEST_THREADS_MIN,
  52. CI_MIN_IDLE_REQUEST_THREADS_MAX );
  53. }
  54. else
  55. {
  56. cMaxActiveThreads = 2;
  57. cMinIdleThreads = 0;
  58. }
  59. } //GetWorkQueueRegParams
  60. //+-------------------------------------------------------------------------
  61. //
  62. // Member: CWorkQueue::CWorkQueue, public
  63. //
  64. // Synopsis: Initialize queue.
  65. //
  66. // Arguments: [cThread] -- Number of worker threads.
  67. // [workQueue] -- Work queue type for getting registry settings.
  68. //
  69. // History: 29-Dec-93 KyleP Created
  70. //
  71. //--------------------------------------------------------------------------
  72. CWorkQueue::CWorkQueue(
  73. unsigned cThread,
  74. WorkQueueType workQueue )
  75. : _cQuery( 0 ),
  76. _pHead( 0 ),
  77. _pTail( 0 ),
  78. _apWorker( 0 ), // avoid allocation in construction of global
  79. _pIdle( 0 ),
  80. _cIdle( 0 ),
  81. _fInit( FALSE ),
  82. _fAbort( FALSE ),
  83. _cWorker( 0 ),
  84. _cMaxActiveThreads(cThread),
  85. _cMinIdleThreads(0),
  86. _QueueType( workQueue ),
  87. _mtxLock( FALSE )
  88. {
  89. Win4Assert( workQueueQuery == workQueue ||
  90. workQueueRequest == workQueue ||
  91. workQueueFrmwrkClient == workQueue );
  92. // Note: don't call RefreshRegParams as long as the work queue
  93. // is a global object -- there's no telling what security context will
  94. // be used to load the .dll.
  95. //RefreshParams( cThread, cThread );
  96. } //CWorkQueue
  97. //+-------------------------------------------------------------------------
  98. //
  99. // Member: CWorkQueue::~CWorkQueue, public
  100. //
  101. // Synopsis: Waits for queue threads to stop.
  102. //
  103. // Requires: An external source has killed all queue items.
  104. //
  105. // History: 29-Dec-93 KyleP Created
  106. //
  107. //--------------------------------------------------------------------------
  108. CWorkQueue::~CWorkQueue()
  109. {
  110. Win4Assert( _cQuery == 0 );
  111. if (_fInit)
  112. Shutdown();
  113. }
  114. //+-------------------------------------------------------------------------
  115. //
  116. // Member: CWorkQueue::RefreshParams, public
  117. //
  118. // Synopsis: Refreshes registry params for the work queue
  119. //
  120. // History: 7-Nov-96 dlee Created
  121. // 30-Dec-96 SrikantS Changed name to RefreshParams and removed
  122. // the dependency on registry.
  123. //
  124. //--------------------------------------------------------------------------
  125. #pragma warning(push)
  126. #pragma warning(disable:4296)
  127. void CWorkQueue::RefreshParams( ULONG cMaxActiveThread,
  128. ULONG cMinIdleThread )
  129. {
  130. CLock lock( _mtxLock );
  131. if ( CWorkQueue::workQueueQuery == _QueueType )
  132. {
  133. _cMaxActiveThreads = min( CI_MAX_ACTIVE_QUERY_THREADS_MAX,
  134. max(CI_MAX_ACTIVE_QUERY_THREADS_MIN,
  135. cMaxActiveThread) );
  136. _cMinIdleThreads = min( CI_MIN_IDLE_QUERY_THREADS_MAX,
  137. max(CI_MIN_IDLE_QUERY_THREADS_MIN,
  138. cMinIdleThread) );
  139. }
  140. else if ( CWorkQueue::workQueueRequest == _QueueType )
  141. {
  142. _cMaxActiveThreads = min( CI_MAX_ACTIVE_REQUEST_THREADS_MAX,
  143. max(CI_MAX_ACTIVE_REQUEST_THREADS_MIN,
  144. cMaxActiveThread) );
  145. _cMinIdleThreads = min( CI_MIN_IDLE_REQUEST_THREADS_MAX,
  146. max(CI_MIN_IDLE_REQUEST_THREADS_MIN,
  147. cMinIdleThread) );
  148. }
  149. else // framework client queue
  150. {
  151. _cMaxActiveThreads = 2;
  152. _cMinIdleThreads = 0;
  153. }
  154. } //RefreshParams
  155. #pragma warning(pop)
  156. //+-------------------------------------------------------------------------
  157. //
  158. // Member: CWorkQueue::Shutdown, public
  159. //
  160. // Synopsis: Shuts down the work queue
  161. //
  162. // History: 7-Nov-96 dlee Added header
  163. //
  164. //--------------------------------------------------------------------------
  165. void CWorkQueue::Shutdown()
  166. {
  167. if (_fInit)
  168. {
  169. CLock lock( _mtxLock );
  170. _fAbort = TRUE;
  171. for ( CWorkThread * pw = _pIdle; pw; pw = pw->Next() ) {
  172. Win4Assert(pw != pw->Next());
  173. pw->Wakeup();
  174. }
  175. vqDebugOut(( DEB_ITRACE, "Work queue shutdown: woke up threads\n" ));
  176. }
  177. _apWorker.Free();
  178. vqDebugOut(( DEB_ITRACE, "Work queue shutdown: exiting\n" ));
  179. } //Shutdown
  180. //+-------------------------------------------------------------------------
  181. //
  182. // Member: CWorkQueue::AddRefWorkThreads, public
  183. //
  184. // Synopsis: Addrefs the current set of worker threads
  185. //
  186. // History: 21-May-97 dlee Created
  187. //
  188. //--------------------------------------------------------------------------
  189. void CWorkQueue::AddRefWorkThreads()
  190. {
  191. CLock lock( _mtxLock );
  192. for ( ULONG x = 0; x < _cWorker; x++ )
  193. _apWorker[x]->AddRef();
  194. } //AddRefWorkThreads
  195. //+-------------------------------------------------------------------------
  196. //
  197. // Member: CWorkQueue::ReleaseWorkThreads, public
  198. //
  199. // Synopsis: Releases the current set of worker threads
  200. //
  201. // History: 21-May-97 dlee Created
  202. //
  203. //--------------------------------------------------------------------------
  204. void CWorkQueue::ReleaseWorkThreads()
  205. {
  206. CLock lock( _mtxLock );
  207. for ( ULONG x = 0; x < _cWorker; x++ )
  208. _apWorker[x]->Release();
  209. } //ReleaseWorkThreads
  210. //+-------------------------------------------------------------------------
  211. //
  212. // Member: CWorkQueue::Add, public
  213. //
  214. // Synopsis: Add a query to the queue.
  215. //
  216. // Arguments: [pitem] -- Query to add
  217. //
  218. // History: 29-Dec-93 KyleP Created
  219. //
  220. //--------------------------------------------------------------------------
  221. void CWorkQueue::Add( PWorkItem * pitem )
  222. {
  223. BOOL fTryRemove = FALSE;
  224. {
  225. CLock lock( _mtxLock );
  226. if ( _fAbort )
  227. {
  228. vqDebugOut(( DEB_ITRACE, "work queue, shutdown, so not adding item\n" ));
  229. return;
  230. }
  231. pitem->AddRef();
  232. //
  233. // Insert at end of list
  234. //
  235. if ( _pTail )
  236. {
  237. _pTail->Link( pitem );
  238. _pTail = pitem;
  239. }
  240. else
  241. {
  242. Win4Assert( !_pHead );
  243. _pHead = pitem;
  244. _pTail = pitem;
  245. }
  246. _pTail->Link( 0 );
  247. _cQuery++;
  248. vqDebugOut(( DEB_ITRACE, "Work queue: add 0x%x\n", pitem ));
  249. //
  250. // Wake up a thread if there is an idle one.
  251. //
  252. if ( !_pIdle && _cWorker < _cMaxActiveThreads )
  253. {
  254. Win4Assert( 0 == _cIdle );
  255. TRY
  256. {
  257. lokAddThread();
  258. }
  259. CATCH( CException, e )
  260. {
  261. //
  262. // Remove the item from the work queue so it gets released
  263. // properly.
  264. //
  265. Remove( pitem );
  266. //
  267. // Now rethrow the exception, which will only happen if
  268. // there are not worker threads at all.
  269. //
  270. RETHROW();
  271. }
  272. END_CATCH;
  273. Win4Assert( _pIdle == 0 || _pIdle->Next() != _pIdle );
  274. }
  275. if ( _pIdle )
  276. {
  277. Win4Assert( _cIdle > 0 );
  278. CWorkThread * pWorker = _pIdle;
  279. _pIdle = _pIdle->Next();
  280. _cIdle--;
  281. Win4Assert( _pIdle != pWorker );
  282. pWorker->Wakeup();
  283. if ( _cIdle > _cMinIdleThreads )
  284. fTryRemove = TRUE;
  285. }
  286. }
  287. if ( fTryRemove )
  288. RemoveThreads();
  289. } //Add
  290. //+-------------------------------------------------------------------------
  291. //
  292. // Member: CWorkQueue::Release, public
  293. //
  294. // Synopsis: Release refcount on worker thread
  295. //
  296. // Arguments: [pThread] -- Worker thread
  297. //
  298. // History: 13-Mar-96 KyleP Created
  299. //
  300. //--------------------------------------------------------------------------
  301. void CWorkQueue::Release( CWorkThread * pThread )
  302. {
  303. pThread->Release();
  304. BOOL fTryRemove = FALSE;
  305. if ( GetCurrentThreadId() != pThread->GetThreadId() )
  306. {
  307. CLock lock( _mtxLock );
  308. if ( _pIdle )
  309. {
  310. Win4Assert( _cIdle > 0 );
  311. if ( _cIdle > _cMinIdleThreads )
  312. fTryRemove = TRUE;
  313. }
  314. }
  315. if ( fTryRemove )
  316. RemoveThreads();
  317. } //Release
  318. //+-------------------------------------------------------------------------
  319. //
  320. // Member: CWorkQueue::Remove, private
  321. //
  322. // Synopsis: Remove a query from the queue.
  323. //
  324. // Arguments: [Worker] -- Worker thread to own the query
  325. //
  326. // History: 29-Dec-93 KyleP Created
  327. //
  328. // Notes: Remove is used by worker threads to acquire a new work
  329. // item. In contrast, the other remove will just remove
  330. // an item from the queue.
  331. //
  332. //--------------------------------------------------------------------------
  333. void CWorkQueue::Remove( CWorkThread & Worker )
  334. {
  335. Win4Assert( Worker.ActiveItem() == 0 );
  336. for (;;)
  337. {
  338. //
  339. // Look for an item
  340. //
  341. {
  342. CLock lock( _mtxLock );
  343. Worker.Reset();
  344. //
  345. // We may have been awoken by an APC. Be sure we're not
  346. // still on the idle queue in this case.
  347. //
  348. if ( _pIdle )
  349. {
  350. if ( _pIdle == &Worker )
  351. {
  352. _cIdle--;
  353. _pIdle = Worker.Next();
  354. }
  355. else
  356. {
  357. for ( CWorkThread * pw = _pIdle; pw; pw = pw->Next() ) {
  358. if (pw->Next() == &Worker)
  359. {
  360. _cIdle--;
  361. pw->Link(Worker.Next());
  362. break;
  363. }
  364. }
  365. }
  366. }
  367. if ( _fAbort || Worker.lokShouldAbort() )
  368. {
  369. vqDebugOut(( DEB_ITRACE,
  370. "Work queue: abort worker thread.\n" ));
  371. break;
  372. }
  373. if ( Count() > 0 )
  374. {
  375. vqDebugOut(( DEB_ITRACE,
  376. "Work queue: %d pending\n", _cQuery ));
  377. Worker.lokSetActiveItem( _pHead );
  378. _pHead = _pHead->Next();
  379. if ( _pHead == 0 )
  380. _pTail = 0;
  381. _cQuery--;
  382. break;
  383. }
  384. //
  385. // Nothing on the queue right now. Wait for item.
  386. //
  387. Worker.Link( _pIdle );
  388. _pIdle = &Worker;
  389. _cIdle++;
  390. Win4Assert(Worker.Next() != &Worker);
  391. }
  392. Worker.Wait();
  393. }
  394. vqDebugOut(( DEB_ITRACE, "Work queue: remove 0x%x\n", Worker.ActiveItem() ));
  395. //
  396. // We're not sleeping the thread, make sure we
  397. // process APCs.
  398. //
  399. SleepEx( 0, TRUE );
  400. } //Remove
  401. //+-------------------------------------------------------------------------
  402. //
  403. // Member: CWorkQueue::Remove, public
  404. //
  405. // Effects: Deletes all references to [pitem] from the queue. If
  406. // pitem is a query-in-progress in a worker thread then
  407. // we wait until that query completes before returning from
  408. // Delete.
  409. //
  410. // Arguments: [pitem] -- Query to remove
  411. //
  412. // History: 29-Dec-93 KyleP Created
  413. // 09-Feb-94 KyleP Speed up removal of active item
  414. //
  415. // Notes: The item may still be running on a worker thread when we
  416. // return from this call.
  417. //
  418. //--------------------------------------------------------------------------
  419. void CWorkQueue::Remove( PWorkItem * pitem )
  420. {
  421. CLock lock( _mtxLock );
  422. if ( _pHead == pitem )
  423. {
  424. _pHead = pitem->Next();
  425. if ( _pTail == pitem )
  426. {
  427. Win4Assert( _pHead == 0 );
  428. _pTail = 0;
  429. }
  430. _cQuery--;
  431. pitem->Release();
  432. vqDebugOut(( DEB_ITRACE,
  433. "Work queue: delete 0x%x\n", pitem ));
  434. }
  435. else
  436. {
  437. for ( PWorkItem * pCurrent = _pHead;
  438. pCurrent && pCurrent->Next() != pitem;
  439. pCurrent = pCurrent->Next() )
  440. continue; // Null body
  441. if ( pCurrent )
  442. {
  443. Win4Assert( pCurrent->Next() == pitem );
  444. if ( _pTail == pitem )
  445. {
  446. _pTail = pCurrent;
  447. }
  448. pCurrent->Link( pitem->Next() );
  449. _cQuery--;
  450. pitem->Release();
  451. vqDebugOut(( DEB_ITRACE,
  452. "Work queue: delete 0x%x\n", pitem ));
  453. }
  454. }
  455. } //Remove
  456. //+-------------------------------------------------------------------------
  457. //
  458. // Member: CWorkQueue::AddThread, private
  459. //
  460. // Synopsis: Adds new worker thread to idle worker list.
  461. //
  462. // History: 12-Jan-94 KyleP Created
  463. //
  464. //--------------------------------------------------------------------------
  465. void CWorkQueue::lokAddThread()
  466. {
  467. TRY
  468. {
  469. vqDebugOut(( DEB_ITRACE, "Add worker thread %d of %d\n",
  470. _cWorker+1, _apWorker.Size() ));
  471. //
  472. // Worker threads must be created in the system context or they
  473. // won't have the permission to revert to system, which is needed
  474. // for queries on remote volumes and to write to catalog files.
  475. //
  476. CImpersonateSystem impersonate;
  477. CEventSem evt1;
  478. SHandle hEvt1( evt1.AcquireHandle() );
  479. CEventSem evt2;
  480. SHandle hEvt2( evt2.AcquireHandle() );
  481. _apWorker.Add( new CWorkThread( *this,
  482. _pIdle,
  483. hEvt1,
  484. hEvt2 ),
  485. _cWorker );
  486. _pIdle = _apWorker[_cWorker];
  487. _cIdle++;
  488. _cWorker++;
  489. }
  490. CATCH( CException, e )
  491. {
  492. vqDebugOut(( DEB_ERROR,
  493. "Exception 0x%x caught creating query worker threads."
  494. " Running with %d threads.\n", e.GetErrorCode(), _cWorker ));
  495. // Only throw an excption if there are no threads around at all.
  496. // If there is at least 1 thread it'll eventually get to the work
  497. // items.
  498. if ( 0 == _cWorker )
  499. {
  500. RETHROW();
  501. }
  502. }
  503. END_CATCH
  504. Win4Assert( _cWorker != 0 );
  505. } //lokAddThread
  506. //+-------------------------------------------------------------------------
  507. //
  508. // Member: CWorkQueue::RemoveThreads, private
  509. //
  510. // Synopsis: Removes one or more threads from idle queue.
  511. //
  512. // History: 28-Sep-95 KyleP Created
  513. //
  514. //--------------------------------------------------------------------------
  515. void CWorkQueue::RemoveThreads()
  516. {
  517. while ( TRUE )
  518. {
  519. CWorkThread * pThread = 0;
  520. //
  521. // Check for too many idle threads under lock.
  522. //
  523. {
  524. CLock lock( _mtxLock );
  525. if ( _cIdle > _cMinIdleThreads )
  526. {
  527. //
  528. // Find an idle thread that has a refcount of 0.
  529. //
  530. CWorkThread * pPrev = 0;
  531. for ( pThread = _pIdle; 0 != pThread; pThread = pThread->Next() )
  532. {
  533. if ( !pThread->IsReferenced() )
  534. break;
  535. pPrev = pThread;
  536. }
  537. if ( 0 != pThread )
  538. {
  539. for ( unsigned i = 0; i < _cWorker; i++ )
  540. {
  541. //
  542. // Remove first idle thread from all queues and abort it.
  543. //
  544. if ( _apWorker[i] == pThread )
  545. {
  546. vqDebugOut(( DEB_ITRACE, "Deleting extra idle thread\n" ));
  547. if ( 0 == pPrev )
  548. _pIdle = _pIdle->Next();
  549. else
  550. pPrev->Link( pThread->Next() );
  551. _cIdle--;
  552. _cWorker--;
  553. _apWorker.Acquire( i );
  554. _apWorker.Add( _apWorker.Acquire(_cWorker), i );
  555. pThread->lokAbort();
  556. pThread->Wakeup();
  557. break;
  558. }
  559. }
  560. Win4Assert( i <= _cWorker );
  561. }
  562. }
  563. }
  564. //
  565. // If we found an extra idle thread, delete it and try again, else just get out.
  566. //
  567. if ( pThread )
  568. delete pThread;
  569. else
  570. break;
  571. }
  572. } //RemoveThreads
  573. //+-------------------------------------------------------------------------
  574. //
  575. // Member: CWorkThread::WorkerThread, static private
  576. //
  577. // Synopsis: Main loop that executes query.
  578. //
  579. // Arguments: [self] -- this pointer for CWorkThread object
  580. //
  581. // History: 29-Dec-93 KyleP Created
  582. //
  583. //--------------------------------------------------------------------------
  584. DWORD WINAPI CWorkThread::WorkerThread( void * self )
  585. {
  586. CWorkThread * pWorker = (CWorkThread *)self;
  587. for( pWorker->_queue.Remove( *pWorker );
  588. pWorker->ActiveItem();
  589. pWorker->_queue.Remove( *pWorker ) )
  590. {
  591. TRY
  592. {
  593. pWorker->ActiveItem()->DoIt( pWorker );
  594. }
  595. CATCH( CException, e )
  596. {
  597. vqDebugOut(( DEB_ERROR, "pWorker->DoIt() failed with error 0x%x\n", e.GetErrorCode() ));
  598. }
  599. END_CATCH
  600. pWorker->Done();
  601. }
  602. //
  603. // We should not do an ExitThread() here because there will be a deadlock
  604. // during shutdown. The DLL_PROCESS_DETACH is called with the "LoaderLock"
  605. // CriticalSection held by the LdrUnloadDll() during the DLL detach.
  606. // Terminating the thread here is okay because there is no cleanup to be
  607. // done after this.
  608. //
  609. //
  610. // This is only necessary if thread is terminated from DLL_PROCESS_DETACH.
  611. //
  612. //TerminateThread( pWorker->_Thread.GetHandle(), 0 );
  613. vqDebugOut(( DEB_ITRACE, "WorkerThread 0x%x: exiting\n", self ));
  614. return 0;
  615. } //WorkerThread
  616. //+-------------------------------------------------------------------------
  617. //
  618. // Member: CWorkThread::CWorkThread, public
  619. //
  620. // Synopsis: Creates worker thread.
  621. //
  622. // Arguments: [queue] -- Work queue which owns worker.
  623. // [pNext] -- Link. Used by Work queue.
  624. // [hEvt1] -- Event handle for first event in the worker thread
  625. // [hEvt2] -- Event handle for second event in the worker thread
  626. //
  627. // History: 29-Dec-93 KyleP Created
  628. //
  629. //--------------------------------------------------------------------------
  630. #pragma warning( disable : 4355 ) // this used in base initialization
  631. CWorkThread::CWorkThread( CWorkQueue & queue,
  632. CWorkThread * pNext
  633. , SHandle & hEvt1
  634. , SHandle & hEvt2
  635. )
  636. : _queue( queue ),
  637. _pNext( pNext ),
  638. _pitem( 0 ),
  639. _fAbort( FALSE ),
  640. _Thread( CWorkThread::WorkerThread, this, TRUE ),
  641. _cRef( 0 )
  642. , _evtQueryAvailable( hEvt1.Acquire() )
  643. , _evtDone( hEvt2.Acquire() )
  644. {
  645. _Thread.Resume();
  646. }
  647. #pragma warning( default : 4355 )
  648. //+-------------------------------------------------------------------------
  649. //
  650. // Member: CWorkThread::~CWorkThread, public
  651. //
  652. // Synopsis: Waits for thread to die.
  653. //
  654. // History: 29-Dec-93 KyleP Created
  655. //
  656. //--------------------------------------------------------------------------
  657. CWorkThread::~CWorkThread()
  658. {
  659. vqDebugOut(( DEB_ITRACE, "Worker 0x%x: WAIT for death\n", this ));
  660. Win4Assert( GetCurrentThreadId() != GetThreadId() );
  661. _Thread.WaitForDeath();
  662. vqDebugOut(( DEB_ITRACE, "Worker 0x%x: done waiting for death\n", this ));
  663. }
  664. //+-------------------------------------------------------------------------
  665. //
  666. // Member: CWorkThread::Wait, public
  667. //
  668. // Synopsis: Waits for 'new work' event
  669. //
  670. // History: 29-Dec-93 KyleP Created
  671. //
  672. //--------------------------------------------------------------------------
  673. void CWorkThread::Wait()
  674. {
  675. vqDebugOut(( DEB_RESULTS, "Worker 0x%x: WAIT for work\n", this ));
  676. // no need to loop to look for work just because we woke
  677. // up after processing an APC.
  678. while ( STATUS_USER_APC == _evtQueryAvailable.Wait( INFINITE, TRUE ) )
  679. continue;
  680. }
  681. //+-------------------------------------------------------------------------
  682. //
  683. // Member: CWorkThread::Done, public
  684. //
  685. // Effects: Finishes one work item and sets 'done' event.
  686. //
  687. // History: 29-Dec-93 KyleP Created
  688. //
  689. //--------------------------------------------------------------------------
  690. void CWorkThread::Done()
  691. {
  692. CLock lock( _queue._mtxLock );
  693. ActiveItem()->Release();
  694. lokSetActiveItem( 0 );
  695. vqDebugOut(( DEB_ITRACE, "Worker 0x%x: SET completion\n", this ));
  696. _evtDone.Set();
  697. }
  698. //+-------------------------------------------------------------------------
  699. //
  700. // Member: CWorkThread::WaitForCompletion, public
  701. //
  702. // Synopsis: Waits for completion of current work item.
  703. //
  704. // History: 29-Dec-93 KyleP Created
  705. //
  706. //--------------------------------------------------------------------------
  707. void CWorkThread::WaitForCompletion( PWorkItem * pitem )
  708. {
  709. {
  710. CLock lock( _queue._mtxLock );
  711. if ( ActiveItem() != pitem )
  712. return;
  713. vqDebugOut(( DEB_ITRACE, "Worker 0x%x: RESET completion\n", this ));
  714. _evtDone.Reset();
  715. }
  716. vqDebugOut(( DEB_ITRACE, "Worker 0x%x: WAIT for completion\n", this ));
  717. _evtDone.Wait( INFINITE, TRUE );
  718. } //WaitForCompletion