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.

1049 lines
28 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: dmnslave.cxx
  7. //
  8. // Contents: The slave thread that executes executes commands on behalf of
  9. // the DownLevel daemon process.
  10. //
  11. // History: 1-31-96 srikants Created
  12. // 1-06-97 srikants Renamed to dmnslave.cxx from dlslave.cxx
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <cci.hxx>
  18. #include <glbconst.hxx>
  19. #include "dmnslave.hxx"
  20. #include "cimanger.hxx"
  21. const WCHAR * wcsCiDaemonImage = L"%systemroot%\\system32\\cidaemon.exe";
  22. //+---------------------------------------------------------------------------
  23. //
  24. // Member: CDaemonSlave::GetInheritableHandle
  25. //
  26. // Synopsis: Creates an inheritable handle of this process for
  27. // synchronization purposes only.
  28. //
  29. // Arguments: [hTarget] - The inherited handle.
  30. //
  31. // Returns: STATUS_SUCCESS if successful.
  32. // An error code otherwise.
  33. //
  34. // History: 2-02-96 srikants Created
  35. //
  36. //----------------------------------------------------------------------------
  37. DWORD CDaemonSlave::GetInheritableHandle( HANDLE & hTarget )
  38. {
  39. HANDLE hSelf = GetCurrentProcess();
  40. BOOL fSuccess = DuplicateHandle( hSelf, // source process
  41. hSelf, // source handle
  42. hSelf, // destination process
  43. &hTarget, // target handle
  44. SYNCHRONIZE, // desired access
  45. TRUE, // inheritable
  46. 0 // dwOptions
  47. );
  48. if (fSuccess)
  49. return STATUS_SUCCESS;
  50. return GetLastError();
  51. } //GetInheritableHandle
  52. //+---------------------------------------------------------------------------
  53. //
  54. // Member: CDaemonSlave::CDaemonSlave ~ctor
  55. //
  56. // Synopsis: Constructor of the class that is manages the slave thread
  57. // in CI. This thread will execute the commands specified by
  58. // the DownLevel Daemon process.
  59. //
  60. // Arguments: [cicat] -
  61. // [pwcsCatRoot] - Catalog path.
  62. // [nameGen] - mutex name
  63. // [pwcsCatName] - 0 or the friendly name
  64. //
  65. // History: 1-31-96 srikants Created
  66. //
  67. //----------------------------------------------------------------------------
  68. CDaemonSlave::CDaemonSlave(
  69. CCiManager & ciManager,
  70. CCI * pCci,
  71. WCHAR const * pwcsCatRoot,
  72. CSharedNameGen & nameGen,
  73. const GUID & clsidDaemonClientMgr)
  74. : _ciManager(ciManager),
  75. _pCci(pCci),
  76. #pragma warning( disable : 4355 ) // this used in base initialization
  77. _thrSlave(SlaveThread, this, TRUE),
  78. #pragma warning( default : 4355 )
  79. _fAbort(FALSE),
  80. _smemMutex( nameGen.GetMutexName() ),
  81. _sharedMem( nameGen.GetSharedMemName(),MAX_DL_SHARED_MEM),
  82. _evtCi( nameGen.GetCiEventName() ),
  83. _evtDaemon( nameGen.GetDaemonEventName() ),
  84. _pProcess(0),
  85. _hParent(INVALID_HANDLE_VALUE),
  86. _state(eDeathNotified),
  87. _daemonExitStatus(0),
  88. _cbStartupData(0),
  89. _clsidDaemonClientMgr(clsidDaemonClientMgr)
  90. {
  91. //
  92. // Initialize both the events to be in an "unsignalled" state.
  93. //
  94. _evtCi.Reset();
  95. _evtDaemon.Reset();
  96. //
  97. // Initialize the shared memory.
  98. //
  99. _pLayout = (CFilterSharedMemLayout *) _sharedMem.Map();
  100. _pLayout->Init();
  101. Win4Assert( 0 != pwcsCatRoot );
  102. ULONG len = wcslen( pwcsCatRoot );
  103. _wszCatRoot.Init( len+1 );
  104. RtlCopyMemory( _wszCatRoot.GetPointer(), pwcsCatRoot, (len+1) * sizeof(WCHAR) );
  105. DWORD dwError = GetInheritableHandle( _hParent );
  106. if ( STATUS_SUCCESS != dwError )
  107. {
  108. ciDebugOut(( DEB_ERROR, "Cannot duplicate a handle to self. Error 0x%X\n",
  109. dwError ));
  110. THROW( CException( HRESULT_FROM_WIN32( dwError) ) );
  111. }
  112. Win4Assert( INVALID_HANDLE_VALUE != _hParent );
  113. SHandle xSafeHandle(_hParent);
  114. //
  115. // First resume the slave thread and then resume the daemon process.
  116. // The slave should run at a lower priority than queries.
  117. //
  118. if ( IDLE_PRIORITY_CLASS == _ciManager._GetFrameworkParams().GetThreadClassFilter() )
  119. {
  120. _thrSlave.SetPriority( THREAD_PRIORITY_BELOW_NORMAL );
  121. }
  122. else
  123. {
  124. _thrSlave.SetPriority( THREAD_PRIORITY_NORMAL );
  125. }
  126. _thrSlave.Resume();
  127. xSafeHandle.Acquire();
  128. END_CONSTRUCTION( CDaemonSlave );
  129. }
  130. //+---------------------------------------------------------------------------
  131. //
  132. // Member: CDaemonSlave::StartFiltering
  133. //
  134. // Synopsis: Signal to indicate that it is okay to start the daemon
  135. // process.
  136. //
  137. // History: 12-30-96 srikants Created
  138. //
  139. //----------------------------------------------------------------------------
  140. void CDaemonSlave::StartFiltering(
  141. BYTE const * pbStartupData,
  142. ULONG cbStartupData )
  143. {
  144. // ====================================================
  145. CLock lock(_mutex);
  146. if ( eReadyToStart == _state || eRunning == _state )
  147. return;
  148. if ( eDeathNotified != _state )
  149. {
  150. ciDebugOut(( DEB_ERROR,
  151. "StartFiltering called in an invalid state (%d)\n",
  152. _state ));
  153. THROW( CException( CI_E_INVALID_STATE ) );
  154. }
  155. //
  156. // Make a local copy of the startup data.
  157. //
  158. if ( _xbStartupData.Count() < cbStartupData )
  159. {
  160. _xbStartupData.Free();
  161. _xbStartupData.Set( cbStartupData,
  162. new BYTE [cbStartupData] );
  163. }
  164. RtlCopyMemory( _xbStartupData.GetPointer(), pbStartupData, cbStartupData );
  165. _cbStartupData = cbStartupData;
  166. _state = eReadyToStart;
  167. _evtCi.Set();
  168. // ====================================================
  169. }
  170. //+---------------------------------------------------------------------------
  171. //
  172. // Member: CDaemonSlave::StartProcess
  173. //
  174. // Synopsis: Creates the DL daemon process if it is not already started.
  175. //
  176. // History: 1-31-96 srikants Created
  177. //
  178. //----------------------------------------------------------------------------
  179. void CDaemonSlave::StartProcess()
  180. {
  181. if ( 0 == _pProcess )
  182. {
  183. WCHAR wszCommandLine[ MAX_PATH + 50 ];
  184. swprintf( wszCommandLine,L"%ls %ls \"%ls\" %ul %ul",
  185. DL_DAEMON_EXE_NAME,
  186. DL_DAEMON_ARG1_W,
  187. _wszCatRoot.GetPointer(),
  188. _sharedMem.SizeLow(),
  189. GetCurrentProcessId() );
  190. XInterface<ICiCAdviseStatus> xAdviseStatus;
  191. SCODE sc = _ciManager._xDocStore->QueryInterface( IID_ICiCAdviseStatus,
  192. xAdviseStatus.GetQIPointer() );
  193. if ( S_OK != sc )
  194. {
  195. Win4Assert( xAdviseStatus.IsNull() );
  196. THROW( CException( sc ) );
  197. }
  198. SECURITY_ATTRIBUTES *pSA = 0;
  199. _pProcess = new CProcess( DL_DAEMON_EXE_NAME,
  200. wszCommandLine,
  201. TRUE, // suspended
  202. *pSA,
  203. FALSE, // make it detached
  204. xAdviseStatus.GetPointer() );
  205. TRY
  206. {
  207. _pProcess->AddDacl( GENERIC_ALL );
  208. }
  209. CATCH( CException, e )
  210. {
  211. //
  212. // If we can't add the DACL, then delete the process and rethrow
  213. // the exception.
  214. //
  215. delete _pProcess;
  216. _pProcess = 0;
  217. RETHROW();
  218. }
  219. END_CATCH
  220. }
  221. } //StartProcess
  222. //+---------------------------------------------------------------------------
  223. //
  224. // Member: CDaemonSlave::~CDaemonSlave
  225. //
  226. // Synopsis: Destructor of the CDaemonSlave class. Kills the slave thread
  227. // and then kills the daemon process.
  228. //
  229. // History: 1-31-96 srikants Created
  230. //
  231. //----------------------------------------------------------------------------
  232. CDaemonSlave::~CDaemonSlave()
  233. {
  234. _fAbort = TRUE;
  235. //
  236. // Kill the thread first. Otherwise, the process will be recreated
  237. // by the thread.
  238. //
  239. KillThread();
  240. KillProcess();
  241. //
  242. // Close the handle to ourselves.
  243. //
  244. CloseHandle(_hParent);
  245. }
  246. //+---------------------------------------------------------------------------
  247. //
  248. // Member: CDaemonSlave::KillProcess
  249. //
  250. // Synopsis: Kills the downlevel daemon process.
  251. //
  252. // History: 1-31-96 srikants Created
  253. //
  254. //----------------------------------------------------------------------------
  255. void CDaemonSlave::KillProcess()
  256. {
  257. // =====================================================
  258. CLock lock(_mutex);
  259. if ( _pProcess )
  260. {
  261. //
  262. // Get the process exit code.
  263. //
  264. SaveDaemonExitCode();
  265. TRY
  266. {
  267. delete _pProcess;
  268. _pProcess = 0;
  269. _state = eDied;
  270. _ciManager.ProcessCiDaemonTermination( _daemonExitStatus );
  271. _state = eDeathNotified;
  272. }
  273. CATCH ( CException, e )
  274. {
  275. ciDebugOut(( DEB_ERROR, "Error while killing process. 0x%X\n",
  276. e.GetErrorCode() ));
  277. }
  278. END_CATCH
  279. _evtCi.Reset();
  280. _pProcess = 0;
  281. }
  282. //
  283. // The process has either not started at all (_pProcess==0), or it has been notified, or it
  284. // has died.
  285. //
  286. Win4Assert( eReadyToStart == _state
  287. || eDeathNotified == _state
  288. || eDied == _state );
  289. // =====================================================
  290. }
  291. //+---------------------------------------------------------------------------
  292. //
  293. // Member: CDaemonSlave::RestartDaemon
  294. //
  295. // Synopsis: Starts the daemon process.
  296. //
  297. // History: 1-31-96 srikants Created
  298. //
  299. //----------------------------------------------------------------------------
  300. void CDaemonSlave::RestartDaemon()
  301. {
  302. Win4Assert( eReadyToStart == _state );
  303. StartProcess();
  304. _pProcess->Resume();
  305. }
  306. //+---------------------------------------------------------------------------
  307. //
  308. // Member: CDaemonSlave::KillThread
  309. //
  310. // Synopsis: Kills the slave thread.
  311. //
  312. // History: 1-31-96 srikants Created
  313. //
  314. //----------------------------------------------------------------------------
  315. void CDaemonSlave::KillThread()
  316. {
  317. _evtCi.Set();
  318. _thrSlave.WaitForDeath();
  319. }
  320. //+---------------------------------------------------------------------------
  321. //
  322. // Member: CDaemonSlave::InitiateShutdown
  323. //
  324. // Synopsis: Initiates the shutdown of the slave thread.
  325. //
  326. // History: 12-30-96 srikants Added comment header.
  327. //
  328. //----------------------------------------------------------------------------
  329. void CDaemonSlave::InitiateShutdown()
  330. {
  331. _fAbort = TRUE;
  332. _evtCi.Set();
  333. }
  334. //+---------------------------------------------------------------------------
  335. //
  336. // Member: CDaemonSlave::SlaveThread
  337. //
  338. // Synopsis: The slave thread in CI.
  339. //
  340. // Arguments: [self] -
  341. //
  342. // History: 1-31-96 srikants Created
  343. //
  344. //----------------------------------------------------------------------------
  345. DWORD CDaemonSlave::SlaveThread( void * self )
  346. {
  347. ((CDaemonSlave *) self)->DoWork();
  348. return 0;
  349. }
  350. //+---------------------------------------------------------------------------
  351. //
  352. // Member: CDaemonSlave::FilterReady
  353. //
  354. // Synopsis: Executes the FilterReady() call on behalf of the DL Daemon.
  355. //
  356. // Returns: Status of the operation.
  357. //
  358. // History: 1-31-96 srikants Created
  359. //
  360. //----------------------------------------------------------------------------
  361. SCODE CDaemonSlave::FilterReady()
  362. {
  363. CFilterReadyLayout & data = _pLayout->GetFilterReady();
  364. Win4Assert( data.IsValid() );
  365. SCODE status = S_OK;
  366. Win4Assert( 0 != _pCci );
  367. ULONG cb = 0;
  368. do
  369. {
  370. cb = data.GetCount();
  371. BYTE * docBuffer = data.GetBuffer();
  372. ULONG cMaxDocs = data.GetMaxDocs();
  373. if ( 0 != _pCci )
  374. {
  375. status = _pCci->FilterReady( docBuffer, cb, cMaxDocs );
  376. }
  377. else
  378. {
  379. status = STATUS_NOT_FOUND;
  380. }
  381. _ciManager._HandleFilterReadyStatus( status );
  382. }
  383. while ( FILTER_S_DISK_FULL == status );
  384. data.SetCount( cb );
  385. return status;
  386. }
  387. //+---------------------------------------------------------------------------
  388. //
  389. // Member: CDaemonSlave::FilterMore
  390. //
  391. // Synopsis: Executes the FilterMore() call.
  392. //
  393. // History: 1-31-96 srikants Created
  394. //
  395. //----------------------------------------------------------------------------
  396. SCODE CDaemonSlave::FilterMore()
  397. {
  398. CFilterMoreDoneLayout & data = _pLayout->GetFilterMore();
  399. Win4Assert( data.IsValid() );
  400. SCODE status = S_OK;
  401. Win4Assert( 0 != _pCci );
  402. if ( 0 != _pCci )
  403. {
  404. STATUS const * pStatus = data.GetStatusArray();
  405. ULONG cStatus = data.GetCount();
  406. status = _pCci->FilterMore( pStatus, cStatus );
  407. }
  408. else
  409. {
  410. status = STATUS_NOT_FOUND;
  411. }
  412. return status;
  413. }
  414. //+---------------------------------------------------------------------------
  415. //
  416. // Member: CDaemonSlave::FilterDataReady
  417. //
  418. // History: 1-31-96 srikants Created
  419. //
  420. //----------------------------------------------------------------------------
  421. SCODE CDaemonSlave::FilterDataReady()
  422. {
  423. CFilterDataLayout & data = _pLayout->GetFilterDataReady();
  424. Win4Assert( data.IsValid() );
  425. SCODE status = S_OK;
  426. Win4Assert( 0 != _pCci );
  427. if ( 0 != _pCci )
  428. {
  429. BYTE const * pEntryBuf = data.GetBuffer();
  430. ULONG cb = data.GetSize();
  431. status = _pCci->FilterDataReady( pEntryBuf, cb );
  432. }
  433. else
  434. {
  435. status = STATUS_NOT_FOUND;
  436. }
  437. return S_OK;
  438. }
  439. //+---------------------------------------------------------------------------
  440. //
  441. // Member: CDaemonSlave::FilterDone
  442. //
  443. // History: 1-31-96 srikants Created
  444. //
  445. //----------------------------------------------------------------------------
  446. SCODE CDaemonSlave::FilterDone()
  447. {
  448. CFilterMoreDoneLayout & data = _pLayout->GetFilterDone();
  449. Win4Assert( data.IsValid() );
  450. SCODE status = S_OK;
  451. Win4Assert( 0 != _pCci );
  452. if ( 0 != _pCci )
  453. {
  454. STATUS const * pStatus = data.GetStatusArray();
  455. ULONG cStatus = data.GetCount();
  456. status = _pCci->FilterDone( pStatus, cStatus );
  457. }
  458. else
  459. {
  460. status = STATUS_NOT_FOUND;
  461. }
  462. return status;
  463. }
  464. //+---------------------------------------------------------------------------
  465. //
  466. // Member: CDaemonSlave::FilterStoreValue
  467. //
  468. // History: 1-31-96 srikants Created
  469. //
  470. //----------------------------------------------------------------------------
  471. SCODE CDaemonSlave::FilterStoreValue()
  472. {
  473. CFilterStoreValueLayout & data = _pLayout->GetFilterStoreValueLayout();
  474. Win4Assert( data.IsValid() );
  475. CMemDeSerStream deSer( data.GetBuffer(), data.GetCount() );
  476. CFullPropSpec ps( deSer );
  477. if ( !ps.IsValid() )
  478. THROW( CException( E_OUTOFMEMORY ) );
  479. CStorageVariant var( deSer );
  480. if ( !var.IsValid() )
  481. THROW( CException( E_OUTOFMEMORY ) );
  482. WORKID widFake = data.GetWorkid();
  483. BOOL fSuccess;
  484. _pCci->FilterStoreValue( widFake, ps, var, fSuccess );
  485. data.SetStatus( fSuccess );
  486. return S_OK;
  487. }
  488. //+---------------------------------------------------------------------------
  489. //
  490. // Member: CDaemonSlave::FilterStoreSecurity
  491. //
  492. // History: 06 Feb 96 AlanW Created
  493. //
  494. //----------------------------------------------------------------------------
  495. SCODE CDaemonSlave::FilterStoreSecurity()
  496. {
  497. CFilterStoreSecurityLayout & data = _pLayout->GetFilterStoreSecurityLayout();
  498. Win4Assert( data.IsValid() );
  499. PSECURITY_DESCRIPTOR pSD = data.GetSD();
  500. ULONG cbSD = data.GetCount();
  501. WORKID widFake = data.GetWorkid();
  502. BOOL fSuccess;
  503. _pCci->FilterStoreSecurity( widFake, pSD, cbSD, fSuccess );
  504. data.SetStatus( fSuccess );
  505. return S_OK;
  506. } //FilterStoreSecurity
  507. //+---------------------------------------------------------------------------
  508. //
  509. // Member: CDaemonSlave::FPSToPROPID, public
  510. //
  511. // Synopsis: Converts FULLPROPSPEC to PROPID
  512. //
  513. // Returns: S_OK on success
  514. //
  515. // History: 29-Dec-1997 KyleP Created
  516. //
  517. //----------------------------------------------------------------------------
  518. SCODE CDaemonSlave::FPSToPROPID()
  519. {
  520. CFPSToPROPIDLayout & data = _pLayout->GetFPSToPROPID();
  521. Win4Assert( data.IsValid() );
  522. CMemDeSerStream deSer( data.GetBuffer(), data.GetCount() );
  523. CFullPropSpec fps( deSer );
  524. if ( !fps.IsValid() )
  525. return E_INVALIDARG;
  526. SCODE status = S_OK;
  527. Win4Assert( 0 != _pCci );
  528. if ( 0 != _pCci )
  529. {
  530. status = _pCci->FPSToPROPID( fps, *(PROPID *)data.GetBuffer() );
  531. unsigned cb;
  532. if ( SUCCEEDED(status) )
  533. cb = sizeof(PROPID);
  534. else
  535. cb = 0;
  536. data.SetCount( cb );
  537. }
  538. else
  539. {
  540. status = STATUS_NOT_FOUND;
  541. }
  542. return status;
  543. } //FPSToPROPID
  544. //+---------------------------------------------------------------------------
  545. //
  546. // Member: CDaemonSlave::GetClientStartupData
  547. //
  548. // Synopsis: Retrieves the client startup data.
  549. //
  550. // History: 12-19-96 srikants Created
  551. //
  552. //----------------------------------------------------------------------------
  553. SCODE CDaemonSlave::GetClientStartupData()
  554. {
  555. CFilterStartupDataLayout & data = _pLayout->GetStartupData();
  556. Win4Assert( data.IsValid() );
  557. SCODE status = S_OK;
  558. Win4Assert( 0 != _pCci );
  559. if ( 0 != _pCci )
  560. {
  561. data.SetData( _clsidDaemonClientMgr,
  562. _xbStartupData.GetPointer(),
  563. _cbStartupData );
  564. }
  565. else
  566. {
  567. status = STATUS_NOT_FOUND;
  568. }
  569. return status;
  570. } //GetClientStartupData
  571. //+---------------------------------------------------------------------------
  572. //
  573. // Member: CDaemonSlave::DoSlaveWork
  574. //
  575. // Synopsis: The "de-multiplexor" which figures out what work was signalled
  576. // by the daemon process.
  577. //
  578. // History: 1-31-96 srikants Created
  579. //
  580. //----------------------------------------------------------------------------
  581. void CDaemonSlave::DoSlaveWork()
  582. {
  583. if ( _fAbort )
  584. return;
  585. CIPLock lock(_smemMutex);
  586. Win4Assert( 0 != _pLayout );
  587. CFilterSharedMemLayout::EFilterWorkType workType = _pLayout->GetWorkType();
  588. SCODE status = S_OK;
  589. TRY
  590. {
  591. switch ( workType )
  592. {
  593. case CFilterSharedMemLayout::eNone:
  594. break;
  595. case CFilterSharedMemLayout::eFilterReady:
  596. {
  597. status = FilterReady();
  598. break;
  599. }
  600. case CFilterSharedMemLayout::eFilterDataReady:
  601. {
  602. status = FilterDataReady();
  603. break;
  604. }
  605. case CFilterSharedMemLayout::eFilterMore:
  606. {
  607. status = FilterMore();
  608. break;
  609. }
  610. case CFilterSharedMemLayout::eFilterDone:
  611. {
  612. status = FilterDone();
  613. break;
  614. }
  615. case CFilterSharedMemLayout::eFilterStoreValue:
  616. {
  617. status = FilterStoreValue();
  618. break;
  619. }
  620. case CFilterSharedMemLayout::eFilterStoreSecurity:
  621. {
  622. status = FilterStoreSecurity();
  623. break;
  624. }
  625. case CFilterSharedMemLayout::eFPSToPROPID:
  626. {
  627. status = FPSToPROPID();
  628. break;
  629. }
  630. case CFilterSharedMemLayout::eFilterStartupData:
  631. {
  632. status = GetClientStartupData();
  633. break;
  634. }
  635. default:
  636. ciDebugOut(( DEB_ERROR, "Unknown work code from daemon\n",
  637. workType ));
  638. Win4Assert( !"Unknown work code");
  639. status = STATUS_INVALID_PARAMETER;
  640. break;
  641. }
  642. }
  643. CATCH( CException, e )
  644. {
  645. status = e.GetErrorCode();
  646. ciDebugOut(( DEB_WARN,
  647. "Error (0x%X) caught while doing slave work\n",
  648. status ));
  649. if ( IsCiCorruptStatus( e.GetErrorCode() ) )
  650. RETHROW();
  651. }
  652. END_CATCH
  653. if ( IsDiskLowError(status) )
  654. {
  655. BOOL fLow;
  656. _pCci->VerifyIfLowOnDiskSpace(fLow);
  657. }
  658. //
  659. // Set the status of the operation and wake up the daemon process.
  660. //
  661. _pLayout->SetStatus( status );
  662. _evtDaemon.Set();
  663. } //DoSlaveWork
  664. //+---------------------------------------------------------------------------
  665. //
  666. // Member: CDaemonSlave::DoStateMachineWork
  667. //
  668. // Synopsis: Does state machine book keeping work. If necessary, it will
  669. // restart the cidaemon process.
  670. //
  671. // History: 12-30-96 srikants Created
  672. //
  673. //----------------------------------------------------------------------------
  674. void CDaemonSlave::DoStateMachineWork()
  675. {
  676. // =======================================
  677. CLock lock(_mutex);
  678. Win4Assert( eRunning != _state );
  679. if ( _state == eReadyToStart && !IsProcessLowOnResources() )
  680. {
  681. RestartDaemon();
  682. _state = eRunning;
  683. }
  684. else if ( _state == eDied )
  685. {
  686. _ciManager.ProcessCiDaemonTermination( _daemonExitStatus );
  687. _state = eDeathNotified;
  688. }
  689. // =======================================
  690. } //DoStateMachineWork
  691. //+---------------------------------------------------------------------------
  692. //
  693. // Member: CDaemonSlave::SaveDaemonExitCode
  694. //
  695. // Synopsis: Saves the exit code of the daemon process.
  696. //
  697. // History: 12-30-96 srikants Created
  698. //
  699. //----------------------------------------------------------------------------
  700. void CDaemonSlave::SaveDaemonExitCode()
  701. {
  702. Win4Assert( 0 != _pProcess );
  703. HANDLE hProcess = _pProcess->GetHandle();
  704. DWORD dwExitCode;
  705. if ( GetExitCodeProcess( hProcess, &dwExitCode ) )
  706. _daemonExitStatus = dwExitCode;
  707. else
  708. _daemonExitStatus = E_FAIL;
  709. } //SaveDaemonExitCode
  710. //+---------------------------------------------------------------------------
  711. //
  712. // Member: CDaemonSlave::IsProcessLowOnResources
  713. //
  714. // Synopsis: Tests if the daemon process died because of being low on
  715. // resources.
  716. //
  717. // Returns: Returns TRUE if the daemon process died with low resource
  718. // condition (low on memory or disk). FALSE o/w.
  719. //
  720. // History: 3-11-96 srikants Created
  721. //
  722. //----------------------------------------------------------------------------
  723. BOOL CDaemonSlave::IsProcessLowOnResources() const
  724. {
  725. Win4Assert( 0 == _pProcess );
  726. return _IsResourceLowError( _daemonExitStatus );
  727. }
  728. //+---------------------------------------------------------------------------
  729. //
  730. // Functions: IsInDebugger
  731. //
  732. // Synopsis: Tests if a process is being debugged
  733. //
  734. // Arguments: [hProcess] -- The process handle to test.
  735. //
  736. // Returns: Returns TRUE if the process is being debugged.
  737. //
  738. // History: 4-23-98 dlee Created
  739. //
  740. //----------------------------------------------------------------------------
  741. BOOL IsInDebugger( HANDLE hProcess )
  742. {
  743. PROCESS_BASIC_INFORMATION bi;
  744. NTSTATUS s = NtQueryInformationProcess( hProcess,
  745. ProcessBasicInformation,
  746. (PVOID) &bi,
  747. sizeof bi,
  748. 0 );
  749. if ( STATUS_SUCCESS != s )
  750. return FALSE;
  751. PEB Peb;
  752. if ( ReadProcessMemory( hProcess, bi.PebBaseAddress, &Peb, sizeof PEB, 0 ) )
  753. return Peb.BeingDebugged;
  754. return FALSE;
  755. } //IsInDebugger
  756. //+---------------------------------------------------------------------------
  757. //
  758. // Member: CDaemonSlave::DoWork
  759. //
  760. // Synopsis: Main worker thread.
  761. //
  762. // History: 1-31-96 srikants Created
  763. //
  764. //----------------------------------------------------------------------------
  765. void CDaemonSlave::DoWork()
  766. {
  767. const cHandles = 2;
  768. HANDLE aHandles[cHandles];
  769. const iCiWork = 0; // Index of the ci work event.
  770. const iDaemonProcess = 1; // Index of the daemon process.
  771. aHandles[iCiWork] = _evtCi.GetHandle();
  772. BOOL fContinue = TRUE;
  773. while ( fContinue )
  774. {
  775. if ( !_fAbort )
  776. {
  777. TRY
  778. {
  779. DWORD nHandles = 1;
  780. if ( 0 != _pProcess )
  781. {
  782. aHandles[iDaemonProcess] = _pProcess->GetHandle();
  783. nHandles++;
  784. }
  785. DWORD timeout = _ciManager._GetFrameworkParams().GetDaemonResponseTimeout() * 60 * 1000;
  786. DWORD status = WaitForMultipleObjects( nHandles,
  787. aHandles,
  788. FALSE,
  789. timeout );
  790. if ( WAIT_FAILED == status )
  791. {
  792. ciDebugOut(( DEB_ERROR, "WaitForMultipleObjects failed with error 0x%X\n",
  793. GetLastError() ));
  794. //
  795. // Don't restart the daemon process immediately. Wait for
  796. // the timeout period.
  797. //
  798. KillProcess();
  799. }
  800. else if ( WAIT_TIMEOUT == status )
  801. {
  802. // The process is probably looping. We should kill it and
  803. // restart.
  804. if ( eRunning == _state )
  805. {
  806. if ( 0 != _pProcess )
  807. {
  808. BOOL fDbg = IsInDebugger( _pProcess->GetHandle() );
  809. ciDebugOut(( DEB_ERROR,
  810. "Daemon is looping, killing? %s\n",
  811. fDbg ? "no" : "yes" ));
  812. if ( !fDbg )
  813. KillProcess();
  814. }
  815. }
  816. else
  817. {
  818. DoStateMachineWork();
  819. }
  820. }
  821. else
  822. {
  823. //
  824. // An event was signalled.
  825. //
  826. DWORD iWake = status - WAIT_OBJECT_0;
  827. if ( iCiWork == iWake )
  828. {
  829. //
  830. // We have been given some work. Do it.
  831. //
  832. // =========================================
  833. {
  834. CLock lock(_mutex);
  835. _evtCi.Reset();
  836. }
  837. // =========================================
  838. if ( eRunning == _state )
  839. DoSlaveWork();
  840. else
  841. DoStateMachineWork();
  842. }
  843. else if ( iDaemonProcess == iWake )
  844. {
  845. //
  846. // The daemon process died.
  847. //
  848. ciDebugOut(( DEB_ERROR, "Daemon process died\n" ));
  849. KillProcess();
  850. }
  851. }
  852. }
  853. CATCH(CException, e )
  854. {
  855. ciDebugOut(( DEB_ERROR, "Error in the Slave Thread - 0x%X\n",
  856. e.GetErrorCode() ));
  857. _ciManager.ProcessError( e.GetErrorCode() );
  858. if ( IsCiCorruptStatus( e.GetErrorCode() ) )
  859. {
  860. KillProcess();
  861. fContinue = FALSE;
  862. }
  863. }
  864. END_CATCH
  865. }
  866. else
  867. {
  868. fContinue = FALSE;
  869. }
  870. }
  871. } //DoWork