/*----------------------------------------------------------------------------- Copyright (c) 1995-1997 Microsoft Corporation Module Name : waminfo.hxx Abstract: Header file for WAMINFO object. Author: David Kaplan ( DaveK ) 11-Mar-1997 Environment: User Mode - Win32 Project: W3 services DLL -----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- Forward references -----------------------------------------------------------------------------*/ #include #include #include #ifndef __W3SVC_WAMINFO_HXX__ #define __W3SVC_WAMINFO_HXX__ #include "ptable.hxx" interface IWam; /*----------------------------------------------------------------------------- External definitions -----------------------------------------------------------------------------*/ typedef LONG (WINAPI * PFN_INTERLOCKED_COMPARE_EXCHANGE) ( LONG *Destination, LONG Exchange, LONG Comperand ); extern PFN_INTERLOCKED_COMPARE_EXCHANGE g_pfnInterlockedCompareExchange; HRESULT CreateWamRequestInstance ( HTTP_REQUEST * pHttpRequest, EXEC_DESCRIPTOR * pExec, const STR * pstrPath, CWamInfo * pWamInfo, WAM_REQUEST** ppWamRequestOut ); /*----------------------------------------------------------------------------- WAM States Explaination WIS_START This state is set in WamInfo constructor, and changed to WIS_RUNNING if Init() succeeded. Therefore, a WamInfo in either hashtable or dyinglist can not have this state. WIS_RUNNING This state indicates the WAMINFO in the hashtable is ok to serving requests. WIS_REPAIR This state indicates a thread is currently repair WAMINFO after it detects the outproc Wam pointer is nolonger reachable via RPC(a crash). This state is only applied to WamInfoOutProc. WIS_PAUSE This state indicates the application is paused by metabase setting, therefore, the WamInfo should be deleted such that next request will refresh the metabase setting again. WIS_CPUPAUSE This state indicates the application is paused by Job object control. An application is in a zombie state that it does not have IWAM pointer(and other stuff) since the out-proc mtx process is terminated. WIS_SHUTDOWN This state indicates the WamInfo is in a shutdown stage. Therefore, any new requests need to be rejected. WIS_ERROR This state indicates the WamInfo is in some weired error state.(Currently, it is not being used). WIS_END This state indicates the WamInfo is in destructor mode. General rules to change the state: Use ChangeToState(oldstate, newstate), check whether the return value is same as oldstate. -----------------------------------------------------------------------------*/ enum { WIS_START = 0, WIS_RUNNING, WIS_REPAIR, WIS_PAUSE, WIS_CPUPAUSE, WIS_ERROR, WIS_SHUTDOWN, WIS_END, WIS_MAX_STATE }; /*----------------------------------------------------------------------------- class CWamInfo: One-to-One relation with Wam object. -----------------------------------------------------------------------------*/ class CWamInfo { public: CWamInfo ( const STR &strMetabasePath, BOOL fInProcess, BOOL fInPool, BOOL fEnableTryExcept, REFGUID clsidWam ); virtual ~CWamInfo(void); void Reference(void); void Dereference(void); void RecycleLock(void); void RecycleUnlock(void); // ------------------------------------------------------------ // WAM INFO's public functions // ------------------------------------------------------------ HRESULT CreateWamInstance( DWORD dwContext ); virtual HRESULT Init ( WCHAR* wszPackageId, DWORD pidInetInfo ); virtual HRESULT UnInit(void); virtual void LeaveOOPZone(WAM_REQUEST * pWamRequest, BOOL fRecord); virtual HRESULT GetStatistics ( DWORD Level, LPWAM_STATISTICS_INFO pWamStatsInfo ); virtual void LoopWaitForActiveRequests ( INT cIgnoreRefs ); virtual HRESULT StartShutdown ( INT cIgnoreRefs ); // NOTE StartShutdown is non-virtual so derived class can use it virtual VOID NotifyGetInfoForName ( IN LPCSTR pszServerVariable ); virtual HRESULT DoProcessRequestCall ( IN IWam * pIWam, IN WAM_REQUEST * pWamRequest, OUT BOOL * pfHandled ); HRESULT ProcessAsyncIO ( WAM_REQUEST* pWamRequest, #ifdef _WIN64 UINT64 pWamExecInfoIn, // WamExecInfo * #else ULONG_PTR pWamExecInfoIn, // WamExecInfo * #endif DWORD dwStatus, DWORD cbWritten, LPBYTE lpOopReadData = NULL ); HRESULT ProcessWamRequest ( HTTP_REQUEST * pHttpRequest, EXEC_DESCRIPTOR * pExec, const STR * pstrPath, BOOL * pfHandled, BOOL * pfFinished ); DWORD ChangeToState(DWORD dwState); DWORD ChangeToState(DWORD dwOldState, DWORD dwNewState); DWORD QueryState(void) const; DWORD QueryCurrentRequests(void) const; virtual VOID ClearMembers(); IWam* QueryIWam(void) const; CProcessEntry* QueryProcessEntry(void) const; DWORD PidWam(void) const; DWORD FInProcess(void) const; HANDLE HWamProcess(void) const; const STR & QueryApplicationPath(void) const; BOOL FCurrentStateValid(void) const; LPCSTR CWamInfo::QueryKey() const; void Print(void) const; void Recycle ( DWORD dwTimeInSec ); DWORD QueryShutdownTimeLimit(void) const; protected: virtual HRESULT PreProcessWamRequest ( IN WAM_REQUEST* pWamRequest, IN HTTP_REQUEST* pHttpRequest, OUT IWam** ppIWam, OUT BOOL* pfHandled ); virtual HRESULT PostProcessRequest ( IN HRESULT hrIn, IN WAM_REQUEST * pWamRequest ); virtual HRESULT PreProcessAsyncIO ( IN WAM_REQUEST * pWamRequest, OUT IWam ** ppIWam ); public: LIST_ENTRY ListEntry; // Double link List node for linking to DyingList. LIST_ENTRY leProcess; // Double Link List node for linking to the process entry. BOOL m_fRecycled; DWORD m_dwRecycleSchedulerCookie; protected: DWORD m_dwSignature; IWam* m_pIWam; DWORD m_dwIWamGipCookie; // GIP cookie to get thread-valid pIWams CProcessEntry* m_pProcessEntry; LONG m_cRef; LONG m_cCurrentRequests; LONG m_cTotalRequests; DWORD m_dwState; BOOL m_fInProcess; BOOL m_fInPool; BOOL m_fEnableTryExcept; BOOL m_fShuttingDown; STR m_strApplicationPath; CLSID m_clsidWam; LONG m_cMaxRequests; DWORD m_dwShutdownTimeLimit; DWORD m_dwRecycleTime; static BOOL m_rgValidState[WIS_MAX_STATE]; CRITICAL_SECTION m_csRecycleLock; }; inline void CWamInfo::Reference(void) { // DBGPRINTF((DBG_CONTEXT, "CWamInfo %p AddRef, m_cRef %d\n", this, m_cRef+1)); InterlockedIncrement(&m_cRef); } inline void CWamInfo::Dereference(void) { DBG_ASSERT(m_cRef > 0); // DBGPRINTF((DBG_CONTEXT, "CWamInfo %p Release, m_cRef %d\n", this, m_cRef-1)); if ( 0 == InterlockedDecrement(&m_cRef) ) { delete this; } } inline DWORD CWamInfo::PidWam() const { return( m_pProcessEntry->QueryProcessId()); } inline HANDLE CWamInfo::HWamProcess() const { return( m_pProcessEntry->QueryProcessHandle() ); } inline DWORD CWamInfo::FInProcess() const { return( m_fInProcess ); } inline BOOL CWamInfo::FCurrentStateValid(void) const { return (m_rgValidState[m_dwState]); } inline DWORD CWamInfo::QueryState(void) const { return (m_dwState); } inline DWORD CWamInfo::QueryCurrentRequests(void) const { return (m_cCurrentRequests); } inline CProcessEntry* CWamInfo::QueryProcessEntry(void) const { return m_pProcessEntry; } inline DWORD CWamInfo::ChangeToState(DWORD eState) { return (DWORD)InterlockedExchange((LONG *)&m_dwState, eState); } inline DWORD CWamInfo::ChangeToState(DWORD eOldState, DWORD eNewState) { return (DWORD)(*g_pfnInterlockedCompareExchange)((LONG *)&m_dwState, (LONG)eNewState, (LONG)eOldState); } inline IWam* CWamInfo::QueryIWam(void) const { return m_pIWam; } inline const STR & CWamInfo::QueryApplicationPath(void) const { // returns the STR object containing the Application Root Path return ( m_strApplicationPath); } inline void CWamInfo::LeaveOOPZone(WAM_REQUEST * pWamRequest, BOOL fRecord) { // No Op. } inline HRESULT CWamInfo::PostProcessRequest ( IN HRESULT hrIn, IN WAM_REQUEST * pWamRequest ) { return NOERROR; } inline DWORD CWamInfo::QueryShutdownTimeLimit(void) const { return m_dwShutdownTimeLimit; } inline VOID CWamInfo::RecycleLock(void) { Reference(); EnterCriticalSection( &m_csRecycleLock ); } inline VOID CWamInfo::RecycleUnlock(void) { LeaveCriticalSection( &m_csRecycleLock ); Dereference(); } class CWamInfoHash : public CTypedHashTable { public: static const char* ExtractKey(const CWamInfo* pWamInfo); static DWORD CalcKeyHash(const char* pszKey); static bool EqualKeys(const char* pszKey1, const char* pszKey2); static void AddRefRecord(CWamInfo* pWamInfo, int nIncr); CWamInfoHash ( double maxload, // Bound on average chain length, size_t initsize, // Initial size of Hash Table size_t num_subtbls // #subordinate hash tables. ) : CTypedHashTable ("WamInfo", maxload, initsize, num_subtbls) {} }; inline const char* CWamInfoHash::ExtractKey(const CWamInfo* pWamInfo) { return pWamInfo->QueryKey(); } inline DWORD CWamInfoHash::CalcKeyHash(const char* pszKey) { return HashStringNoCase(pszKey); } inline bool CWamInfoHash::EqualKeys(const char* pszKey1, const char* pszKey2) { return (_stricmp(pszKey1, pszKey2) == 0); } inline void CWamInfoHash::AddRefRecord(CWamInfo* pWamInfo, int nIncr) { if (nIncr == 1) { pWamInfo->Reference(); } else { pWamInfo->Dereference(); } } //======================== CWamInfoOutProc ==================================== /*----------------------------------------------------------------------------- // COOPWamReqList // // class that contains link list head for OOP Wam Requests of a WAM instance. // -----------------------------------------------------------------------------*/ class COOPWamReqList { public: COOPWamReqList(void); ~COOPWamReqList(void); BOOL FTimeToCleanup(DWORD dwCurrentTime); BOOL FActive(void); void SetTimeStamp(void); LIST_ENTRY m_leRecoverListLink; // Link with other COOPWamReqList. LIST_ENTRY m_leOOPWamReqListHead; // Cleanup List Head private: DWORD m_dwTimeStamp; // TimeStamp for Cleanup Scheduler // (GetTickerCount) BOOL m_fActive; // FALSE if the corresponding Wam // crashed. }; /*----------------------------------------------------------------------------- // COOPWamReqList::SetTimeStamp // // Set time stamp when Out Proc Wam crashes. -----------------------------------------------------------------------------*/ inline void COOPWamReqList::SetTimeStamp(void) { m_dwTimeStamp = GetTickCount(); m_fActive = FALSE; } /*----------------------------------------------------------------------------- //COOPWamReqList::FActive // //Return whether the list is Active or not(m_fActive). -----------------------------------------------------------------------------*/ inline BOOL COOPWamReqList::FActive(void) { return m_fActive; } class CWamInfoOutProc : public CWamInfo { public: PLIST_ENTRY m_pCurrentListHead; // pointer to an OOPWamReq ListHead // with current valid OOP WAM. private: DWORD m_fInRepair; // flag indicates WamInfo in crash-recovery mode or not. DWORD m_fNoMoreRecovery; // flag indicates WamInfo failed to ReInitWam() or not. HANDLE m_hPermitOOPEvent; // Event that serve as a gate to OutofProc processing // Signaled when normal processing // Reset during the crash-recovery CRITICAL_SECTION m_csList; // Critical section for RecoverList. LIST_ENTRY m_rgRecoverListHead;// pointer to an Array of cleanup list DWORD m_dwThreshold; // Threshold for number of active cleanup list. DWORD m_dwWamVersion; // Current valid WAM verion number. DWORD m_cRecoverList; // # of active cleanup list in the system(started with 1) DWORD m_idScheduled; // Scheduler ID for Schedule a work item. BOOL m_fJobEnabled; PW3_SERVER_INSTANCE m_pwsiInstance; SV_CACHE_LIST m_svCache; public: CWamInfoOutProc ( const STR & strMetabasePath, BOOL fInProcess, BOOL fInPool, BOOL fEnableTryExcept, REFGUID clsidWam, DWORD dwThreshold, PW3_SERVER_INSTANCE pwiInstance, BOOL fJobEnabled, DWORD dwPeriodicRestartRequests, DWORD dwPeriodicRestartTime, DWORD dwShutdownTimeLimit ); virtual ~CWamInfoOutProc(); HRESULT GetStatistics ( DWORD Level, LPWAM_STATISTICS_INFO pWamStatsInfo ); static void WINAPI CleanupScheduled(void *pContext); VOID ClearMembers(); private: HRESULT PreProcessWamRequest ( IN WAM_REQUEST* pWamRequest, IN HTTP_REQUEST* pHttpRequest, OUT IWam** ppIWam, OUT BOOL* pfHandled ); HRESULT PostProcessRequest ( IN HRESULT hrIn, IN WAM_REQUEST * pWamRequest ); HRESULT PreProcessAsyncIO ( IN WAM_REQUEST * pWamRequest, OUT IWam ** ppIWam ); HRESULT Init ( IN WCHAR* wszPackageId, IN DWORD pidInetInfo ); HRESULT UnInit(void); VOID NotifyGetInfoForName ( IN LPCSTR pszServerVariable ); HRESULT DoProcessRequestCall ( IN IWam * pIWam, IN WAM_REQUEST * pWamRequest, OUT BOOL * pfHandled ); IWam * EnterOOPZone(WAM_REQUEST * pWamRequest, DWORD *pdwWamVersion, BOOL fRecord); void LeaveOOPZone(WAM_REQUEST * pWamRequest, BOOL fRecord); void LoopWaitForActiveRequests(INT cIgnoreRefs); BOOL FExceedCrashLimit(void); HRESULT Repair(void); HRESULT ReInitWam(void); BOOL FinalCleanup(void); BOOL CleanupAll(BOOL fScheduled); BOOL Cleanup(COOPWamReqList *pCleanupList); void LockList(void); void UnLockList(void); public: DWORD GetWamVersion(void); BOOL IsJobEnabled() {return m_fJobEnabled;}; }; inline BOOL CWamInfoOutProc::FExceedCrashLimit(void) { return (m_dwWamVersion >= m_dwThreshold || m_fNoMoreRecovery); } inline DWORD CWamInfoOutProc::GetWamVersion(void) { return ( m_dwWamVersion ); } inline void CWamInfoOutProc::LockList(void) { EnterCriticalSection(&m_csList); } inline void CWamInfoOutProc::UnLockList(void) { LeaveCriticalSection(&m_csList); } #endif __W3SVC_WAMINFO_HXX__