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.

887 lines
24 KiB

  1. /*-----------------------------------------------------------------------------
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name :
  4. ptable.cxx
  5. Abstract:
  6. Author:
  7. Lei Jin ( LeiJin ) 13-Oct-1998
  8. Environment:
  9. User Mode - Win32
  10. Project:
  11. W3 services DLL
  12. -----------------------------------------------------------------------------*/
  13. #include <w3p.hxx>
  14. #include "ptable.hxx"
  15. #include "waminfo.hxx"
  16. #include "comadmin.h"
  17. //#include "comadmii.c"
  18. #include "wamexec.hxx"
  19. VOID
  20. CleanupRecycledProcessEntry(
  21. VOID * pvContext
  22. );
  23. //===============================================================================
  24. /*-----------------------------------------------------------------------------
  25. CProcessEntry::CProcessEntry
  26. Constructor for a CProcessEntry.
  27. -----------------------------------------------------------------------------*/
  28. CProcessEntry::CProcessEntry
  29. (
  30. DWORD dwProcessId,
  31. HANDLE hProcessHandle,
  32. LPCWSTR wszPackageId
  33. )
  34. : m_dwSignature(0),
  35. m_dwProcessId(dwProcessId),
  36. m_hProcessHandle(hProcessHandle),
  37. m_cRefs(0),
  38. m_fCrashed(FALSE),
  39. m_fRecycling(FALSE)
  40. {
  41. DBGPRINTF((DBG_CONTEXT, "Initializing new CProcessEntry 0x%p.\r\n", this));
  42. if (wszPackageId != NULL)
  43. {
  44. wcsncpy(static_cast<WCHAR *>(m_wszPackageId), wszPackageId, 39/*uSizeofCLSIDStr*/);
  45. }
  46. InitializeListHead(&m_ListHeadOfWamInfo);
  47. g_pWamDictator->Reference();
  48. }
  49. CProcessEntry::~CProcessEntry()
  50. {
  51. g_pWamDictator->Dereference();
  52. }
  53. /*-----------------------------------------------------------------------------
  54. CProcessEntry::Release
  55. Release a reference. Call destructor if Ref count reaches zero.
  56. -----------------------------------------------------------------------------*/
  57. void CProcessEntry::Release()
  58. {
  59. LONG cRefs = InterlockedDecrement(&m_cRefs);
  60. if (cRefs == 0)
  61. {
  62. delete this;
  63. }
  64. }
  65. /*-----------------------------------------------------------------------------
  66. CProcessEntry::AddWamInfoToProcessEntry
  67. Add a WamInfo object to this ProcessEntry linklist.
  68. return TRUE.
  69. -----------------------------------------------------------------------------*/
  70. bool CProcessEntry::AddWamInfoToProcessEntry
  71. (
  72. CWamInfo* pWamInfo
  73. )
  74. {
  75. InsertHeadList(&m_ListHeadOfWamInfo, &pWamInfo->leProcess);
  76. AddRef();
  77. return TRUE;
  78. }
  79. /*-----------------------------------------------------------------------------
  80. CProcessEntry::RemoveWamInfoFromProcessEntry
  81. Remove a waminfo object from this ProcessEntry linklist.
  82. Set fDelete to TRUE if the linklist after removal is empty.
  83. return TRUE.
  84. -----------------------------------------------------------------------------*/
  85. bool CProcessEntry::RemoveWamInfoFromProcessEntry
  86. (
  87. CWamInfo* pWamInfo,
  88. bool* fDelete
  89. )
  90. {
  91. RemoveEntryList(&pWamInfo->leProcess);
  92. InitializeListHead(&pWamInfo->leProcess);
  93. Release();
  94. *fDelete = FALSE;
  95. if (IsListEmpty(&m_ListHeadOfWamInfo))
  96. {
  97. *fDelete = TRUE;
  98. }
  99. return TRUE;
  100. }
  101. /*-----------------------------------------------------------------------------
  102. CProcessEntry::FindWamInfo
  103. Find a waminfo object from this ProcessEntry's linklist.
  104. If found, returns the object via *ppWamInfo. Else, set *ppWamInfo to NULL.
  105. return TRUE.
  106. -----------------------------------------------------------------------------*/
  107. bool CProcessEntry::FindWamInfo
  108. (
  109. CWamInfo** ppWamInfo
  110. )
  111. {
  112. CWamInfo* pWamInfo = NULL;
  113. PLIST_ENTRY pleTemp = NULL;
  114. if (!IsListEmpty(&m_ListHeadOfWamInfo))
  115. {
  116. pleTemp = m_ListHeadOfWamInfo.Flink;
  117. DBG_ASSERT(pleTemp != NULL);
  118. pWamInfo = CONTAINING_RECORD(
  119. pleTemp,
  120. CWamInfo,
  121. leProcess);
  122. pWamInfo->Reference();
  123. }
  124. *ppWamInfo = pWamInfo;
  125. return TRUE;
  126. }
  127. bool CProcessEntry::Recycle()
  128. {
  129. CWamInfo * pWamInfo = NULL;
  130. LIST_ENTRY * pleTemp = NULL;
  131. DWORD dwTimeElapsed = 0;
  132. DWORD dwTimeAllowed = 0;
  133. IF_DEBUG( WAM_ISA_CALLS )
  134. DBGPRINTF((
  135. DBG_CONTEXT,
  136. "Recycling CProcessEntry 0x%p m_fRecycling is %d\r\n",
  137. this,
  138. m_fRecycling
  139. ));
  140. //
  141. // Only 1 thread gets to do this.
  142. //
  143. if ( InterlockedExchange( (LONG*)&m_fRecycling, (LONG)TRUE ) )
  144. {
  145. IF_DEBUG( WAM_ISA_CALLS )
  146. DBGPRINTF((
  147. DBG_CONTEXT,
  148. "CProcessEntry 0x%p already recycled.\r\n",
  149. this
  150. ));
  151. return TRUE;
  152. }
  153. //
  154. // Grab the write lock on WAM_DICTATOR's hash table and delete
  155. // all the CWamInfo entries associated with this process. We
  156. // need to minimize the time that we hold the write lock because
  157. // no WAM_REQUESTs will get through as long as we have it.
  158. //
  159. // We'll go through the list again after we release the lock and
  160. // shut down the wam info dudes.
  161. //
  162. g_pWamDictator->HashWriteLock();
  163. pleTemp = m_ListHeadOfWamInfo.Flink;
  164. while ( pleTemp != &m_ListHeadOfWamInfo )
  165. {
  166. pWamInfo = CONTAINING_RECORD(
  167. pleTemp,
  168. CWamInfo,
  169. leProcess
  170. );
  171. DBG_ASSERT( pWamInfo );
  172. if ( !m_dwShutdownTimeLimit )
  173. {
  174. m_dwShutdownTimeLimit = pWamInfo->QueryShutdownTimeLimit();
  175. }
  176. g_pWamDictator->DeleteWamInfoFromHashTable( pWamInfo );
  177. pleTemp = pleTemp->Flink;
  178. }
  179. pleTemp = NULL;
  180. pWamInfo = NULL;
  181. g_pWamDictator->HashWriteUnlock();
  182. //
  183. // Kick off a scheduler a scheduler thread that will cleanup
  184. // the CWamInfo object for this process entry.
  185. //
  186. m_pShuttingDownCWamInfo = NULL;
  187. m_dwShutdownStartTime = GetCurrentTimeInSeconds();
  188. AddRef();
  189. ScheduleWorkItem(
  190. CleanupRecycledProcessEntry,
  191. this,
  192. 0,
  193. FALSE
  194. );
  195. return TRUE;
  196. }
  197. //===============================================================================
  198. /*-----------------------------------------------------------------------------
  199. CProcessTable::CProcessTable
  200. Constructor for CProcessTable
  201. -----------------------------------------------------------------------------*/
  202. CProcessTable::CProcessTable()
  203. : m_dwCnt(0),
  204. m_pCurrentProcessId(0),
  205. m_pCatalog(NULL),
  206. m_HashTable(LK_DFLT_MAXLOAD, LK_DFLT_INITSIZE, LK_DFLT_NUM_SUBTBLS)
  207. {
  208. }
  209. /*-----------------------------------------------------------------------------
  210. CProcessTable::~CProcessTable
  211. Destructor for CProcessTable
  212. -----------------------------------------------------------------------------*/
  213. CProcessTable::~CProcessTable()
  214. {
  215. DBG_ASSERT(m_dwCnt == 0);
  216. }
  217. /*-----------------------------------------------------------------------------
  218. CProcessTable::Init
  219. Constructor for CProcessTable
  220. Caches inetinfo.exe's process id in m_pCurrentProcessId.
  221. -----------------------------------------------------------------------------*/
  222. bool CProcessTable::Init()
  223. {
  224. INITIALIZE_CRITICAL_SECTION(&m_csPTable);
  225. m_pCurrentProcessId = GetCurrentProcessId();
  226. return TRUE;
  227. }
  228. /*-----------------------------------------------------------------------------
  229. CProcessTable::UnInit
  230. UnInit. Release the m_pCatalog.
  231. -----------------------------------------------------------------------------*/
  232. bool CProcessTable::UnInit()
  233. {
  234. if (m_pCatalog)
  235. {
  236. m_pCatalog->Release();
  237. m_pCatalog = NULL;
  238. }
  239. DeleteCriticalSection(&m_csPTable);
  240. return FALSE;
  241. }
  242. /*-----------------------------------------------------------------------------
  243. CProcessTable::AddWamInfoToProcessTable
  244. Add a waminfo to the process table. First find a process entry with the same process id,
  245. if none, create a new process entry. Then, add the waminfo to that process entry's linklist.
  246. Return pointer to ProcessEntry.
  247. -----------------------------------------------------------------------------*/
  248. CProcessEntry* CProcessTable::AddWamInfoToProcessTable
  249. (
  250. CWamInfo *pWamInfo,
  251. LPCWSTR szPackageId,
  252. DWORD pid
  253. )
  254. {
  255. HANDLE hProcess = INVALID_HANDLE_VALUE;
  256. CProcessEntry* pProcEntry = NULL;
  257. bool fReturn = TRUE;
  258. Lock();
  259. m_HashTable.FindKey(pid, &pProcEntry);
  260. if (pProcEntry)
  261. {
  262. pProcEntry->AddWamInfoToProcessEntry(pWamInfo);
  263. pProcEntry->Release();
  264. }
  265. else
  266. {
  267. hProcess = OpenProcess(
  268. PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_SET_QUOTA, // get duplicate handle
  269. FALSE, // fInheritable = ?
  270. pid );
  271. if (hProcess)
  272. {
  273. pProcEntry = new CProcessEntry(pid, hProcess, szPackageId);
  274. if (pProcEntry)
  275. {
  276. LK_RETCODE lkReturn;
  277. bool fDelete;
  278. pProcEntry->AddWamInfoToProcessEntry(pWamInfo);
  279. if ( LK_SUCCESS != m_HashTable.InsertRecord(pProcEntry))
  280. {
  281. pProcEntry->RemoveWamInfoFromProcessEntry(pWamInfo, &fDelete);
  282. fReturn = FALSE;
  283. }
  284. if (fReturn == FALSE)
  285. {
  286. delete pProcEntry;
  287. pProcEntry = NULL;
  288. }
  289. }
  290. else
  291. {
  292. SetLastError(E_OUTOFMEMORY);
  293. fReturn = FALSE;
  294. }
  295. }
  296. if (fReturn == FALSE)
  297. {
  298. CloseHandle(hProcess);
  299. hProcess = INVALID_HANDLE_VALUE;
  300. }
  301. }
  302. UnLock();
  303. return pProcEntry;
  304. }
  305. /*-----------------------------------------------------------------------------
  306. CProcessTable::FindWamInfo
  307. Giving a process entry, and find a Waminfo in that process entry's linklist.
  308. return TRUE/FALSE.
  309. -----------------------------------------------------------------------------*/
  310. bool CProcessTable::FindWamInfo
  311. (
  312. CProcessEntry *pProcEntry,
  313. CWamInfo **ppWamInfo
  314. )
  315. {
  316. bool fRet;
  317. DBG_ASSERT(pProcEntry != NULL);
  318. Lock();
  319. fRet = pProcEntry->FindWamInfo(ppWamInfo);
  320. UnLock();
  321. return fRet;
  322. }
  323. bool CProcessTable::RecycleWamInfo
  324. (
  325. CWamInfo * pWamInfo
  326. )
  327. {
  328. BSTR bstrInstanceId = NULL;
  329. HRESULT hr = NOERROR;
  330. CProcessEntry * pProcEntry = NULL;
  331. DWORD dwProcEntryPid;
  332. VARIANT varInstanceId = {0};
  333. DBG_ASSERT( pWamInfo );
  334. IF_DEBUG( WAM_ISA_CALLS )
  335. DBGPRINTF((
  336. DBG_CONTEXT,
  337. "Recycling CWamInfo 0x%p.\r\n",
  338. pWamInfo
  339. ));
  340. //
  341. // Get the com admin application interface
  342. //
  343. if (m_pCatalog == NULL)
  344. {
  345. // Create instance of the catalog object
  346. hr = CoCreateInstance(
  347. CLSID_COMAdminCatalog,
  348. NULL,
  349. CLSCTX_INPROC_SERVER,
  350. IID_ICOMAdminCatalog2,
  351. (void**)&m_pCatalog
  352. );
  353. if (FAILED(hr))
  354. {
  355. DBGPRINTF((
  356. DBG_CONTEXT,
  357. "Failed to CoCreateInstance of CLSID_ICOMAdminCatalog2, hr = %08x\n",
  358. hr
  359. ));
  360. goto Finished;
  361. }
  362. }
  363. pProcEntry = pWamInfo->QueryProcessEntry();
  364. if ( pProcEntry )
  365. {
  366. pProcEntry->AddRef();
  367. }
  368. //
  369. // If the application is inproc, then we don't want to
  370. // recycle it.
  371. //
  372. if ( pWamInfo->FInProcess() || !pProcEntry )
  373. {
  374. DBGPRINTF((
  375. DBG_CONTEXT,
  376. "Failing to recycle CProcessEntry 0x%d. OOP=%d.\r\n",
  377. pProcEntry,
  378. pWamInfo->FInProcess
  379. ));
  380. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  381. goto Finished;
  382. }
  383. //
  384. // If the process has already been recycled, then we
  385. // don't need to recycle it.
  386. //
  387. if ( pProcEntry->IsRecycling() )
  388. {
  389. IF_DEBUG( WAM_ISA_CALLS )
  390. DBGPRINTF((
  391. DBG_CONTEXT,
  392. "ProcEntry 0x%p is already recycling.\r\n",
  393. pProcEntry
  394. ));
  395. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  396. goto Finished;
  397. }
  398. //
  399. // Get the Instance ID
  400. //
  401. dwProcEntryPid = pProcEntry->QueryProcessId();
  402. hr = m_pCatalog->GetApplicationInstanceIDFromProcessID( dwProcEntryPid, &bstrInstanceId );
  403. if ( FAILED( hr ) )
  404. {
  405. pWamInfo->Print();
  406. DBGPRINTF((
  407. DBG_CONTEXT,
  408. "Failed to get instance ID for application '%s'. "
  409. "Error=0x%08x, CProcessEntry=0x%p, PID=%d.\r\n",
  410. pWamInfo->QueryApplicationPath().QueryStr(),
  411. hr,
  412. pProcEntry,
  413. dwProcEntryPid
  414. ));
  415. goto Finished;
  416. }
  417. DBG_ASSERT( bstrInstanceId );
  418. //
  419. // Call the COM+ function to recycle the process.
  420. // If this fails, we'll just return the error and let
  421. // the existing instance continue handling requests.
  422. //
  423. // CODEWORK
  424. //
  425. // The second argument to RecycleProcess should be
  426. // CRR_RECYCLED_FROM_API, but that constant was not
  427. // been defined yet...
  428. //
  429. varInstanceId.vt = VT_BSTR;
  430. varInstanceId.bstrVal = bstrInstanceId;
  431. hr = m_pCatalog->RecycleApplicationInstances( &varInstanceId, 0 );
  432. if ( FAILED( hr ) )
  433. {
  434. //
  435. // CODEWORK
  436. //
  437. // Need to write an event to the log for this failure.
  438. //
  439. DBGPRINTF((
  440. DBG_CONTEXT,
  441. "Error recycling application. App = %s, "
  442. "Instance ID = %S, hr = 0x%08x\r\n",
  443. pWamInfo->QueryApplicationPath().QueryStr(),
  444. bstrInstanceId,
  445. hr
  446. ));
  447. goto Finished;
  448. }
  449. //
  450. // Notify the process entry that it has been
  451. // recycled.
  452. //
  453. if ( !pProcEntry->Recycle() )
  454. {
  455. hr = E_FAIL;
  456. }
  457. Finished:
  458. VariantClear(&varInstanceId);
  459. if ( pProcEntry != NULL )
  460. {
  461. pProcEntry->Release();
  462. }
  463. if ( FAILED( hr ) )
  464. {
  465. SetLastError( WIN32_FROM_HRESULT( hr ) );
  466. return FALSE;
  467. }
  468. return TRUE;
  469. }
  470. /*-----------------------------------------------------------------------------
  471. CProcessTable::RemoveWamInfoFromProcessTable
  472. Remove the WamInfo from the process table. Using pWaminfo to find ProcessEntry. Then,
  473. Search the hashtable to find ProcessEntry, and then call ProcessEntry to remove the WamInfo
  474. from that process entry's linklist.
  475. Return TRUE/FALSE.
  476. -----------------------------------------------------------------------------*/
  477. bool CProcessTable::RemoveWamInfoFromProcessTable
  478. (
  479. CWamInfo *pWamInfo
  480. )
  481. {
  482. CProcessEntry* pProcEntry = pWamInfo->QueryProcessEntry();
  483. bool fDelete;
  484. /*
  485. DBGPRINTF((
  486. DBG_CONTEXT,
  487. "CProcessTable::RemoveWamInfoFromProcessTable called on CWamInfo 0x%p.\r\n",
  488. pWamInfo
  489. ));
  490. */
  491. DBG_ASSERT(pProcEntry != NULL);
  492. if (pProcEntry != NULL)
  493. {
  494. pProcEntry->AddRef();
  495. }
  496. else
  497. {
  498. return FALSE;
  499. }
  500. Lock();
  501. pProcEntry->RemoveWamInfoFromProcessEntry(pWamInfo, &fDelete);
  502. if (fDelete)
  503. {
  504. LK_RETCODE LkReturn;
  505. LkReturn = m_HashTable.DeleteRecord(pProcEntry);
  506. DBG_ASSERT(LkReturn == LK_SUCCESS);
  507. if (pProcEntry->QueryProcessId() != m_pCurrentProcessId
  508. && !pProcEntry->IsCrashed())
  509. {
  510. ShutdownProcess(pProcEntry->QueryProcessId());
  511. }
  512. CloseHandle(pProcEntry->QueryProcessHandle());
  513. }
  514. UnLock();
  515. pProcEntry->Release();
  516. return fDelete;
  517. }
  518. /*-----------------------------------------------------------------------------
  519. CProcessTable::ShutdownPackage
  520. Shut down the out of process package,(wszPackageID).
  521. If the m_pCatalog is not CoCreated, then, m_pCatalog will be created first, and call COM+
  522. ShutdownApplication() to shutdown a package.
  523. Return:
  524. HRESULT
  525. -----------------------------------------------------------------------------*/
  526. HRESULT
  527. CProcessTable::ShutdownProcess
  528. (
  529. DWORD dwProcEntryPid
  530. )
  531. {
  532. IF_DEBUG( WAM_ISA_CALLS )
  533. DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::ShutdownPackage\n"));
  534. HRESULT hr = NOERROR;
  535. BSTR bstrInstanceId = NULL;
  536. VARIANT varInstanceId = {0};
  537. if (m_pCatalog == NULL)
  538. {
  539. //CONSIDER : CoCreateInstance Catalog object in everycall might not be a bad idea.
  540. //
  541. // Create instance of the catalog object
  542. hr = CoCreateInstance(CLSID_COMAdminCatalog
  543. , NULL
  544. , CLSCTX_INPROC_SERVER
  545. , IID_ICOMAdminCatalog2
  546. , (void**)&m_pCatalog);
  547. if (FAILED(hr))
  548. {
  549. DBGPRINTF((DBG_CONTEXT, "Failed to CoCreateInstance of CLSID_ICOMAdminCatalog2, hr = %08x\n",
  550. hr));
  551. goto LErrExit;
  552. }
  553. }
  554. hr = m_pCatalog->GetApplicationInstanceIDFromProcessID( dwProcEntryPid, &bstrInstanceId );
  555. if (FAILED(hr))
  556. {
  557. DBGPRINTF((DBG_CONTEXT, "ShutdownProcess failed to obtain instance ID, PID=%d, "
  558. "hr=0x%08x.\r\n", dwProcEntryPid, hr));
  559. goto LErrExit;
  560. }
  561. varInstanceId.vt = VT_BSTR;
  562. varInstanceId.bstrVal = bstrInstanceId;
  563. hr = m_pCatalog->ShutdownApplicationInstances(&varInstanceId);
  564. if (FAILED(hr))
  565. {
  566. DBGPRINTF((DBG_CONTEXT, "Failed to ShutdownProcess, PID=%d, instanceid=%S, hr=%08x\n",
  567. dwProcEntryPid,
  568. bstrInstanceId,
  569. hr));
  570. }
  571. LErrExit:
  572. if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))
  573. {
  574. DBGPRINTF((DBG_CONTEXT, "Failed to ShutdownPackage, hr = %08x\n",
  575. hr));
  576. // Perhaps an over-aggressive assert. Remove for now.
  577. //
  578. // DBG_ASSERT(SUCCEEDED(hr));
  579. }
  580. VariantClear(&varInstanceId);
  581. return hr;
  582. }//CProcessTable::ShutdownPackage
  583. VOID
  584. CleanupRecycledProcessEntry(
  585. VOID * pvContext
  586. )
  587. {
  588. CProcessEntry * pProcEntry = (CProcessEntry*)pvContext;
  589. LIST_ENTRY * pleTemp;
  590. DWORD dwCurrentRequests;
  591. BOOL fW3SvcShuttingDown;
  592. DBG_ASSERT( pProcEntry );
  593. //
  594. // If there is no CWamInfo shutting down, check for the
  595. // next one. If there is another on the list, queue a
  596. // work item to shut it down, else we're done and can
  597. // release the CProcessEntry.
  598. //
  599. if ( !pProcEntry->m_pShuttingDownCWamInfo )
  600. {
  601. if ( IsListEmpty( &pProcEntry->m_ListHeadOfWamInfo ) )
  602. {
  603. //
  604. // All CWamInfos are shut down. Release our
  605. // reference on the CProcessEntry and return
  606. //
  607. pProcEntry->Release();
  608. return;
  609. }
  610. //
  611. // Get the next CWamInfo and schedule it for shutdown
  612. //
  613. pleTemp = RemoveHeadList( &pProcEntry->m_ListHeadOfWamInfo );
  614. pProcEntry->m_pShuttingDownCWamInfo = CONTAINING_RECORD(
  615. pleTemp,
  616. CWamInfo,
  617. leProcess
  618. );
  619. DBG_ASSERT( pProcEntry->m_pShuttingDownCWamInfo );
  620. pProcEntry->m_pShuttingDownCWamInfo->Reference();
  621. pProcEntry->m_pShuttingDownCWamInfo->ChangeToState( WIS_SHUTDOWN );
  622. ScheduleWorkItem(
  623. CleanupRecycledProcessEntry,
  624. pProcEntry,
  625. 0,
  626. FALSE
  627. );
  628. return;
  629. }
  630. //
  631. // If we get here, the then we are shutting down a CWamInfo.
  632. // There are 4 possible scenarios here:
  633. //
  634. // The shutdown time limit has been exceeded. In this case,
  635. // we'll force the CWamInfo closed immediately.
  636. //
  637. // The CWamInfo has no requests remaining in flight. In this
  638. // case, we'll gracefully shut down the CWamInfo.
  639. //
  640. // The CWamInfo still has requests remaining in flight. In
  641. // this case, we'll schedule another work item and check again
  642. // in 1000ms.
  643. //
  644. // W3SVC is shutting down, in which case we want to treat it
  645. // the same as if the timeout has expired and we're immediately
  646. // closing all CWamInfo's forcably.
  647. //
  648. DBG_ASSERT( g_pWamDictator );
  649. fW3SvcShuttingDown = g_pWamDictator->FIsShutdown();
  650. DWORD dwTime = GetCurrentTimeInSeconds();
  651. if ( GetCurrentTimeInSeconds() - pProcEntry->m_dwShutdownStartTime >
  652. pProcEntry->m_dwShutdownTimeLimit ||
  653. fW3SvcShuttingDown )
  654. {
  655. //
  656. // Forceably shut down the CWamInfo. Calling StartShutdown
  657. // will cause the CWamInfo's m_pIWam to disconnect immediately.
  658. //
  659. IF_DEBUG( WAM_ISA_CALLS )
  660. DBGPRINTF((
  661. DBG_CONTEXT,
  662. "CProcessEntry 0x%08x forceably shutting down CWamInfo 0x%08x\r\n",
  663. pProcEntry,
  664. pProcEntry->m_pShuttingDownCWamInfo
  665. ));
  666. pProcEntry->m_pShuttingDownCWamInfo->StartShutdown(0);
  667. pProcEntry->m_pShuttingDownCWamInfo->UnInit();
  668. pProcEntry->m_pShuttingDownCWamInfo->Dereference(); // This function's ref
  669. pProcEntry->m_pShuttingDownCWamInfo->Dereference(); // WAM_DICTATOR's ref
  670. pProcEntry->m_pShuttingDownCWamInfo = NULL;
  671. ScheduleWorkItem(
  672. CleanupRecycledProcessEntry,
  673. pProcEntry,
  674. 0,
  675. FALSE
  676. );
  677. return;
  678. }
  679. dwCurrentRequests = pProcEntry->m_pShuttingDownCWamInfo->QueryCurrentRequests();
  680. if ( dwCurrentRequests )
  681. {
  682. //
  683. // Requests remaining - try again in 1000ms
  684. //
  685. DBGPRINTF((
  686. DBG_CONTEXT,
  687. "CProcessEntry 0x%08x, CWamInfo 0x%08x, waiting for %d requests.\r\n",
  688. pProcEntry,
  689. pProcEntry->m_pShuttingDownCWamInfo,
  690. dwCurrentRequests
  691. ));
  692. ScheduleWorkItem(
  693. CleanupRecycledProcessEntry,
  694. pProcEntry,
  695. 1000,
  696. FALSE
  697. );
  698. return;
  699. }
  700. //
  701. // Finally, if we get here, then we have a CWamInfo with no
  702. // requests remaining in flight. We can just Uninit and release
  703. // it.
  704. //
  705. pProcEntry->m_pShuttingDownCWamInfo->UnInit();
  706. pProcEntry->m_pShuttingDownCWamInfo->Dereference(); // This functions's ref
  707. pProcEntry->m_pShuttingDownCWamInfo->Dereference(); // WAM_DICTATOR's ref
  708. pProcEntry->m_pShuttingDownCWamInfo = NULL;
  709. ScheduleWorkItem(
  710. CleanupRecycledProcessEntry,
  711. pProcEntry,
  712. 0,
  713. FALSE
  714. );
  715. return;
  716. }