This commit is contained in:
Pavel Krymets 2018-04-03 12:50:24 -07:00
parent 6e54256fca
commit d63e8c5558
8 changed files with 151 additions and 155 deletions

View File

@ -179,6 +179,7 @@
<ClInclude Include="hostfxr_utility.h" />
<ClInclude Include="requesthandler.h" />
<ClInclude Include="resources.h" />
<ClInclude Include="SRWLockWrapper.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="utility.h" />
</ItemGroup>
@ -188,6 +189,7 @@
<ClCompile Include="fx_ver.cxx" />
<ClCompile Include="hostfxr_utility.cpp" />
<ClCompile Include="requesthandler.cxx" />
<ClCompile Include="SRWLockWrapper.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>

View File

@ -0,0 +1,13 @@
#include "stdafx.h"
#include "SRWLockWrapper.h"
SRWLockWrapper::SRWLockWrapper(const SRWLOCK& lock)
: m_lock(lock)
{
AcquireSRWLockExclusive(const_cast<SRWLOCK*>(&m_lock));
}
SRWLockWrapper::~SRWLockWrapper()
{
ReleaseSRWLockExclusive(const_cast<SRWLOCK*>(&m_lock));
}

View File

@ -0,0 +1,9 @@
#pragma once
class SRWLockWrapper
{
public:
SRWLockWrapper(const SRWLOCK& lock);
~SRWLockWrapper();
private:
const SRWLOCK& m_lock;
};

View File

@ -7,10 +7,10 @@ APPLICATION::APPLICATION(
_In_ IHttpServer* pHttpServer,
_In_ ASPNETCORE_CONFIG* pConfig) :
m_cRefs(1),
m_pHttpServer(pHttpServer),
m_pConfig(pConfig),
m_status(APPLICATION_STATUS::UNKNOWN)
{
UNREFERENCED_PARAMETER(pHttpServer);
}
APPLICATION::~APPLICATION()

View File

@ -18,7 +18,7 @@ class APPLICATION
{
public:
APPLICATION(
_In_ IHttpServer* pHttpServer,
_In_ IHttpServer* pHttpServer,
_In_ ASPNETCORE_CONFIG* pConfig);
virtual
@ -49,6 +49,5 @@ public:
protected:
mutable LONG m_cRefs;
volatile APPLICATION_STATUS m_status;
IHttpServer* m_pHttpServer;
ASPNETCORE_CONFIG* m_pConfig;
};

View File

@ -21,6 +21,7 @@
#include "..\IISLib\dbgutil.h"
#include "..\IISLib\ahutil.h"
#include "..\IISLib\hashfn.h"
#include "SRWLockWrapper.h"
#include "environmentvariablehash.h"
#include "utility.h"
#include "aspnetcoreconfig.h"

View File

