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.

806 lines
24 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: APIDispatcher.cpp
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // A class that handles API requests in the server on a separate thread. Each
  7. // thread is dedicated to respond to a single client. This is acceptable for
  8. // a lightweight server.
  9. //
  10. // History: 1999-11-07 vtan created
  11. // 2000-08-25 vtan moved from Neptune to Whistler
  12. // --------------------------------------------------------------------------
  13. #include "StandardHeader.h"
  14. #include "APIDispatcher.h"
  15. #include "APIRequest.h"
  16. #include "SingleThreadedExecution.h"
  17. #include "StatusCode.h"
  18. // --------------------------------------------------------------------------
  19. // CAPIDispatcher::CAPIDispatcher
  20. //
  21. // Arguments: hClientProcess = HANDLE to the client process.
  22. //
  23. // Returns: <none>
  24. //
  25. // Purpose: Constructor for CAPIDispatcher. The handle to the client
  26. // process is transferred to this object.
  27. //
  28. // History: 1999-11-07 vtan created
  29. // 2000-08-25 vtan moved from Neptune to Whistler
  30. // --------------------------------------------------------------------------
  31. CAPIDispatcher::CAPIDispatcher (HANDLE hClientProcess) :
  32. _hSection(NULL),
  33. _pSection(NULL),
  34. _hProcessClient(hClientProcess),
  35. _hPort(NULL),
  36. _fRequestsPending(false),
  37. _fConnectionClosed(false),
  38. _pAPIDispatchSync(NULL)
  39. {
  40. }
  41. // --------------------------------------------------------------------------
  42. // CAPIDispatcher::~CAPIDispatcher
  43. //
  44. // Arguments: <none>
  45. //
  46. // Returns: <none>
  47. //
  48. // Purpose: Destructor for CAPIDispatcher. Release the port handle if
  49. // present. Release the process handle.
  50. //
  51. // History: 1999-11-07 vtan created
  52. // 2000-08-25 vtan moved from Neptune to Whistler
  53. // --------------------------------------------------------------------------
  54. CAPIDispatcher::~CAPIDispatcher (void)
  55. {
  56. ASSERTMSG(_fConnectionClosed, "Destructor invoked without connection being closed in CAPIDispatcher::~CAPIDispatcher");
  57. if (_pSection != NULL)
  58. {
  59. TBOOL(UnmapViewOfFile(_pSection));
  60. _pSection = NULL;
  61. }
  62. ReleaseHandle(_hSection);
  63. ReleaseHandle(_hPort);
  64. ReleaseHandle(_hProcessClient);
  65. }
  66. // --------------------------------------------------------------------------
  67. // CAPIDispatcher::GetClientProcess
  68. //
  69. // Arguments: <none>
  70. //
  71. // Returns: HANDLE
  72. //
  73. // Purpose: Returns the handle to the client process. This is not
  74. // duplicated. DO NOT CLOSE THIS HANDLE.
  75. //
  76. // History: 1999-11-07 vtan created
  77. // 2000-08-25 vtan moved from Neptune to Whistler
  78. // --------------------------------------------------------------------------
  79. HANDLE CAPIDispatcher::GetClientProcess (void) const
  80. {
  81. return(_hProcessClient);
  82. }
  83. // --------------------------------------------------------------------------
  84. // CAPIDispatcher::GetClientSessionID
  85. //
  86. // Arguments: <none>
  87. //
  88. // Returns: DWORD
  89. //
  90. // Purpose: Returns the client session ID.
  91. //
  92. // History: 2000-11-11 vtan created
  93. // --------------------------------------------------------------------------
  94. DWORD CAPIDispatcher::GetClientSessionID (void) const
  95. {
  96. DWORD dwSessionID;
  97. ULONG ulReturnLength;
  98. PROCESS_SESSION_INFORMATION processSessionInformation;
  99. if (NT_SUCCESS(NtQueryInformationProcess(_hProcessClient,
  100. ProcessSessionInformation,
  101. &processSessionInformation,
  102. sizeof(processSessionInformation),
  103. &ulReturnLength)))
  104. {
  105. dwSessionID = processSessionInformation.SessionId;
  106. }
  107. else
  108. {
  109. dwSessionID = 0;
  110. }
  111. return(dwSessionID);
  112. }
  113. // --------------------------------------------------------------------------
  114. // CAPIDispatcher::SetPort
  115. //
  116. // Arguments: hPort = Reply port received from
  117. // ntdll!NtAcceptConnectionPort.
  118. //
  119. // Returns: <none>
  120. //
  121. // Purpose: Sets the given port handle into this object. The handle
  122. // ownership is transferred. Wait until the thread processing
  123. // requests is ready before returning.
  124. //
  125. // History: 1999-11-07 vtan created
  126. // 2000-08-25 vtan moved from Neptune to Whistler
  127. // --------------------------------------------------------------------------
  128. void CAPIDispatcher::SetPort (HANDLE hPort)
  129. {
  130. _hPort = hPort;
  131. }
  132. // --------------------------------------------------------------------------
  133. // CAPIDispatcher::GetSection
  134. //
  135. // Arguments: <none>
  136. //
  137. // Returns: HANDLE
  138. //
  139. // Purpose: Returns a handle to a section used to communicate large
  140. // quantities of data from client to server. If the section has
  141. // not been created then create it.
  142. //
  143. // History: 2000-10-10 vtan created
  144. // --------------------------------------------------------------------------
  145. HANDLE CAPIDispatcher::GetSection (void)
  146. {
  147. if (_hSection == NULL)
  148. {
  149. TSTATUS(CreateSection());
  150. }
  151. return(_hSection);
  152. }
  153. // --------------------------------------------------------------------------
  154. // CAPIDispatcher::GetSectionAddress
  155. //
  156. // Arguments: <none>
  157. //
  158. // Returns: void*
  159. //
  160. // Purpose: Returns the mapped address of the section.
  161. //
  162. // History: 2000-10-10 vtan created
  163. // --------------------------------------------------------------------------
  164. void* CAPIDispatcher::GetSectionAddress (void) const
  165. {
  166. return(_pSection);
  167. }
  168. // --------------------------------------------------------------------------
  169. // CAPIDispatcher::CloseConnection
  170. //
  171. // Arguments: <none>
  172. //
  173. // Returns: NTSTATUS
  174. //
  175. // Purpose: Sets the member variable indicating the dispatcher's port has
  176. // been closed and that any pending requests are now invalid.
  177. // The object is reference counted so if there are any pending
  178. // requests they will release their reference when they're done.
  179. // The caller of this function releases its reference.
  180. //
  181. // History: 1999-11-07 vtan created
  182. // 2000-08-25 vtan moved from Neptune to Whistler
  183. // 2000-11-08 vtan reference counted object
  184. // --------------------------------------------------------------------------
  185. NTSTATUS CAPIDispatcher::CloseConnection (void)
  186. {
  187. CSingleThreadedExecution requestsPendingLock(_lock);
  188. _fConnectionClosed = true;
  189. return(STATUS_SUCCESS);
  190. }
  191. // --------------------------------------------------------------------------
  192. // CAPIDispatcher::QueueRequest
  193. //
  194. // Arguments: portMessage = CPortMessage of request.
  195. //
  196. // Returns: NTSTATUS
  197. //
  198. // Purpose: Checks if the connection has been closed. If closed then it
  199. // rejects the request. Otherwise it queues it.
  200. //
  201. // History: 2000-12-02 vtan created
  202. // 2002-03-21 scotthan Copy APIDispatchSync address,
  203. // update count of queued requests
  204. // --------------------------------------------------------------------------
  205. NTSTATUS CAPIDispatcher::QueueRequest (const CPortMessage& portMessage, CAPIDispatchSync* pAPIDispatchSync)
  206. {
  207. NTSTATUS status;
  208. if (_fConnectionClosed)
  209. {
  210. status = RejectRequest(portMessage, STATUS_PORT_DISCONNECTED);
  211. }
  212. else
  213. {
  214. // Note: we should receive one and the same CAPIDispatchSync address for the lifetime
  215. // of this CAPIDispatcher instance. We do not own this pointer, but only maintain a copy.
  216. #ifdef DEBUG
  217. if( NULL == _pAPIDispatchSync )
  218. {
  219. #endif DEBUG
  220. _pAPIDispatchSync = pAPIDispatchSync;
  221. #ifdef DEBUG
  222. }
  223. else
  224. {
  225. ASSERTBREAKMSG(pAPIDispatchSync == _pAPIDispatchSync, "CAPIDispatcher::QueueRequest - invalid APIDispatchSync");
  226. }
  227. #endif DEBUG
  228. // track this request queue.
  229. CAPIDispatchSync::DispatchEnter(_pAPIDispatchSync);
  230. status = CreateAndQueueRequest(portMessage);
  231. // on failure to queue the request, remove counter reference.
  232. if( !NT_SUCCESS(status) )
  233. {
  234. CAPIDispatchSync::DispatchLeave(_pAPIDispatchSync);
  235. }
  236. }
  237. return(status);
  238. }
  239. // --------------------------------------------------------------------------
  240. // CAPIDispatcher::ExecuteRequest
  241. //
  242. // Arguments: portMessage = CPortMessage of request.
  243. //
  244. // Returns: NTSTATUS
  245. //
  246. // Purpose: Checks if the connection has been closed. If closed then it
  247. // rejects the request. Otherwise it executes it.
  248. //
  249. // History: 2000-12-02 vtan created
  250. // --------------------------------------------------------------------------
  251. NTSTATUS CAPIDispatcher::ExecuteRequest (const CPortMessage& portMessage)
  252. {
  253. NTSTATUS status;
  254. if (_fConnectionClosed)
  255. {
  256. status = RejectRequest(portMessage, STATUS_PORT_DISCONNECTED);
  257. }
  258. else
  259. {
  260. status = CreateAndExecuteRequest(portMessage);
  261. }
  262. return(status);
  263. }
  264. // --------------------------------------------------------------------------
  265. // CAPIDispatcher::RejectRequest
  266. //
  267. // Arguments: portMessage = CPortMessage of request.
  268. //
  269. // Returns: NTSTATUS
  270. //
  271. // Purpose: Sends back a reply to the caller STATUS_PORT_DISCONNECTED to
  272. // reject the request.
  273. //
  274. // History: 2000-12-02 vtan created
  275. // --------------------------------------------------------------------------
  276. NTSTATUS CAPIDispatcher::RejectRequest (const CPortMessage& portMessage, NTSTATUS status) const
  277. {
  278. CPortMessage portMessageOut(portMessage);
  279. // Send the message back to the client.
  280. portMessageOut.SetDataLength(sizeof(NTSTATUS));
  281. portMessageOut.SetReturnCode(status);
  282. return(SendReply(portMessageOut));
  283. }
  284. // --------------------------------------------------------------------------
  285. // CAPIDispatcher::Entry
  286. //
  287. // Arguments: <none>
  288. //
  289. // Returns: <none>
  290. //
  291. // Purpose: Main entry point for processing LPC requests. If there are
  292. // pending requests in the queue pick them off and process them.
  293. // While processing them more items can get queued. Keep
  294. // processing until there are no more queued items. There is a
  295. // possible overlap where a newly queued item can be missed. In
  296. // that case a new work item is queued to execute those requests.
  297. //
  298. // History: 1999-11-07 vtan created
  299. // 2000-08-25 vtan moved from Neptune to Whistler
  300. // 2002-03-21 scotthan Add queue synchronization via CAPIDispatchSynch.
  301. // --------------------------------------------------------------------------
  302. void CAPIDispatcher::Entry (void)
  303. {
  304. CAPIRequest *pAPIRequest;
  305. // artificial addref our dispatch sync to prevent us from signalling prematurely,
  306. // before we can safely allow ourselves to be destroyed by our parent APIConnection.
  307. CAPIDispatchSync::DispatchEnter(_pAPIDispatchSync);
  308. // Acquire the requests pending lock before fetching the first
  309. // request. This will ensure an accurate result.
  310. _lock.Acquire();
  311. pAPIRequest = static_cast<CAPIRequest*>(_queue.Get());
  312. // If there are more requests in the queue keep looping.
  313. while (pAPIRequest != NULL)
  314. {
  315. // Release the requests pending lock to allow more requests to
  316. // get queued to this dispatcher while the dispatch is executing.
  317. if (!_fConnectionClosed)
  318. {
  319. NTSTATUS status;
  320. // Before executing the API request release the lock to allow
  321. // more requests to get queued while executing this one.
  322. _lock.Release();
  323. // Execute the request.
  324. status = Execute(pAPIRequest);
  325. // Acquire the requests pending lock again before getting
  326. // the next available request. If the loop continues the
  327. // lock will be released at the top of the loop. If the loop
  328. // exits then the lock must be released outside.
  329. _lock.Acquire();
  330. // On debug builds ignore STATUS_REPLY_MESSAGE_MISMATCH.
  331. // This typically happens on stress machines where timing
  332. // causes the thread waiting on the reply to go away before
  333. // the service has a chance to reply to the LPC request.
  334. #ifdef DEBUG
  335. if (!_fConnectionClosed && !ExcludedStatusCodeForDebug(status))
  336. {
  337. TSTATUS(status);
  338. }
  339. #endif /* DEBUG */
  340. }
  341. // Remove this processed request.
  342. _queue.Remove();
  343. // Decrement dispatch sync object. The matching DispatchEnter()
  344. // took place at time of queuing, in CAPIDispatcher::QueueRequest().
  345. CAPIDispatchSync::DispatchLeave(_pAPIDispatchSync);
  346. // Get the next request. A request may have been queued while
  347. // processing the request just processed. So keep looping until
  348. // there really are no requests left.
  349. pAPIRequest = static_cast<CAPIRequest*>(_queue.Get());
  350. }
  351. // Set the state to no longer processing requests so that any
  352. // further queued requests will cause the dispatcher to be
  353. // re-invoked in a new worker thread. Release the lock.
  354. _fRequestsPending = false;
  355. _lock.Release();
  356. // remove defensive addref
  357. CAPIDispatchSync::DispatchLeave(_pAPIDispatchSync);
  358. }
  359. // --------------------------------------------------------------------------
  360. // CAPIDispatcher::Execute
  361. //
  362. // Arguments: pAPIRequest = API request to execute.
  363. //
  364. // Returns: NTSTATUS
  365. //
  366. // Purpose: Execute the API request. This can be done from a queued work
  367. // item executing on a different thread or execute in the server
  368. // port listen thread.
  369. //
  370. // History: 2000-10-19 vtan created
  371. // --------------------------------------------------------------------------
  372. NTSTATUS CAPIDispatcher::Execute (CAPIRequest *pAPIRequest) const
  373. {
  374. NTSTATUS status;
  375. // Set the return data size to NTSTATUS by default. Execute the
  376. // request. Store the result. If the executed function has more
  377. // data to return it will set the size itself.
  378. pAPIRequest->SetDataLength(sizeof(NTSTATUS));
  379. // Protect the execution with an exception block. If the code
  380. // throws an exception it would normally just kill the worker
  381. // thread. However, the CAPIDispatcher would be left in a state
  382. // where it was marked as still executing requests even though
  383. // the thread died. If an exception is thrown the function is
  384. // considered unsuccessful.
  385. __try
  386. {
  387. status = pAPIRequest->Execute(_pAPIDispatchSync);
  388. }
  389. __except (DispatcherExceptionFilter(GetExceptionInformation()))
  390. {
  391. status = STATUS_UNSUCCESSFUL;
  392. }
  393. pAPIRequest->SetReturnCode(status);
  394. // Reply to the client with the result.
  395. return(SendReply(*pAPIRequest));
  396. }
  397. // --------------------------------------------------------------------------
  398. // CAPIDispatcher::CreateSection
  399. //
  400. // Arguments: <none>
  401. //
  402. // Returns: NTSTATUS
  403. //
  404. // Purpose: Overridable function that creates a section object. Because
  405. // size is not determinable it can be inheritable.
  406. //
  407. // The default implementation does nothing.
  408. //
  409. // History: 2000-10-10 vtan created
  410. // --------------------------------------------------------------------------
  411. NTSTATUS CAPIDispatcher::CreateSection (void)
  412. {
  413. return(STATUS_NOT_IMPLEMENTED);
  414. }
  415. // --------------------------------------------------------------------------
  416. // CAPIDispatcher::SignalRequestPending
  417. //
  418. // Arguments: <none>
  419. //
  420. // Returns: NTSTATUS
  421. //
  422. // Purpose: Signals the event to wake up the thread processing requests.
  423. //
  424. // History: 1999-11-07 vtan created
  425. // 2000-08-25 vtan moved from Neptune to Whistler
  426. // --------------------------------------------------------------------------
  427. NTSTATUS CAPIDispatcher::SignalRequestPending (void)
  428. {
  429. NTSTATUS status;
  430. CSingleThreadedExecution requestsPendingLock(_lock);
  431. // Only check the validity of _fRequestsPending after acquiring the
  432. // lock. This will guarantee that the value of this variable is
  433. // 100% correct in a multi worker threaded environment.
  434. if (!_fRequestsPending)
  435. {
  436. _fRequestsPending = true;
  437. status = Queue();
  438. }
  439. else
  440. {
  441. status = STATUS_SUCCESS;
  442. }
  443. return(status);
  444. }
  445. // --------------------------------------------------------------------------
  446. // CAPIDispatcher::SendReply
  447. //
  448. // Arguments: portMessage = CPortMessage to send in the reply.
  449. //
  450. // Returns: NTSTATUS
  451. //
  452. // Purpose: Sends a reply to the LPC port so the caller can be unblocked.
  453. //
  454. // History: 2000-10-19 vtan created
  455. // --------------------------------------------------------------------------
  456. NTSTATUS CAPIDispatcher::SendReply (const CPortMessage& portMessage) const
  457. {
  458. return(NtReplyPort(_hPort, const_cast<PORT_MESSAGE*>(portMessage.GetPortMessage())));
  459. }
  460. #ifdef DEBUG
  461. // --------------------------------------------------------------------------
  462. // CAPIDispatcher::ExcludedStatusCodeForDebug
  463. //
  464. // Arguments: status = NTSTATUS code to check.
  465. //
  466. // Returns: bool
  467. //
  468. // Purpose: Returns whether this status code should be ignored on asserts.
  469. //
  470. // History: 2001-03-30 vtan created
  471. // --------------------------------------------------------------------------
  472. bool CAPIDispatcher::ExcludedStatusCodeForDebug (NTSTATUS status)
  473. {
  474. return((status == STATUS_REPLY_MESSAGE_MISMATCH) ||
  475. (status == STATUS_INVALID_CID));
  476. }
  477. #endif /* DEBUG */
  478. // --------------------------------------------------------------------------
  479. // CAPIDispatcher::DispatcherExceptionFilter
  480. //
  481. // Arguments: <none>
  482. //
  483. // Returns: LONG
  484. //
  485. // Purpose: Filters exceptions that occur when dispatching API requests.
  486. //
  487. // History: 2000-10-13 vtan created
  488. // --------------------------------------------------------------------------
  489. LONG WINAPI CAPIDispatcher::DispatcherExceptionFilter (struct _EXCEPTION_POINTERS *pExceptionInfo)
  490. {
  491. (LONG)RtlUnhandledExceptionFilter(pExceptionInfo);
  492. return(EXCEPTION_EXECUTE_HANDLER);
  493. }
  494. // --------------------------------------------------------------------------
  495. // CAPIDispatchSync impl
  496. // History: 2002-03-18 scotthan created.
  497. // --------------------------------------------------------------------------
  498. // --------------------------------------------------------------------------
  499. CAPIDispatchSync::CAPIDispatchSync()
  500. : _cDispatches(0)
  501. , _hServiceStopping(NULL)
  502. , _hZeroDispatches(NULL)
  503. , _hPortShutdown(NULL)
  504. , _hServiceControlStop(NULL)
  505. {
  506. if( !InitializeCriticalSectionAndSpinCount(&_cs, 0) )
  507. {
  508. ZeroMemory(&_cs, sizeof(_cs));
  509. }
  510. _hServiceStopping = CreateEvent(NULL, TRUE /* manual-rest */, FALSE /* unsignalled */, NULL);
  511. _hZeroDispatches = CreateEvent(NULL, TRUE /* manual-rest */, TRUE /* signalled */, NULL);
  512. _hPortShutdown = CreateEvent(NULL, FALSE /* auto-reset */, FALSE /* unsignalled */, NULL);
  513. _hServiceControlStop = CreateEvent(NULL, FALSE /* auto-reset */, FALSE /* unsignalled */, NULL);
  514. }
  515. // --------------------------------------------------------------------------
  516. CAPIDispatchSync::~CAPIDispatchSync()
  517. {
  518. HANDLE h;
  519. h = _hServiceStopping;
  520. _hServiceStopping = NULL;
  521. if( h )
  522. {
  523. CloseHandle(h);
  524. }
  525. h = _hZeroDispatches;
  526. _hZeroDispatches = NULL;
  527. if( h )
  528. {
  529. CloseHandle(h);
  530. }
  531. h = _hPortShutdown;
  532. _hPortShutdown = NULL;
  533. if( h )
  534. {
  535. CloseHandle(h);
  536. }
  537. h = _hServiceControlStop;
  538. _hServiceControlStop = NULL;
  539. if( h )
  540. {
  541. CloseHandle(h);
  542. }
  543. if( _cs.DebugInfo )
  544. {
  545. DeleteCriticalSection(&_cs);
  546. }
  547. }
  548. // --------------------------------------------------------------------------
  549. void CAPIDispatchSync::SignalServiceStopping(CAPIDispatchSync* pds)
  550. {
  551. if( pds )
  552. {
  553. pds->Lock();
  554. if( pds->_hServiceStopping )
  555. {
  556. SetEvent(pds->_hServiceStopping);
  557. }
  558. pds->Unlock();
  559. }
  560. }
  561. // --------------------------------------------------------------------------
  562. BOOL CAPIDispatchSync::IsServiceStopping(CAPIDispatchSync* pds)
  563. {
  564. BOOL fRet = FALSE;
  565. if( pds )
  566. {
  567. if( pds->_hServiceStopping )
  568. {
  569. fRet = (WaitForSingleObject(pds->_hPortShutdown, 0) != WAIT_TIMEOUT);
  570. }
  571. }
  572. return fRet;
  573. }
  574. // --------------------------------------------------------------------------
  575. HANDLE CAPIDispatchSync::GetServiceStoppingEvent(CAPIDispatchSync* pds)
  576. {
  577. return pds ? pds->_hServiceStopping : NULL;
  578. }
  579. // --------------------------------------------------------------------------
  580. void CAPIDispatchSync::DispatchEnter(CAPIDispatchSync* pds)
  581. {
  582. if( pds )
  583. {
  584. pds->Lock();
  585. if( (++(pds->_cDispatches) > 0) && pds->_hZeroDispatches )
  586. {
  587. ResetEvent(pds->_hZeroDispatches);
  588. }
  589. pds->Unlock();
  590. }
  591. }
  592. // --------------------------------------------------------------------------
  593. void CAPIDispatchSync::DispatchLeave(CAPIDispatchSync* pds)
  594. {
  595. if( pds )
  596. {
  597. pds->Lock();
  598. if( (--(pds->_cDispatches) == 0) && pds->_hZeroDispatches )
  599. {
  600. SetEvent(pds->_hZeroDispatches);
  601. }
  602. ASSERTMSG(pds->_cDispatches >= 0, "CAPIDispatchSync::Leave - refcount < 0: Mismatched Enter/Leave");
  603. pds->Unlock();
  604. }
  605. }
  606. // --------------------------------------------------------------------------
  607. DWORD CAPIDispatchSync::WaitForZeroDispatches(CAPIDispatchSync* pds, DWORD dwTimeout)
  608. {
  609. if( pds )
  610. {
  611. if( pds->_hZeroDispatches )
  612. {
  613. return WaitForSingleObject(pds->_hZeroDispatches, dwTimeout);
  614. }
  615. }
  616. return WAIT_ABANDONED;
  617. }
  618. // --------------------------------------------------------------------------
  619. void CAPIDispatchSync::SignalPortShutdown(CAPIDispatchSync* pds)
  620. {
  621. if( pds )
  622. {
  623. pds->Lock();
  624. if( pds->_hPortShutdown )
  625. {
  626. SetEvent(pds->_hPortShutdown);
  627. }
  628. pds->Unlock();
  629. }
  630. }
  631. // --------------------------------------------------------------------------
  632. DWORD CAPIDispatchSync::WaitForPortShutdown(CAPIDispatchSync* pds, DWORD dwTimeout)
  633. {
  634. if( pds )
  635. {
  636. if( pds->_hPortShutdown )
  637. {
  638. return WaitForSingleObject(pds->_hPortShutdown, dwTimeout);
  639. }
  640. }
  641. return WAIT_ABANDONED;
  642. }
  643. // --------------------------------------------------------------------------
  644. void CAPIDispatchSync::SignalServiceControlStop(CAPIDispatchSync* pds)
  645. {
  646. if( pds )
  647. {
  648. pds->Lock();
  649. if( pds->_hServiceControlStop )
  650. {
  651. SetEvent(pds->_hServiceControlStop);
  652. }
  653. pds->Unlock();
  654. }
  655. }
  656. // --------------------------------------------------------------------------
  657. DWORD CAPIDispatchSync::WaitForServiceControlStop(CAPIDispatchSync* pds, DWORD dwTimeout)
  658. {
  659. if( pds )
  660. {
  661. if( pds->_hServiceControlStop )
  662. {
  663. return WaitForSingleObject(pds->_hServiceControlStop, dwTimeout);
  664. }
  665. }
  666. return WAIT_ABANDONED;
  667. }
  668. // --------------------------------------------------------------------------
  669. void CAPIDispatchSync::Lock()
  670. {
  671. if( _cs.DebugInfo )
  672. {
  673. EnterCriticalSection(&_cs);
  674. }
  675. }
  676. // --------------------------------------------------------------------------
  677. void CAPIDispatchSync::Unlock()
  678. {
  679. if( _cs.DebugInfo )
  680. {
  681. LeaveCriticalSection(&_cs);
  682. }
  683. }