windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/w3/server/waminfo.hxx
2020-09-26 16:20:57 +08:00

627 lines
18 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*-----------------------------------------------------------------------------
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 <lkrhash.h>
#include <svmap.h>
#include <issched.hxx>
#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<CWamInfoHash, CWamInfo, const char*>
{
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<CWamInfoHash, CWamInfo, const char*>
("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__