@ -6,6 +6,7 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
IHttpServer* pHttpServer,
ASPNETCORE_CONFIG* pConfig) :
APPLICATION(pHttpServer, pConfig),
m_pHttpServer(pHttpServer),
m_ProcessExitCode(0),
m_hLogFileHandle(INVALID_HANDLE_VALUE),
m_hErrReadPipe(INVALID_HANDLE_VALUE),
@ -15,7 +16,8 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
m_fBlockCallbacksIntoManaged(FALSE),
m_fInitialized(FALSE),
m_fShutdownCalledFromNative(FALSE),
m_fShutdownCalledFromManaged(FALSE)
m_fShutdownCalledFromManaged(FALSE),
m_srwLock()
{
// is it guaranteed that we have already checked app offline at this point?
// If so, I don't think there is much to do here.
@ -57,8 +59,8 @@ IN_PROCESS_APPLICATION::ShutDown(
VOID
)
{
HANDLE hThread = NULL;
HRESULT hr = S_OK;
HRESULT hr = S_OK;
CHandle hThread;
DWORD dwThreadStatus = 0;
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
@ -67,15 +69,15 @@ IN_PROCESS_APPLICATION::ShutDown(
dwTimeout = INFINITE;
}
hThread = CreateThread(
hThread.Attach(CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)DoShutDown,
this, // thread function arguments
0, // default creation flags
NULL); // receive thread identifier
NULL)); // receive thread identifier
if (hThread == NULL)
if ((HANDLE)hThread == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
@ -95,12 +97,6 @@ IN_PROCESS_APPLICATION::ShutDown(
Finished:
if (hThread != NULL)
{
CloseHandle(hThread);
}
m_hThread = NULL;
if (FAILED(hr))
{
UTILITY::LogEventF(g_hEventLog,
@ -126,7 +122,6 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
HANDLE handle = NULL;
WIN32_FIND_DATA fileData;
BOOL fLocked = FALSE;
if (IsDebuggerPresent())
{
@ -137,41 +132,43 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
m_status == APPLICATION_STATUS::STARTING ||
m_status == APPLICATION_STATUS::FAIL)
{
goto Finished;
return;
}
AcquireSRWLockExclusive(&m_srwLock);
fLocked = TRUE;
if (m_fShutdownCalledFromNative ||
m_status == APPLICATION_STATUS::STARTING ||
m_status == APPLICATION_STATUS::FAIL)
{
goto Finished;
}
SRWLockWrapper lock(m_srwLock);
// We need to keep track of when both managed and native initiate shutdown
// to avoid AVs. If shutdown has already been initiated in managed, we don't want to call into
// managed. We still need to wait on main exiting no matter what. m_fShutdownCalledFromNative
// is used for detecting redundant calls and blocking more requests to OnExecuteRequestHandler.
m_fShutdownCalledFromNative = TRUE;
m_status = APPLICATION_STATUS::SHUTDOWN;
if (m_fShutdownCalledFromNative ||
m_status == APPLICATION_STATUS::STARTING ||
m_status == APPLICATION_STATUS::FAIL)
{
return;
}
// We need to keep track of when both managed and native initiate shutdown
// to avoid AVs. If shutdown has already been initiated in managed, we don't want to call into
// managed. We still need to wait on main exiting no matter what. m_fShutdownCalledFromNative
// is used for detecting redundant calls and blocking more requests to OnExecuteRequestHandler.
m_fShutdownCalledFromNative = TRUE;
m_status = APPLICATION_STATUS::SHUTDOWN;
if (!m_fShutdownCalledFromManaged)
{
// We cannot call into managed if the dll is detaching from the process.
// Calling into managed code when the dll is detaching is strictly a bad idea,
// and usually results in an AV saying "The string binding is invalid"
if (!g_fProcessDetach)
{
m_ShutdownHandler(m_ShutdownHandlerContext);
m_ShutdownHandler = NULL;
}
}
// Release the lock before we wait on the thread to exit.
}
if (!m_fShutdownCalledFromManaged)
{
// We cannot call into managed if the dll is detaching from the process.
// Calling into managed code when the dll is detaching is strictly a bad idea,
// and usually results in an AV saying "The string binding is invalid"
if (!g_fProcessDetach)
{
m_ShutdownHandler(m_ShutdownHandlerContext);
m_ShutdownHandler = NULL;
}
ReleaseSRWLockExclusive(&m_srwLock);
fLocked = FALSE;
// Release the lock before we wait on the thread to exit.
if (m_hThread != NULL &&
GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 &&
dwThreadStatus == STILL_ACTIVE)
@ -221,36 +218,32 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
// as nothing can be done
DeleteFile(m_struLogFilePath.QueryStr());
}
Finished:
if (fLocked)
{
ReleaseSRWLockExclusive(&m_srwLock);
}
return;
}
__override
VOID
IN_PROCESS_APPLICATION::Recycle(
VOID
)
{
BOOL fLockAcquired = FALSE;
// We need to guarantee that recycle is only called once, as calling pHttpServer->RecycleProcess
// multiple times can lead to AVs.
if (m_fRecycleCalled)
{
goto Finished;
return;
}
AcquireSRWLockExclusive(&m_srwLock);
fLockAcquired = TRUE;
if (m_fRecycleCalled)
{
goto Finished;
SRWLockWrapper lock(m_srwLock);
if (m_fRecycleCalled)
{
return;
}
m_fRecycleCalled = true;
}
if (!m_pHttpServer->IsCommandLineLaunch())
{
// IIS scenario.
@ -260,20 +253,10 @@ IN_PROCESS_APPLICATION::Recycle(
else
{
// IISExpress scenario
// Release the lock first as Shutdown will acquire lock later
ReleaseSRWLockExclusive(&m_srwLock);
fLockAcquired = FALSE;
// Shutdown the managed application and call exit to terminate current process
ShutDown();
exit(0);
}
Finished:
if (fLockAcquired)
{
ReleaseSRWLockExclusive(&m_srwLock);
}
}
REQUEST_NOTIFICATION_STATUS
@ -392,7 +375,6 @@ IN_PROCESS_APPLICATION::SetStdOut(
)
{
HRESULT hr = S_OK;
BOOL fLocked = FALSE;
STRU struPath;
SYSTEMTIME systemTime;
SECURITY_ATTRIBUTES saAttr = { 0 };
@ -402,8 +384,7 @@ IN_PROCESS_APPLICATION::SetStdOut(
if (!m_fDoneStdRedirect)
{
// Have not set stdout yet, redirect stdout to log file
AcquireSRWLockExclusive(&m_srwLock);
fLocked = TRUE;
SRWLockWrapper lock(m_srwLock);
if (!m_fDoneStdRedirect)
{
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
@ -553,10 +534,6 @@ IN_PROCESS_APPLICATION::SetStdOut(
Finished:
m_fDoneStdRedirect = TRUE;
if (fLocked)
{
ReleaseSRWLockExclusive(&m_srwLock);
}
if (FAILED(hr) && m_pConfig->QueryStdoutLogEnabled())
{
UTILITY::LogEventF(g_hEventLog,
@ -651,7 +628,6 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
HRESULT hr = S_OK;
DWORD dwTimeout;
DWORD dwResult;
BOOL fLocked = FALSE;
ReferenceApplication();
@ -674,84 +650,84 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
// Set up stdout redirect
SetStdOut();
AcquireSRWLockExclusive(&m_srwLock);
fLocked = TRUE;
if (m_status != APPLICATION_STATUS::STARTING)
{
if (m_status == APPLICATION_STATUS::FAIL)
SRWLockWrapper lock(m_srwLock);
if (m_status != APPLICATION_STATUS::STARTING)
{
if (m_status == APPLICATION_STATUS::FAIL)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
}
else if (m_status == APPLICATION_STATUS::SHUTDOWN)
{
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
}
goto Finished;
}
m_hThread = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)ExecuteAspNetCoreProcess,
this, // thread function arguments
0, // default creation flags
NULL); // receive thread identifier
if (m_hThread == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
m_pInitalizeEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual reset event
FALSE, // not set
NULL); // name
if (m_pInitalizeEvent == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
// If the debugger is attached, never timeout
if (IsDebuggerPresent())
{
dwTimeout = INFINITE;
}
else
{
dwTimeout = m_pConfig->QueryStartupTimeLimitInMS();
}
const HANDLE pHandles[2]{ m_hThread, m_pInitalizeEvent };
// Wait on either the thread to complete or the event to be set
dwResult = WaitForMultipleObjects(2, pHandles, FALSE, dwTimeout);
// It all timed out
if (dwResult == WAIT_TIMEOUT)
{
// kill the backend thread as loading dotnet timedout
TerminateThread(m_hThread, 0);
hr = HRESULT_FROM_WIN32(dwResult);
goto Finished;
}
else if (dwResult == WAIT_FAILED)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
// The thread ended it means that something failed
if (dwResult == WAIT_OBJECT_0)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
}
else if (m_status == APPLICATION_STATUS::SHUTDOWN)
{
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
goto Finished;
}
goto Finished;
m_status = APPLICATION_STATUS::RUNNING;
}
m_hThread = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)ExecuteAspNetCoreProcess,
this, // thread function arguments
0, // default creation flags
NULL); // receive thread identifier
if (m_hThread == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
m_pInitalizeEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual reset event
FALSE, // not set
NULL); // name
if (m_pInitalizeEvent == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
// If the debugger is attached, never timeout
if (IsDebuggerPresent())
{
dwTimeout = INFINITE;
}
else
{
dwTimeout = m_pConfig->QueryStartupTimeLimitInMS();
}
const HANDLE pHandles[2]{ m_hThread, m_pInitalizeEvent };
// Wait on either the thread to complete or the event to be set
dwResult = WaitForMultipleObjects(2, pHandles, FALSE, dwTimeout);
// It all timed out
if (dwResult == WAIT_TIMEOUT)
{
// kill the backend thread as loading dotnet timedout
TerminateThread(m_hThread, 0);
hr = HRESULT_FROM_WIN32(dwResult);
goto Finished;
}
else if (dwResult == WAIT_FAILED)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
// The thread ended it means that something failed
if (dwResult == WAIT_OBJECT_0)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
goto Finished;
}
m_status = APPLICATION_STATUS::RUNNING;
Finished:
if (FAILED(hr))
@ -766,12 +742,6 @@ Finished:
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
hr);
}
if (fLocked)
{
ReleaseSRWLockExclusive(&m_srwLock);
}
DereferenceApplication();
return hr;

View File

@ -110,6 +110,8 @@ private:
VOID
);
IHttpServer* const m_pHttpServer;
// Thread executing the .NET Core process
HANDLE m_hThread;