aspnetcore/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.h

197 lines
5.0 KiB
C++

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma once
#define ONE_MINUTE_IN_MILLISECONDS 60000
class SERVER_PROCESS;
class PROCESS_MANAGER
{
public:
virtual
~PROCESS_MANAGER();
VOID
ReferenceProcessManager() const
{
InterlockedIncrement(&m_cRefs);
}
VOID
DereferenceProcessManager() const
{
if (InterlockedDecrement(&m_cRefs) == 0)
{
delete this;
}
}
HRESULT
GetProcess(
_In_ REQUESTHANDLER_CONFIG *pConfig,
_In_ BOOL fWebsocketEnabled,
_Out_ SERVER_PROCESS **ppServerProcess
);
HANDLE
QueryNULHandle()
{
return m_hNULHandle;
}
HRESULT
Initialize(
VOID
);
VOID
SendShutdownSignal()
{
AcquireSRWLockExclusive( &m_srwLock );
for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
{
if( m_ppServerProcessList != NULL &&
m_ppServerProcessList[i] != NULL )
{
m_ppServerProcessList[i]->SendSignal();
m_ppServerProcessList[i]->DereferenceServerProcess();
m_ppServerProcessList[i] = NULL;
}
}
ReleaseSRWLockExclusive( &m_srwLock );
}
VOID
ShutdownProcess(
SERVER_PROCESS* pServerProcess
)
{
AcquireSRWLockExclusive( &m_srwLock );
ShutdownProcessNoLock( pServerProcess );
ReleaseSRWLockExclusive( &m_srwLock );
}
VOID
ShutdownAllProcesses(
)
{
AcquireSRWLockExclusive( &m_srwLock );
ShutdownAllProcessesNoLock();
ReleaseSRWLockExclusive( &m_srwLock );
}
VOID
IncrementRapidFailCount(
VOID
)
{
InterlockedIncrement(&m_cRapidFailCount);
}
PROCESS_MANAGER() :
m_ppServerProcessList( NULL ),
m_hNULHandle( NULL ),
m_cRapidFailCount( 0 ),
m_dwProcessesPerApplication( 1 ),
m_dwRouteToProcessIndex( 0 ),
m_fServerProcessListReady(FALSE),
m_cRefs( 1 )
{
m_ppServerProcessList = NULL;
m_fServerProcessListReady = FALSE;
InitializeSRWLock( &m_srwLock );
}
private:
BOOL
RapidFailsPerMinuteExceeded(
LONG dwRapidFailsPerMinute
)
{
DWORD dwCurrentTickCount = GetTickCount();
if( (dwCurrentTickCount - m_dwRapidFailTickStart)
>= ONE_MINUTE_IN_MILLISECONDS )
{
//
// reset counters every minute.
//
InterlockedExchange(&m_cRapidFailCount, 0);
m_dwRapidFailTickStart = dwCurrentTickCount;
}
return m_cRapidFailCount > dwRapidFailsPerMinute;
}
VOID
ShutdownProcessNoLock(
SERVER_PROCESS* pServerProcess
)
{
for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
{
if( m_ppServerProcessList != NULL &&
m_ppServerProcessList[i] != NULL &&
m_ppServerProcessList[i]->GetPort() == pServerProcess->GetPort() )
{
// shutdown pServerProcess if not already shutdown.
m_ppServerProcessList[i]->StopProcess();
m_ppServerProcessList[i]->DereferenceServerProcess();
m_ppServerProcessList[i] = NULL;
}
}
}
VOID
ShutdownAllProcessesNoLock(
VOID
)
{
for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
{
if( m_ppServerProcessList != NULL &&
m_ppServerProcessList[i] != NULL )
{
// shutdown pServerProcess if not already shutdown.
m_ppServerProcessList[i]->SendSignal();
m_ppServerProcessList[i]->DereferenceServerProcess();
m_ppServerProcessList[i] = NULL;
}
}
}
volatile LONG m_cRapidFailCount;
DWORD m_dwRapidFailTickStart;
DWORD m_dwProcessesPerApplication;
volatile DWORD m_dwRouteToProcessIndex;
SRWLOCK m_srwLock;
SERVER_PROCESS **m_ppServerProcessList;
//
// m_hNULHandle is used to redirect stdout/stderr to NUL.
// If Createprocess is called to launch a batch file for example,
// it tries to write to the console buffer by default. It fails to
// start if the console buffer is owned by the parent process i.e
// in our case w3wp.exe. So we have to redirect the stdout/stderr
// of the child process to NUL or to a file (anything other than
// the console buffer of the parent process).
//
HANDLE m_hNULHandle;
mutable LONG m_cRefs;
volatile static BOOL sm_fWSAStartupDone;
volatile BOOL m_fServerProcessListReady;
};