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

342 lines
8.6 KiB
C++

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1997 Microsoft Corporation. All Rights Reserved.
Component: MTA Callback
File: mtacb.cpp
Owner: DmitryR
This file contains the implementation of MTA callbacks
===================================================================*/
#include <w3p.hxx>
#include <process.h>
#pragma hdrstop
#include "MTAcb.h"
/*===================================================================
MTA Callback Thread
Worker thread that implements the MTA callback functionality
===================================================================*/
class CMTACallbackThread
{
private:
DWORD m_fInited : 1; // inited?
DWORD m_fCSInited : 1; // critical section inited?
DWORD m_fShutdown : 1; // shutdown?
CRITICAL_SECTION m_csLock; // callback critical section
HANDLE m_hDoItEvent; // callback requested event
HANDLE m_hDoneEvent; // callback done event
HANDLE m_hThread; // thread handle
PMTACALLBACK m_pMTACallback; // callback function ptr
void *m_pvContext; // arg1
void *m_pvContext2; // arg2
HRESULT m_hrResult; // return code
// The call callback from MTA thread
void DoCallback()
{
DBG_ASSERT(m_pMTACallback);
m_hrResult = (*m_pMTACallback)(m_pvContext, m_pvContext2);
}
// The thread function
static unsigned Thread(void *pvArg)
{
HRESULT hr;
DBG_ASSERT(pvArg);
CMTACallbackThread *pThread = (CMTACallbackThread *)pvArg;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // MTA
if (FAILED(hr))
{
// Bug 87857: Handle failure from CoInitialize
if (hr == E_INVALIDARG)
{
CoUninitialize();
}
// This shouldnt actually fail. Not entirely clear what to do if it does
DBG_ASSERT(FALSE);
return hr;
}
while (!pThread->m_fShutdown)
{
DWORD dwRet = MsgWaitForMultipleObjects
(
1,
&(pThread->m_hDoItEvent),
FALSE,
INFINITE,
QS_ALLINPUT
);
if (pThread->m_fShutdown)
break;
if (dwRet == WAIT_OBJECT_0)
{
// Event -> do the callback
pThread->DoCallback();
SetEvent(pThread->m_hDoneEvent);
}
else
{
// Do messages
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
DispatchMessage(&msg);
}
}
CoUninitialize();
return 0;
}
public:
// Constructor
CMTACallbackThread()
: m_fInited(FALSE), m_fCSInited(FALSE), m_fShutdown(FALSE),
m_hDoItEvent(NULL), m_hDoneEvent(NULL), m_hThread(NULL),
m_pMTACallback(NULL)
{
}
// Destructor
~CMTACallbackThread()
{
// Real cleanup is in UnInit()
// This is to cleanup after a bad Init()
if (m_fCSInited)
DeleteCriticalSection(&m_csLock);
if (m_hDoItEvent)
CloseHandle(m_hDoItEvent);
if (m_hDoneEvent)
CloseHandle(m_hDoneEvent);
}
// Init (real constructor)
HRESULT Init()
{
HRESULT hr = NOERROR;
if (SUCCEEDED(hr))
{
INITIALIZE_CRITICAL_SECTION(&m_csLock);
m_fCSInited = TRUE;
}
if (SUCCEEDED(hr))
{
m_hDoItEvent = IIS_CREATE_EVENT(
"CMTACallbackThread::m_hDoItEvent",
this,
FALSE,
FALSE
);
if (!m_hDoItEvent)
hr = E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
{
m_hDoneEvent = IIS_CREATE_EVENT(
"CMTACallbackThread::m_hDoneEvent",
this,
FALSE,
FALSE
);
if (!m_hDoneEvent)
hr = E_OUTOFMEMORY;
}
// Launch the MTA thread
unsigned threadId;
uintptr_t ulThread = _beginthreadex(NULL,
0,
CMTACallbackThread::Thread,
this,
0,
&threadId);
if (ulThread == 0xffffffff || ulThread == 0)
hr = E_OUTOFMEMORY;
else
m_hThread = (HANDLE)ulThread;
if (SUCCEEDED(hr))
m_fInited = TRUE;
return hr;
}
// UnInit (real destructor)
HRESULT UnInit()
{
DBG_ASSERT(m_fInited);
if (m_hThread)
{
// Kill the MTA thread
m_fShutdown = TRUE;
SetEvent(m_hDoItEvent);
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
m_hThread = NULL;
}
if (m_fCSInited)
{
DeleteCriticalSection(&m_csLock);
m_fCSInited = FALSE;
}
if (m_hDoItEvent)
{
CloseHandle(m_hDoItEvent);
m_hDoItEvent = NULL;
}
if (m_hDoneEvent)
{
CloseHandle(m_hDoneEvent);
m_hDoneEvent = NULL;
}
m_fInited = FALSE;
return NOERROR;
}
// Execute callback
HRESULT CallCallback
(
PMTACALLBACK pMTACallback,
void *pvContext,
void *pvContext2
)
{
if (m_fShutdown)
return E_FAIL;
DBG_ASSERT(m_fInited);
DBG_ASSERT(pMTACallback);
HRESULT hr = E_FAIL;
EnterCriticalSection(&m_csLock);
DBG_ASSERT(m_pMTACallback == NULL);
m_pMTACallback = pMTACallback;
m_pvContext = pvContext;
m_pvContext2 = pvContext2;
m_hrResult = E_FAIL;
// Tell MTA thread to call back
SetEvent(m_hDoItEvent);
// Wait till done
WaitForSingleObject(m_hDoneEvent, INFINITE);
// remember HRESULT
hr = m_hrResult;
// to make sure we never do it twice
m_pMTACallback = NULL;
LeaveCriticalSection(&m_csLock);
return hr;
}
};
// Sole instance of the above
static CMTACallbackThread *g_pMTACallbackThread = NULL;
/*===================================================================
E x t e r n a l A P I
===================================================================*/
/*===================================================================
InitMTACallbacks
To be called from DllInit()
Inits the MTA callback processing
Launches the MTA thread
Parameters
Returns:
HRESULT
===================================================================*/
HRESULT InitMTACallbacks()
{
g_pMTACallbackThread = new CMTACallbackThread;
if (g_pMTACallbackThread == NULL)
{
return E_OUTOFMEMORY;
}
return g_pMTACallbackThread->Init();
}
/*===================================================================
UnInitMTACallbacks
To be called from DllUnInit()
Stops the MTA callback processing
Kills the MTA thread
Parameters
Returns:
HRESULT
===================================================================*/
HRESULT UnInitMTACallbacks()
{
HRESULT hr = E_FAIL;
if (g_pMTACallbackThread != NULL)
{
hr = g_pMTACallbackThread->UnInit();
delete g_pMTACallbackThread;
g_pMTACallbackThread = NULL;
}
return hr;
}
/*===================================================================
CallMTACallback
Calls the hack.
Parameters
PMTACALLBACK pMTACallback call this function
void *pvContext pass this to it
void *pvContext2 extra arg
Returns:
HRESULT
===================================================================*/
HRESULT CallMTACallback
(
PMTACALLBACK pMTACallback,
void *pvContext,
void *pvContext2
)
{
return g_pMTACallbackThread->CallCallback
(
pMTACallback,
pvContext,
pvContext2
);
}