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.

1814 lines
40 KiB

  1. /*---------------------------------------------------------------------*
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. wamxinfo.cxx (formerly seinfo.cxx)
  5. Abstract:
  6. Implementation of WAM_EXEC_INFO object.
  7. Authors:
  8. Murali R. Krishnan ( MuraliK ) 18-July-1996
  9. David Kaplan ( DaveK ) 10-July-1997
  10. Environment:
  11. User Mode - Win32
  12. Project:
  13. Wam DLL
  14. --*/
  15. /************************************************************
  16. * Include Headers
  17. ************************************************************/
  18. # include <isapip.hxx>
  19. # include "wamxinfo.hxx"
  20. # include "WReqCore.hxx"
  21. # include "setable.hxx"
  22. # include "gip.h"
  23. # include "WamW3.hxx"
  24. // MIDL-generated
  25. # include "iwr.h"
  26. // allocation cache for the WAM_EXEC_INFO objects
  27. ALLOC_CACHE_HANDLER * WAM_EXEC_INFO::sm_pachExecInfo;
  28. # define WAM_EXEC_INFO_CACHE_THRESHOLD (400) // UNDONE: Empirically vary
  29. #if DBG
  30. PTRACE_LOG WAM_EXEC_INFO::sm_pDbgRefTraceLog;
  31. #endif
  32. SV_CACHE_MAP * WAM_EXEC_INFO::sm_pSVCacheMap = NULL;
  33. //
  34. // Ref count trace log sizes for per-request log and global log
  35. // (used for debugging ref count problems)
  36. //
  37. // NOTE these are large because WAM_EXEC_INFO can have a lot of
  38. // ref/deref activity
  39. //
  40. #define C_REFTRACES_PER_REQUEST 128
  41. #define C_REFTRACES_GLOBAL 4096
  42. /************************************************************
  43. * Functions
  44. ************************************************************/
  45. /*---------------------------------------------------------------------*
  46. WAM_EXEC_INFO::WAM_EXEC_INFO
  47. Constructor
  48. Arguments:
  49. pWam - ptr to wam
  50. Returns:
  51. Nothing
  52. */
  53. WAM_EXEC_INFO::WAM_EXEC_INFO(
  54. PWAM pWam
  55. )
  56. {
  57. _cRefs = 1;
  58. m_pWam= pWam;
  59. _psExtension = NULL;
  60. _FirstThread = FT_NULL;
  61. m_dwSignature = WAM_EXEC_INFO_SIGNATURE;
  62. DBG_ASSERT( m_pWam );
  63. m_fInProcess = m_pWam->FInProcess();
  64. m_fInPool = m_pWam->FInPool();
  65. m_fDisconnected = FALSE;
  66. InitializeListHead( &_ListEntry);
  67. IF_DEBUG( WAM_EXEC ) {
  68. DBGPRINTF(( DBG_CONTEXT, "WAM_EXEC_INFO(%p) Ctor : %d -> %d\n",
  69. this, _cRefs-1, _cRefs ));
  70. }
  71. #if DBG
  72. // create ref trace log
  73. m_pDbgRefTraceLog = CreateRefTraceLog( C_REFTRACES_PER_REQUEST, 0 );
  74. #endif
  75. } // WAM_EXEC_INFO::WAM_EXEC_INFO
  76. /*---------------------------------------------------------------------*
  77. WAM_EXEC_INFO::~WAM_EXEC_INFO
  78. Destructor
  79. Arguments:
  80. None
  81. Returns:
  82. Nothing
  83. */
  84. WAM_EXEC_INFO::~WAM_EXEC_INFO(
  85. )
  86. {
  87. IF_DEBUG( WAM_EXEC ) {
  88. DBGPRINTF((
  89. DBG_CONTEXT
  90. , "WAM_EXEC_INFO(%p) Dtor \n"
  91. , this
  92. ));
  93. }
  94. m_dwSignature = WAM_EXEC_INFO_SIGNATURE_FREE;
  95. #if DBG
  96. // write thread id into second dword of this object's memory
  97. // (alloc cache stores next-ptr in 1st dword, so we use 2nd slot)
  98. *( (DWORD *)this + 1 ) = GetCurrentThreadId();
  99. // destroy ref trace log
  100. if( m_pDbgRefTraceLog != NULL ) {
  101. DestroyRefTraceLog( m_pDbgRefTraceLog );
  102. }
  103. #endif
  104. } // WAM_EXEC_INFO::~WAM_EXEC_INFO
  105. #define WRC_F _WamReqCore.m_WamReqCoreFixed
  106. /*---------------------------------------------------------------------*
  107. WAM_EXEC_INFO::InitWamExecInfo
  108. Initializes the wamexec info
  109. Arguments:
  110. cbWrcStrings - number of bytes required by strings buffer
  111. dwChildFlags - flags for child execution (HSE_EXEC_???)
  112. Returns:
  113. HRESULT
  114. */
  115. HRESULT
  116. WAM_EXEC_INFO::InitWamExecInfo
  117. (
  118. IWamRequest * pIWamRequest,
  119. DWORD cbWrcStrings,
  120. OOP_CORE_STATE * pOopCoreState
  121. )
  122. {
  123. HRESULT hr = NOERROR;
  124. DBG_ASSERT( pIWamRequest );
  125. IF_DEBUG( WAM_EXEC ) {
  126. DBGPRINTF((
  127. DBG_CONTEXT
  128. , "WAM_EXEC_INFO(%p)::InitWamExecInfo "
  129. "pIWamRequest(%p) "
  130. "cbWrcStrings(%d) "
  131. "m_fInProcess(%d) "
  132. "\n"
  133. , this
  134. , pIWamRequest
  135. , cbWrcStrings
  136. , m_fInProcess
  137. ));
  138. }
  139. if ( FAILED( hr = InitWamExecBase( pIWamRequest ) ) ) {
  140. DBGPRINTF((
  141. DBG_CONTEXT
  142. , "InitWamExecBase failed "
  143. "hr(%x) "
  144. "\n"
  145. , hr
  146. ));
  147. goto LExit;
  148. }
  149. //
  150. // Init wamreq core - contains stuff needed by ecb
  151. //
  152. if ( FAILED( hr = _WamReqCore.InitWamReqCore(
  153. cbWrcStrings
  154. , pIWamRequest
  155. , pOopCoreState
  156. , m_fInProcess
  157. ) ) )
  158. {
  159. DBGPRINTF((
  160. DBG_CONTEXT
  161. , "InitWamReqCore failed "
  162. "hr(%x) "
  163. "\n"
  164. , hr
  165. ));
  166. goto LExit;
  167. }
  168. //
  169. // If this is a child ISA, set appropriate flags
  170. //
  171. _dwChildExecFlags = _WamReqCore.m_WamReqCoreFixed.m_dwChildExecFlags;
  172. IF_DEBUG( WAM_EXEC ) {
  173. Print();
  174. }
  175. //
  176. // begin Reset_Code
  177. // [the following code was formerly WAM_EXEC_INFO::Reset]
  178. //
  179. _dwFlags = SE_PRIV_FLAG_IN_CALLBACK;
  180. _AsyncIoInfo._pfnHseIO = NULL;
  181. _AsyncIoInfo._pvHseIOContext = NULL;
  182. _AsyncIoInfo._dwOutstandingIO = ASYNC_IO_TYPE_NONE;
  183. _AsyncIoInfo._cbLastAsyncIO = 0;
  184. _AsyncIoInfo._pvAsyncReadBuffer = NULL;
  185. // we are either inproc-valid or oop-valid, not both
  186. DBG_ASSERT(
  187. ( m_fInProcess && AssertInpValid() && !AssertOopValid() )
  188. ||
  189. (!m_fInProcess && !AssertInpValid() && AssertOopValid() )
  190. );
  191. ecb.cbSize = sizeof(EXTENSION_CONTROL_BLOCK);
  192. //
  193. // dwVersion is hardcoded because the iisext.h file that defines
  194. // HSE_VERSION_MAJOR and HSE_VERSION_MINOR is shipped as a part of
  195. // the SDK, and the compiler variable that distinguishes 5.1 from
  196. // 6.0 builds is internal. The #if directive wouldn't make sense
  197. // in a file exposed to the public.
  198. //
  199. ecb.dwVersion = MAKELONG( 1, 5 );
  200. // keep in sync with HT_OK in basereq.hxx
  201. #define HT_OK 200
  202. ecb.dwHttpStatusCode = HT_OK;
  203. ecb.lpszLogData[0] = '\0';
  204. //
  205. // note that function pointers are set in isplocal.cxx before
  206. // executing the request using ECB
  207. //
  208. ecb.ConnID = (HCONN) this;
  209. ecb.lpszMethod = _WamReqCore.GetSz( WRC_I_METHOD );
  210. ecb.lpszQueryString = _WamReqCore.GetSz( WRC_I_QUERY );
  211. ecb.lpszPathInfo = _WamReqCore.GetSz( WRC_I_PATHINFO );
  212. ecb.lpszContentType = _WamReqCore.GetSz( WRC_I_CONTENTTYPE );
  213. ecb.lpszPathTranslated = _WamReqCore.GetSz( WRC_I_PATHTRANS );
  214. ecb.cbTotalBytes = WRC_F.m_cbClientContent;
  215. //
  216. // Clients can send more bytes then are indicated in their
  217. // Content-Length header. Adjust byte counts so they match
  218. //
  219. ecb.cbAvailable = (WRC_F.m_cbEntityBody > WRC_F.m_cbClientContent)
  220. ? WRC_F.m_cbClientContent
  221. : WRC_F.m_cbEntityBody
  222. ;
  223. ecb.lpbData = _WamReqCore.m_pbEntityBody;
  224. //
  225. // end Reset_Code
  226. // [the preceding code was formerly WAM_EXEC_INFO::Reset]
  227. //
  228. LExit:
  229. return hr;
  230. } // WAM_EXEC_INFO::InitWamExecInfo
  231. HRESULT
  232. WAM_EXEC_INFO::GetInfoForName
  233. (
  234. IWamRequest * pIWamRequest,
  235. const unsigned char * szVarName,
  236. unsigned char * pchBuffer,
  237. DWORD cchBuffer,
  238. DWORD * pcchRequired
  239. )
  240. {
  241. HRESULT hr = NOERROR;
  242. BOOL fCacheHit = FALSE;
  243. if( !m_fInProcess )
  244. {
  245. // Lookup server variable in the cache.
  246. DBG_ASSERT( sm_pSVCacheMap );
  247. LPCSTR szTempVarName = (LPSTR)szVarName;
  248. DWORD dwOrdinal;
  249. if( sm_pSVCacheMap->FindOrdinal( szTempVarName,
  250. strlen(szTempVarName),
  251. &dwOrdinal
  252. ) )
  253. {
  254. DBG_ASSERT( dwOrdinal < SVID_COUNT );
  255. DWORD dwOffset = _WamReqCore.m_rgSVOffsets[dwOrdinal];
  256. if( dwOffset != SV_DATA_INVALID_OFFSET )
  257. {
  258. DBG_ASSERT( _WamReqCore.m_pbSVData );
  259. // We have a value cached.
  260. fCacheHit = TRUE;
  261. if( SUCCEEDED(dwOffset) )
  262. {
  263. // The offset is an actual offset into our data buffer iff
  264. // the high bit isn't set.
  265. LPSTR szValue = (LPSTR)(_WamReqCore.m_pbSVData + dwOffset);
  266. DWORD cchValue = strlen( szValue ) + 1;
  267. if( cchValue > cchBuffer || pchBuffer == NULL )
  268. {
  269. // Insufficient buffer
  270. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  271. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  272. }
  273. else
  274. {
  275. CopyMemory( pchBuffer, szValue, cchValue );
  276. }
  277. *pcchRequired = cchValue;
  278. }
  279. else
  280. {
  281. //
  282. // In the event that HTTP_REQUEST::GetInfoForName
  283. // failed because of missing data the error code
  284. // returned is stored in dwOffset.
  285. //
  286. DBG_ASSERT( FAILED(dwOffset) );
  287. // Rely on BoolFromHresult to do the SetLastError...
  288. hr = dwOffset;
  289. }
  290. }
  291. }
  292. }
  293. if( !fCacheHit )
  294. {
  295. // Moved from isplocal.cxx - GetServerVariable()
  296. HANDLE hCurrentUser = NULL;
  297. if( !m_fInProcess )
  298. {
  299. hCurrentUser = INVALID_HANDLE_VALUE;
  300. }
  301. DoRevertHack( &hCurrentUser );
  302. hr = pIWamRequest->GetInfoForName( szVarName,
  303. pchBuffer,
  304. cchBuffer,
  305. pcchRequired
  306. );
  307. UndoRevertHack( &hCurrentUser );
  308. }
  309. return hr;
  310. }
  311. /*---------------------------------------------------------------------*
  312. WAM_EXEC_INFO::TransmitFile
  313. This function transmits the file contents as specified in the
  314. pHseTfi. It also sets up the call back functions for
  315. processing the request when it completes.
  316. Arguments:
  317. pHseTfi - pointer to Server Extension Transmit File information
  318. Returns:
  319. TRUE on success and FALSE on failure
  320. */
  321. BOOL
  322. WAM_EXEC_INFO::TransmitFile(
  323. IN LPHSE_TF_INFO pHseTfi
  324. )
  325. {
  326. BOOL fReturn = FALSE;
  327. IWamRequest * pIWamRequest = NULL;
  328. IF_DEBUG( WAM_ISA_CALLS ) {
  329. DBGPRINTF((
  330. DBG_CONTEXT
  331. , "WAM_EXEC_INFO(%p)::TransmitFile "
  332. "pHseTfi(%p) "
  333. "\n"
  334. , this
  335. , pHseTfi
  336. ));
  337. }
  338. //
  339. // It is unlikely that ISAPI applications will post
  340. // multiple outstanding IOs. However we have the state
  341. // pAsyncIoInfo->_fOutstandingIO to secure ourselves against this.
  342. // I have not used any critical sections to protect against
  343. // multiple threads for performance reasons.
  344. // Today we support only Async IO transfers
  345. //
  346. if ( pHseTfi == NULL
  347. || _AsyncIoInfo._dwOutstandingIO
  348. || ((pHseTfi->dwFlags & HSE_IO_ASYNC) == 0) ) {
  349. SetLastError( ERROR_INVALID_PARAMETER );
  350. return ( FALSE );
  351. }
  352. if ( pHseTfi->hFile == INVALID_HANDLE_VALUE) {
  353. SetLastError( ERROR_INVALID_HANDLE );
  354. return ( FALSE );
  355. }
  356. //
  357. // If there is no file being transfered, then having a non-zero
  358. // offset or BytesToWrite will be bad.
  359. //
  360. if( (pHseTfi->hFile == NULL) &&
  361. (pHseTfi->BytesToWrite != 0 || pHseTfi->Offset != 0) )
  362. {
  363. // Consider: We could just set these to 0, ie ignore them
  364. // if the hFile is NULL.
  365. SetLastError( ERROR_INVALID_PARAMETER );
  366. return ( FALSE );
  367. }
  368. //
  369. // Record the number of bytes to complete the IO with
  370. //
  371. if ( pHseTfi->BytesToWrite > 0 ) {
  372. DBG_ASSERT( pHseTfi->hFile );
  373. _AsyncIoInfo._cbLastAsyncIO = pHseTfi->BytesToWrite;
  374. } else {
  375. //
  376. // If a zero-size was passed in, get size from file
  377. //
  378. if( pHseTfi->hFile )
  379. {
  380. BY_HANDLE_FILE_INFORMATION hfi;
  381. if ( !GetFileInformationByHandle( pHseTfi->hFile, &hfi )) {
  382. // CONSIDER something besides ERROR_INVALID_HANDLE???
  383. SetLastError( ERROR_INVALID_HANDLE );
  384. return ( FALSE );
  385. }
  386. if ( hfi.nFileSizeHigh ) {
  387. SetLastError( ERROR_NOT_SUPPORTED );
  388. return ( FALSE );
  389. }
  390. _AsyncIoInfo._cbLastAsyncIO = hfi.nFileSizeLow;
  391. }
  392. else
  393. {
  394. // We want to allow TransmitFile without a file handle
  395. _AsyncIoInfo._cbLastAsyncIO = 0;
  396. }
  397. }
  398. //
  399. // Set the callback function. Override old one
  400. //
  401. if ( pHseTfi->pfnHseIO != NULL) {
  402. _AsyncIoInfo._pfnHseIO = pHseTfi->pfnHseIO;
  403. }
  404. if ( NULL == _AsyncIoInfo._pfnHseIO) {
  405. // No callback specified. return error
  406. SetLastError( ERROR_INVALID_PARAMETER );
  407. return ( FALSE );
  408. }
  409. if ( pHseTfi->pContext != NULL) {
  410. // Override the old context
  411. _AsyncIoInfo._pvHseIOContext = pHseTfi->pContext;
  412. }
  413. if ( FAILED( GetIWamRequest( &pIWamRequest ) ) ) {
  414. // CONSIDER something besides ERROR_INVALID_FUNCTION???
  415. SetLastError( ERROR_INVALID_FUNCTION );
  416. return FALSE;
  417. }
  418. DBG_ASSERT( pIWamRequest );
  419. //
  420. // Finally, call appropriate transmit-file version
  421. // based on in-proc vs. oop.
  422. //
  423. // First, we init async i/o processing. In normal (success) case,
  424. // i/o completion thread will call balancing uninit. In failure
  425. // case, we call it below.
  426. //
  427. InitAsyncIO( ASYNC_IO_TYPE_WRITE );
  428. if ( m_fInProcess ) {
  429. //
  430. // call in-proc interface (fastest)
  431. //
  432. fReturn = BoolFromHresult(
  433. pIWamRequest->TransmitFileInProc(
  434. #ifdef _WIN64
  435. (UINT64) this
  436. #else
  437. (ULONG_PTR) this
  438. #endif
  439. , (unsigned char *) pHseTfi
  440. ) );
  441. } else {
  442. //
  443. // call out-of-proc interface
  444. //
  445. unsigned char * pszStatusCode = NULL;
  446. DWORD cbStatusCode = 0;
  447. //
  448. // if send-headers flag is set, get status code from struct
  449. //
  450. if ( pHseTfi->dwFlags & HSE_IO_SEND_HEADERS ) {
  451. DBG_ASSERT( pHseTfi->pszStatusCode );
  452. pszStatusCode = (unsigned char *) pHseTfi->pszStatusCode;
  453. cbStatusCode = lstrlen( pHseTfi->pszStatusCode ) + 1;
  454. }
  455. HANDLE hCurrentUser = INVALID_HANDLE_VALUE;
  456. DoRevertHack( &hCurrentUser );
  457. fReturn = BoolFromHresult(
  458. pIWamRequest->TransmitFileOutProc(
  459. #ifdef _WIN64
  460. (UINT64) this
  461. , (UINT64) pHseTfi->hFile
  462. #else
  463. (ULONG_PTR) this
  464. , (ULONG_PTR) pHseTfi->hFile
  465. #endif
  466. , pszStatusCode
  467. , cbStatusCode
  468. , pHseTfi->BytesToWrite
  469. , pHseTfi->Offset
  470. , (unsigned char *) pHseTfi->pHead
  471. , pHseTfi->HeadLength
  472. , (unsigned char *) pHseTfi->pTail
  473. , pHseTfi->TailLength
  474. , pHseTfi->dwFlags
  475. ) );
  476. UndoRevertHack( &hCurrentUser );
  477. }
  478. if ( !fReturn ) {
  479. UninitAsyncIO();
  480. }
  481. ReleaseIWamRequest( pIWamRequest );
  482. return fReturn;
  483. } // WAM_EXEC_INFO::TransmitFile()
  484. /*---------------------------------------------------------------------*
  485. WAM_EXEC_INFO::AsyncReadClient
  486. Description:
  487. This function performs an async read of client (browser) data
  488. on behalf of the ISA
  489. Arguments:
  490. pvBuff - Data buffer to read into
  491. pcbToRead - Number of bytes to read, set to number of bytes read if
  492. request is not Async
  493. dwFlags - Receive flags
  494. Notes:
  495. The initial design for AsyncRead was inadequate when the isapi is
  496. running out of process. The problem was that the data buffer was
  497. marshalled over to inetinfo and back during the AsyncRead call.
  498. Since the completion will happen on another thread the ISAPI could
  499. get the completion before the data was completely marshalled back
  500. or the address in inetinfo could be invalidated before the read was
  501. complete. The solution is to add a separate path for oop async reads
  502. and marshall the data on the io completion and copy it into the
  503. client's buffer then.
  504. Returns:
  505. TRUE on success and FALSE on failure
  506. */
  507. BOOL
  508. WAM_EXEC_INFO::AsyncReadClient(
  509. IN OUT PVOID pvBuff
  510. , IN OUT DWORD *pcbToRead
  511. , IN DWORD dwFlags
  512. )
  513. {
  514. BOOL fReturn = FALSE;
  515. DBG_ASSERT( pvBuff );
  516. DBG_ASSERT( pcbToRead );
  517. IF_DEBUG( WAM_ISA_CALLS ) {
  518. DBGPRINTF((
  519. DBG_CONTEXT
  520. , "WAM_EXEC_INFO(%p)::AsyncReadClient\t"
  521. "Bytes to read = %d\n"
  522. , this
  523. , *pcbToRead
  524. ));
  525. }
  526. DBG_ASSERT( dwFlags & HSE_IO_ASYNC );
  527. //
  528. // It is unlikely that ISAPI applications will post
  529. // multiple outstanding IOs. However we have the state
  530. // _AsyncIoInfo._dwOutstandingIO to secure ourselves against such cases.
  531. // I have not used any critical sections to protect against
  532. // multiple threads for performance reasons.
  533. // Today we support only Async IO transfers
  534. //
  535. if ( _AsyncIoInfo._dwOutstandingIO ||
  536. ((dwFlags & HSE_IO_ASYNC) == 0) ) {
  537. SetLastError(ERROR_INVALID_PARAMETER);
  538. return ( FALSE);
  539. }
  540. if ( NULL == _AsyncIoInfo._pfnHseIO) {
  541. // No callback specified. return error
  542. SetLastError( ERROR_INVALID_PARAMETER);
  543. return (FALSE);
  544. }
  545. //
  546. // Setup stage for and execute AsyncReadClient operation
  547. //
  548. //
  549. // If callback function exists and flags indicate Async IO, do it.
  550. // Also there should be no outstanding Async IO operation.
  551. //
  552. if ( dwFlags & HSE_IO_ASYNC) {
  553. //
  554. // 1. Set Request state to be async IO from ISAPI client
  555. // 2. Submit Async IOP
  556. // 3. return to the ISAPI application
  557. //
  558. IWamRequest * pIWamRequest = NULL;
  559. if ( FAILED( GetIWamRequest( &pIWamRequest ) ) ) {
  560. return FALSE;
  561. }
  562. InitAsyncIO( ASYNC_IO_TYPE_READ );
  563. if( m_fInProcess )
  564. {
  565. fReturn = BoolFromHresult( pIWamRequest->AsyncReadClientExt(
  566. #ifdef _WIN64
  567. (UINT64) this
  568. #else
  569. (ULONG_PTR) this
  570. #endif
  571. , (unsigned char *) pvBuff
  572. , *pcbToRead
  573. ) );
  574. }
  575. else
  576. {
  577. DBG_ASSERT( _AsyncIoInfo._pvAsyncReadBuffer == NULL );
  578. _AsyncIoInfo._pvAsyncReadBuffer = pvBuff;
  579. fReturn = BoolFromHresult( pIWamRequest->AsyncReadClientOop(
  580. #ifdef _WIN64
  581. (UINT64) this
  582. #else
  583. (ULONG_PTR) this
  584. #endif
  585. , *pcbToRead
  586. ) );
  587. if( !fReturn )
  588. {
  589. _AsyncIoInfo._pvAsyncReadBuffer = NULL;
  590. }
  591. }
  592. ReleaseIWamRequest( pIWamRequest );
  593. if ( !fReturn ) {
  594. UninitAsyncIO();
  595. }
  596. } else {
  597. DBG_ASSERT( FALSE );
  598. }
  599. return ( fReturn);
  600. } // WAM_EXEC_INFO::AsyncReadClient()
  601. /*---------------------------------------------------------------------*
  602. WAM_EXEC_INFO::ProcessAsyncIO
  603. Description:
  604. Completes an async i/o by calling the ISA's i/o completion callback
  605. Arguments:
  606. Returns:
  607. BOOL
  608. */
  609. BOOL
  610. WAM_EXEC_INFO::ProcessAsyncIO(
  611. DWORD dwStatus
  612. , DWORD cbWritten
  613. )
  614. {
  615. DBG_ASSERT( _AsyncIoInfo._pfnHseIO );
  616. DBG_ASSERT( _AsyncIoInfo._dwOutstandingIO );
  617. IF_DEBUG( WAM_ISA_CALLS ) {
  618. DBGPRINTF((
  619. DBG_CONTEXT,
  620. "WAM_EXEC_INFO[%p]::ProcessAsyncIO(IOStatus=%d, %d bytes)\n"
  621. , this, dwStatus, cbWritten
  622. ));
  623. }
  624. BOOL fRet = TRUE;
  625. BOOL fImpersonated = FALSE;
  626. DWORD dwIOType = ASYNC_IO_TYPE_NONE;
  627. //
  628. // 1.
  629. // We are in the return from an async io completion.
  630. // We will be making a call into the ISAPI DLL to notify that
  631. // the IO operation completed.
  632. // This callback has to occur within the bounds of ref/deref
  633. // of the WAM_EXEC_INFO otherwise following race condition can occur:
  634. // - isapi's completion function calls done-with-session;
  635. // if that release got rid of last ref, this WAM_EXEC_INFO
  636. // gets destroyed
  637. // - isapi's completion function continues doing other work
  638. // - an unrelated shutdown command comes in asynchronously
  639. // - if isapi has no TerminateExtension (or a non-robust one),
  640. // isapi gets summarily unloaded
  641. // - any of a number of terrible things can happen
  642. //
  643. // If you HAVE temptations to optimize this,
  644. // please first talk to MuraliK
  645. //
  646. AddRef();
  647. //
  648. // 2.
  649. // Un-init async i/o - balances init we did before requesting i/o
  650. //
  651. // NOTE we do this before calling the isapi's completion function
  652. // Reasons:
  653. // WAM_EXEC_INFO maintians state that an async IO operation is going on
  654. // UninitAsyncIO resets this state and other associated ref-counts.
  655. // This way we ensure that any further async IO callbacks made during
  656. // the call to the ISAPI DLL will be honored properly.
  657. //
  658. // Only call this in success case.
  659. if (dwStatus == 0)
  660. {
  661. dwIOType = _AsyncIoInfo._dwOutstandingIO;
  662. UninitAsyncIO();
  663. }
  664. //
  665. // 3.
  666. // Impersonate before making ISAPI callback
  667. //
  668. if ( !m_pWam->FWin95() )
  669. {
  670. HANDLE hToken = _WamReqCore.m_WamReqCoreFixed.m_hUserToken;
  671. if ( !( fImpersonated = ImpersonateLoggedOnUser( hToken ) ) )
  672. {
  673. DBGPRINTF((DBG_CONTEXT,
  674. "WAM_EXEC_INFO(%p) ImpersonateLoggedOnUser(%x)"
  675. "failed[err %d]\n",
  676. this, hToken, GetLastError()));
  677. fRet = FALSE;
  678. }
  679. }
  680. //
  681. // 4.
  682. // call isapi if we are successful so far
  683. //
  684. if ( fRet ) {
  685. __try {
  686. //
  687. // Adjust bytes written for async writes -
  688. // otherwise filter adjusted bytes show up
  689. // which confuses some ISAPI Applications
  690. //
  691. if ( dwIOType == ASYNC_IO_TYPE_WRITE
  692. && dwStatus == ERROR_SUCCESS ) {
  693. cbWritten = _AsyncIoInfo._cbLastAsyncIO;
  694. _AsyncIoInfo._cbLastAsyncIO = 0;
  695. }
  696. //
  697. // Make the ISAPI callback to indicate that the I/O completed
  698. //
  699. (*_AsyncIoInfo._pfnHseIO)(
  700. &ecb,
  701. _AsyncIoInfo._pvHseIOContext,
  702. cbWritten,
  703. dwStatus
  704. );
  705. }
  706. __except ( g_fEnableTryExcept ?
  707. WAMExceptionFilter( GetExceptionInformation(),
  708. WAM_EVENT_EXTENSION_EXCEPTION,
  709. this ) :
  710. EXCEPTION_CONTINUE_SEARCH )
  711. {
  712. fRet = FALSE;
  713. }
  714. }
  715. //
  716. // 5.
  717. // Revert back if we were impersonated before making ISAPI DLL callback
  718. //
  719. if ( fImpersonated )
  720. {
  721. ::RevertToSelf( );
  722. fImpersonated = FALSE;
  723. }
  724. if (dwStatus != 0)
  725. {
  726. UninitAsyncIO();
  727. }
  728. //
  729. // Complimentary release for the AddRef() done in Step (1) above
  730. //
  731. Release();
  732. return fRet;
  733. } // ProcessAsyncIO()
  734. BOOL
  735. WAM_EXEC_INFO::ProcessAsyncReadOop
  736. (
  737. DWORD dwStatus,
  738. DWORD cbRead,
  739. unsigned char * lpDataRead
  740. )
  741. /*++
  742. Routine Description:
  743. Handle callback for out of process AsyncRead
  744. Arguments:
  745. dwStatus - IO status
  746. cbRead - Number of bytes read
  747. lpDataRead - Marshalled data read
  748. Return Value:
  749. Notes:
  750. The initial design for AsyncRead was inadequate when the isapi is
  751. running out of process. The problem was that the data buffer was
  752. marshalled over to inetinfo and back during the AsyncRead call.
  753. Since the completion will happen on another thread the ISAPI could
  754. get the completion before the data was completely marshalled back
  755. or the address in inetinfo could be invalidated before the read was
  756. complete. The solution is to add a separate path for oop async reads
  757. and marshall the data on the io completion and copy it into the
  758. client's buffer then.
  759. --*/
  760. {
  761. DBG_ASSERT( !m_fInProcess );
  762. DBG_ASSERT( _AsyncIoInfo._pvAsyncReadBuffer != NULL );
  763. // Copy the marshalled data into the client's buffer.
  764. if( dwStatus == STATUS_SUCCESS )
  765. {
  766. //
  767. // Is there more we can do to protect this?
  768. //
  769. // We'd have problems anyway if the client's buffer wasn't large
  770. // enough to hold the data and cbRead should always be <= than the
  771. // size the client specified.
  772. //
  773. CopyMemory( _AsyncIoInfo._pvAsyncReadBuffer, lpDataRead, cbRead );
  774. }
  775. _AsyncIoInfo._pvAsyncReadBuffer = NULL;
  776. return ProcessAsyncIO( dwStatus, cbRead );
  777. }
  778. /*---------------------------------------------------------------------*
  779. WAM_EXEC_INFO::InitAsyncIO
  780. Initilializes members before requesting async i/o
  781. Arguments:
  782. None
  783. Returns:
  784. Nothing
  785. */
  786. VOID
  787. WAM_EXEC_INFO::InitAsyncIO( DWORD dwIOType )
  788. {
  789. IF_DEBUG( WAM_ISA_CALLS ) {
  790. DBGPRINTF((
  791. DBG_CONTEXT
  792. , "WAM_EXEC_INFO(%p)::InitAsyncIO "
  793. "\n"
  794. , this
  795. ));
  796. }
  797. DBG_ASSERT( dwIOType == ASYNC_IO_TYPE_READ || dwIOType == ASYNC_IO_TYPE_WRITE );
  798. DBG_ASSERT( _AsyncIoInfo._dwOutstandingIO == ASYNC_IO_TYPE_NONE );
  799. DBG_ASSERT( _AsyncIoInfo._pfnHseIO != NULL);
  800. DBG_ASSERT( _AsyncIoInfo._pvAsyncReadBuffer == NULL );
  801. AddRef();
  802. _AsyncIoInfo._dwOutstandingIO = dwIOType;
  803. }
  804. /*---------------------------------------------------------------------*
  805. WAM_EXEC_INFO::UninitAsyncIO
  806. Un-initilializes members before completing async i/o
  807. Arguments:
  808. None
  809. Returns:
  810. Nothing
  811. */
  812. VOID
  813. WAM_EXEC_INFO::UninitAsyncIO()
  814. {
  815. IF_DEBUG( WAM_ISA_CALLS ) {
  816. DBGPRINTF((
  817. DBG_CONTEXT
  818. , "WAM_EXEC_INFO(%p)::UninitAsyncIO "
  819. "\n"
  820. , this
  821. ));
  822. }
  823. _AsyncIoInfo._dwOutstandingIO = ASYNC_IO_TYPE_NONE;
  824. Release();
  825. }
  826. /*---------------------------------------------------------------------*
  827. WAM_EXEC_INFO::IsValid
  828. Is this a valid object?
  829. Arguments:
  830. None
  831. Returns:
  832. BOOL
  833. */
  834. BOOL
  835. WAM_EXEC_INFO::IsValid( )
  836. {
  837. //
  838. // CONSIDER more thorough error checking
  839. //
  840. return (m_dwSignature == WAM_EXEC_INFO_SIGNATURE);
  841. }
  842. /*---------------------------------------------------------------------*
  843. WAM_EXEC_INFO::AddRef
  844. Add refs
  845. Arguments:
  846. None
  847. Returns:
  848. Ref count
  849. */
  850. ULONG
  851. WAM_EXEC_INFO::AddRef( )
  852. {
  853. IF_DEBUG( WAM_REFCOUNTS ) {
  854. DBGPRINTF((
  855. DBG_CONTEXT
  856. , "WAM_EXEC_INFO(%p) AddRef : %d -> %d\n"
  857. , this
  858. , _cRefs
  859. , _cRefs + 1
  860. ));
  861. }
  862. LONG cRefs = InterlockedIncrement( &_cRefs );
  863. #if DBG
  864. //
  865. // Write to both this request's trace log and global trace log
  866. //
  867. if( m_pDbgRefTraceLog != NULL ) {
  868. WriteRefTraceLog(
  869. m_pDbgRefTraceLog
  870. , cRefs
  871. , (PVOID) this
  872. );
  873. }
  874. if( sm_pDbgRefTraceLog != NULL ) {
  875. WriteRefTraceLog(
  876. sm_pDbgRefTraceLog
  877. , cRefs
  878. , (PVOID) this
  879. );
  880. }
  881. #endif
  882. return cRefs;
  883. }
  884. /*---------------------------------------------------------------------*
  885. WAM_EXEC_INFO::CleanupAndRelease
  886. Description:
  887. Calls wamreq's (prep)cleanup, then releases this wamexecinfo.
  888. Arguments:
  889. None
  890. Returns:
  891. Nothing
  892. */
  893. void
  894. WAM_EXEC_INFO::CleanupAndRelease(
  895. BOOL fFullCleanup
  896. )
  897. {
  898. //
  899. // Prep wamreq's cleanup
  900. //
  901. // This method should only be called from the IIS thread
  902. //
  903. DBG_ASSERT( m_dwThreadIdIIS == GetCurrentThreadId() );
  904. //
  905. // While on IIS thread m_pIWamReqIIS must be a valid pointer
  906. //
  907. DBG_ASSERT( m_pIWamReqIIS );
  908. //
  909. // The skip wamreq cleanup is only set by ASP after returning
  910. // a status pending
  911. //
  912. //
  913. // init hr's to failure - these will drive cleanup logic below,
  914. // but only if calls are successful
  915. //
  916. HRESULT hrCoInitEx = E_FAIL;
  917. HRESULT hrGetIWamReq = E_FAIL;
  918. IWamRequest * pIWamRequest = NULL;
  919. if ( m_fInProcess ) {
  920. //
  921. // inproc case, use our cached ptr.
  922. pIWamRequest = m_pIWamReqIIS;
  923. } else {
  924. //
  925. // in oop case,
  926. // an isapi might have changed the thread's mode on us
  927. // (for example, by coinit'ing single-threaded).
  928. // if so, we need to get an interface pointer from gip,
  929. // since our cached ptr will no longer be valid.
  930. //
  931. // NOTE we test this by calling coinit, which is cheap.
  932. // if this succeeds, we plough ahead with our cached ptr.
  933. // else if mode changed, we get an interface ptr from gip.
  934. //
  935. hrCoInitEx = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  936. if ( hrCoInitEx == RPC_E_CHANGED_MODE ) {
  937. hrGetIWamReq = GetIWamRequest( &pIWamRequest );
  938. } else {
  939. //
  940. // NOTE in most cases we are here because we succeeded
  941. // in others we forge ahead and hope for the best ...
  942. // at any rate, we cannot be worse off than before
  943. // we added the above co-init call
  944. //
  945. pIWamRequest = m_pIWamReqIIS;
  946. }
  947. }
  948. if ( pIWamRequest != NULL ) {
  949. HANDLE hCurrentUser = m_fInProcess ? NULL : INVALID_HANDLE_VALUE;
  950. DoRevertHack( &hCurrentUser );
  951. if ( fFullCleanup ) {
  952. //
  953. // we are doing full cleanup
  954. //
  955. pIWamRequest->CleanupWamRequest(
  956. (unsigned char*) ecb.lpszLogData
  957. , lstrlen( ecb.lpszLogData ) + 1
  958. , ecb.dwHttpStatusCode
  959. , _dwIsaKeepConn
  960. );
  961. } else {
  962. //
  963. // we are not doing full cleanup, so call 'Prep' only
  964. //
  965. pIWamRequest->PrepCleanupWamRequest(
  966. (unsigned char*) ecb.lpszLogData
  967. , lstrlen( ecb.lpszLogData ) + 1
  968. , ecb.dwHttpStatusCode
  969. , _dwIsaKeepConn
  970. );
  971. }
  972. UndoRevertHack( &hCurrentUser );
  973. }
  974. //
  975. // if we got a ptr from gip, release it
  976. //
  977. if ( SUCCEEDED( hrGetIWamReq ) ) {
  978. ReleaseIWamRequest( pIWamRequest );
  979. }
  980. //
  981. // if we co-init'ed, co-uninit
  982. //
  983. if ( hrCoInitEx == S_OK ) {
  984. CoUninitialize( );
  985. }
  986. //
  987. // Release this
  988. //
  989. Release( );
  990. return;
  991. } // CleanupAndRelease
  992. /*---------------------------------------------------------------------*
  993. WAM_EXEC_INFO::Release
  994. Releases
  995. Arguments:
  996. None
  997. Returns:
  998. Ref count
  999. */
  1000. ULONG
  1001. WAM_EXEC_INFO::Release(
  1002. )
  1003. {
  1004. IF_DEBUG( WAM_REFCOUNTS ) {
  1005. DBGPRINTF((
  1006. DBG_CONTEXT
  1007. , "WAM_EXEC_INFO(%p) Release: %d -> %d\n"
  1008. , this
  1009. , _cRefs
  1010. , _cRefs-1
  1011. ));
  1012. }
  1013. //
  1014. // Write the trace log BEFORE the decrement operation :(
  1015. // If we write it after the decrement, we will run into potential
  1016. // race conditions in this object getting freed up accidentally
  1017. // by another thread
  1018. //
  1019. #if DBG
  1020. //
  1021. // Write to both this request's trace log and global trace log
  1022. //
  1023. if( m_pDbgRefTraceLog != NULL ) {
  1024. WriteRefTraceLog(
  1025. m_pDbgRefTraceLog
  1026. , _cRefs - 1 // ref count AFTER decrement happens
  1027. , (PVOID) this
  1028. );
  1029. }
  1030. if( sm_pDbgRefTraceLog != NULL ) {
  1031. WriteRefTraceLog(
  1032. sm_pDbgRefTraceLog
  1033. , _cRefs - 1 // ref count AFTER decrement happens
  1034. , (PVOID) this
  1035. );
  1036. }
  1037. #endif
  1038. LONG cRefs = InterlockedDecrement( &_cRefs );
  1039. if( cRefs == 0) {
  1040. IF_DEBUG( WAM_REFCOUNTS ) {
  1041. DBGPRINTF(( DBG_CONTEXT, "... dying ...\n\n" ));
  1042. }
  1043. CleanupWamExecInfo( );
  1044. //
  1045. // Finally, delete ourselves.
  1046. //
  1047. delete this;
  1048. return 0;
  1049. }
  1050. return cRefs;
  1051. }
  1052. /*---------------------------------------------------------------------*
  1053. WAM_EXEC_INFO::CleanupWamExecInfo
  1054. Cleans up this object prior to its destruction
  1055. Arguments:
  1056. None
  1057. Returns:
  1058. Nothing
  1059. */
  1060. VOID
  1061. WAM_EXEC_INFO::CleanupWamExecInfo(
  1062. )
  1063. {
  1064. //
  1065. // remove this from its list
  1066. //
  1067. m_pWam->RemoveFromList( &_ListEntry);
  1068. if ( !m_fInProcess & !(m_pWam->FWin95()) ) {
  1069. //
  1070. // If oop, close the impersonation token
  1071. // (dup'ed in w3svc!HGetOopImpersonationToken)
  1072. //
  1073. // NOTE ignore if in-proc or win95 because we never dup'ed
  1074. // handle in the first place
  1075. //
  1076. DBG_ASSERT( _WamReqCore.m_WamReqCoreFixed.m_hUserToken
  1077. != (HANDLE)0 );
  1078. CloseHandle( _WamReqCore.m_WamReqCoreFixed.m_hUserToken );
  1079. _WamReqCore.m_WamReqCoreFixed.m_hUserToken = (HANDLE)0;
  1080. }
  1081. if ( _psExtension != NULL) {
  1082. // release the extension object
  1083. g_psextensions->ReleaseExtension( _psExtension);
  1084. _psExtension = NULL;
  1085. }
  1086. DBG_ASSERT( QueryPWam());
  1087. QueryPWam()->QueryWamStats().DecrCurrentWamRequests();
  1088. CleanupWamExecBase();
  1089. return;
  1090. } // WAM_EXEC_INFO::CleanupWamExecInfo
  1091. /*---------------------------------------------------------------------*
  1092. WAM_EXEC_INFO::ISAThreadNotify
  1093. Notifies WAM_EXEC_BASE that an ISAPI thread is about to
  1094. start/stop using it. Allows to cache IWamRequest* in the
  1095. OOP case.
  1096. NOTE this method is on WAM_EXEC_INFO (rather than WAM_EXEC_BASE)
  1097. because it must addref and release.
  1098. Arguments:
  1099. fStart thread start (TRUE) / thread end (FALSE)
  1100. Returns:
  1101. HRESULT
  1102. */
  1103. HRESULT
  1104. WAM_EXEC_INFO::ISAThreadNotify(
  1105. BOOL fStart
  1106. )
  1107. {
  1108. if ( m_fInProcess ) {
  1109. //
  1110. // In-proc: no-op
  1111. //
  1112. return NOERROR;
  1113. }
  1114. IF_DEBUG( WAM_THREADID ) {
  1115. DBGPRINTF((
  1116. DBG_CONTEXT
  1117. , "WAM_EXEC_INFO(%p)::ISAThreadNotify(%d) Thread(%d)\n"
  1118. , this
  1119. , fStart
  1120. , GetCurrentThreadId()
  1121. ));
  1122. }
  1123. HRESULT hr = NOERROR;
  1124. if ( fStart ) {
  1125. //
  1126. // Out-of-proc: when starting the ISA's single-thread
  1127. // sequence, cache ISA-thread ptr we get from gip-master.
  1128. //
  1129. if ( SUCCEEDED( hr = GetInterfaceForThread( ) ) ) {
  1130. AddRef();
  1131. }
  1132. DBG_ASSERT( AssertSmartISAValid() || (hr != NOERROR) );
  1133. } else {
  1134. //
  1135. // Out-of-proc: when ending the ISA's single-thread
  1136. // sequence, release ISA-thread ptr
  1137. //
  1138. hr = ReleaseInterfaceForThread( );
  1139. Release();
  1140. }
  1141. return hr;
  1142. } // WAM_EXEC_INFO::ISAThreadNotify
  1143. /*---------------------------------------------------------------------*
  1144. Debug methods
  1145. */
  1146. #if DBG
  1147. VOID
  1148. WAM_EXEC_INFO::Print( VOID) const
  1149. {
  1150. DBGPRINTF((
  1151. DBG_CONTEXT
  1152. , "WAM_EXEC_INFO(%p): Method: %s; Query: %s;\n"
  1153. "PathInfo: %s; PathTrans: %s; ContentType: %s;\n"
  1154. "URL: %s; ISA DLL path: %s;\n"
  1155. "In-Proc = %d; m_pIWamReqInproc = %p; "
  1156. "m_gipIWamRequest = %p; m_pIWamReqSmartISA = %p\n"
  1157. "Flags = %x; ChildExecFlags = %x; RefCount = %d\n"
  1158. "Extension = %p; OutstandingIO = %d; "
  1159. "IoCompletion() = %p; IoContext = %p\n"
  1160. , this
  1161. , _WamReqCore.GetSz( WRC_I_METHOD )
  1162. , _WamReqCore.GetSz( WRC_I_QUERY )
  1163. , _WamReqCore.GetSz( WRC_I_PATHINFO )
  1164. , _WamReqCore.GetSz( WRC_I_PATHTRANS )
  1165. , _WamReqCore.GetSz( WRC_I_CONTENTTYPE )
  1166. , _WamReqCore.GetSz( WRC_I_URL )
  1167. , _WamReqCore.GetSz( WRC_I_ISADLLPATH )
  1168. , m_fInProcess
  1169. , m_pIWamReqInproc
  1170. , m_gipIWamRequest
  1171. , m_pIWamReqSmartISA
  1172. , _dwFlags
  1173. , _dwChildExecFlags
  1174. , _cRefs
  1175. , _psExtension
  1176. , _AsyncIoInfo._dwOutstandingIO
  1177. , _AsyncIoInfo._pfnHseIO
  1178. , _AsyncIoInfo._pvHseIOContext
  1179. ));
  1180. return;
  1181. } // WAM_EXEC_INFO::Print()
  1182. #else
  1183. VOID WAM_EXEC_INFO::Print( VOID) const { }
  1184. #endif //DBG
  1185. #if DBG
  1186. void
  1187. DbgWamreqRefcounts
  1188. (
  1189. char* szPrefix,
  1190. WAM_EXEC_INFO * pWamExecInfo,
  1191. long cRefsWamRequest,
  1192. long cRefsWamReqContext
  1193. )
  1194. {
  1195. IWamRequest * pIWamRequest = NULL;
  1196. pWamExecInfo->GetIWamRequest( &pIWamRequest );
  1197. DBG_ASSERT( pIWamRequest );
  1198. IF_DEBUG( WAM_REFCOUNTS ) {
  1199. DBGPRINTF(( DBG_CONTEXT, szPrefix ));
  1200. DBGPRINTF(( DBG_CONTEXT, "\n" ));
  1201. }
  1202. HANDLE hCurrentUser = pWamExecInfo->FInProcess() ? NULL : INVALID_HANDLE_VALUE;
  1203. DoRevertHack( &hCurrentUser );
  1204. if( cRefsWamRequest != -1) {
  1205. DBG_ASSERT( cRefsWamRequest
  1206. == (long) pIWamRequest->DbgRefCount() );
  1207. }
  1208. if( cRefsWamReqContext != -1) {
  1209. DBG_ASSERT( cRefsWamReqContext
  1210. == (long) pWamExecInfo->DbgRefCount() );
  1211. }
  1212. IF_DEBUG( WAM_REFCOUNTS ) {
  1213. DBGPRINTF((
  1214. DBG_CONTEXT
  1215. , "IWamRequest(%p): RefCount = %d\n"
  1216. , pIWamRequest
  1217. , pIWamRequest->DbgRefCount()
  1218. ));
  1219. DBGPRINTF((
  1220. DBG_CONTEXT
  1221. , "WAM_EXEC_INFO(%p): RefCount = %d\n"
  1222. , pWamExecInfo, pWamExecInfo->DbgRefCount()
  1223. ));
  1224. }
  1225. UndoRevertHack( &hCurrentUser );
  1226. pWamExecInfo->ReleaseIWamRequest( pIWamRequest );
  1227. } // WAM_EXEC_INFO::DbgWamreqRefcounts
  1228. #endif // DBG
  1229. /************************************************************
  1230. * Static Member Functions of WAM_EXEC_INFO
  1231. ************************************************************/
  1232. BOOL
  1233. WAM_EXEC_INFO::InitClass( VOID)
  1234. {
  1235. HRESULT hr;
  1236. ALLOC_CACHE_CONFIGURATION acConfig = {
  1237. 1
  1238. , WAM_EXEC_INFO_CACHE_THRESHOLD
  1239. , sizeof(WAM_EXEC_INFO)
  1240. };
  1241. if ( NULL != sm_pachExecInfo) {
  1242. // already initialized
  1243. return ( TRUE );
  1244. }
  1245. hr = g_GIPAPI.Init();
  1246. if( FAILED( hr ) ) {
  1247. DBGPRINTF( (DBG_CONTEXT, "GIPAPI::Init Failed: %8.8x\n", hr) );
  1248. return ( FALSE );
  1249. }
  1250. sm_pachExecInfo = new ALLOC_CACHE_HANDLER( "WamExecInfo",
  1251. &acConfig);
  1252. #if DBG
  1253. sm_pDbgRefTraceLog = CreateRefTraceLog( C_REFTRACES_GLOBAL, 0 );
  1254. #endif
  1255. return ( NULL != sm_pachExecInfo);
  1256. } // WAM_EXEC_INFO::InitClass()
  1257. VOID
  1258. WAM_EXEC_INFO::CleanupClass( VOID)
  1259. {
  1260. HRESULT hr;
  1261. hr = g_GIPAPI.UnInit();
  1262. if( FAILED( hr ) ) {
  1263. DBGPRINTF( (DBG_CONTEXT, "GIPAPI::UnInit returned %8.8x\n", hr ) );
  1264. }
  1265. if ( NULL != sm_pachExecInfo) {
  1266. delete sm_pachExecInfo;
  1267. sm_pachExecInfo = NULL;
  1268. }
  1269. #if DBG
  1270. DestroyRefTraceLog( sm_pDbgRefTraceLog );
  1271. #endif
  1272. return;
  1273. } // WAM_EXEC_INFO::CleanupClass()
  1274. void *
  1275. WAM_EXEC_INFO::operator new( size_t s)
  1276. {
  1277. DBG_ASSERT( s == sizeof( WAM_EXEC_INFO));
  1278. // allocate from allocation cache.
  1279. DBG_ASSERT( NULL != sm_pachExecInfo);
  1280. return (sm_pachExecInfo->Alloc());
  1281. } // WAM_EXEC_INFO::operator new()
  1282. void
  1283. WAM_EXEC_INFO::operator delete( void * psi)
  1284. {
  1285. DBG_ASSERT( NULL != psi);
  1286. // free to the allocation pool
  1287. DBG_ASSERT( NULL != sm_pachExecInfo);
  1288. DBG_REQUIRE( sm_pachExecInfo->Free(psi));
  1289. return;
  1290. } // WAM_EXEC_INFO::operator delete()
  1291. /************************ End of File *********************************/