WindowsXP-SP1/inetcore/urlmon/mon/tls.cxx
2020-09-30 16:53:49 +02:00

487 lines
13 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: tls.cxx
//
// Contents: Thread Local Storage initialization and cleanup.
//
// Classes:
//
// Functions:
//
// History: 12-02-95 JohannP (Johann Posch) Created
//
//----------------------------------------------------------------------------
#include <mon.h>
#ifndef unix
#include "..\trans\transact.hxx"
#include "..\download\cdl.h"
#else
#include "../trans/transact.hxx"
#include "../download/cdl.h"
#endif /* unix */
#include <tls.h>
PerfDbgExtern(tagUrlDll)
DbgTag(tagUrlDllErr, "Urlmon", "Log CBinding Errors", DEB_BINDING|DEB_ERROR);
// Thread Local Storage index.
DWORD gTlsIndex;
HINSTANCE g_hInst = 0;
HANDLE g_hHeap = 0; // used for tls data
// Heap Handle
extern HANDLE g_hHeap;
#define HEAP_SERIALIZE 0
BOOL UnregisterUrlMkWndClass();
HRESULT DeleteOInetSession(DWORD dwReserved);
extern URLMON_TS* g_pHeadURLMONTSList;
HRESULT AddTSToList(URLMON_TS* pts)
{
CLock lck(g_mxsMedia);
pts->_pNext = g_pHeadURLMONTSList;
g_pHeadURLMONTSList = pts;
return NOERROR;
}
HRESULT RemoveTSFromList(DWORD tid)
{
// this can only be called from ThreadDetach time
CLock lck(g_mxsMedia);
URLMON_TS* pts = NULL;
URLMON_TS* ptsPrev = NULL;
pts = g_pHeadURLMONTSList;
while( pts )
{
if( pts->_dwTID == tid )
{
if( ptsPrev == NULL )
{
// this is the head of the list
g_pHeadURLMONTSList = pts->_pNext;
}
else
{
ptsPrev->_pNext = pts->_pNext;
}
// destroy the window
// can only be called from current thread
DestroyWindow(pts->_hwndNotify);
// delete pts
delete pts;
break;
}
// advance
ptsPrev = pts;
pts = pts->_pNext;
}
return NOERROR;
}
URLMON_TS* GetTS(DWORD tid)
{
CLock lck(g_mxsMedia);
URLMON_TS* pts = NULL;
pts = g_pHeadURLMONTSList;
while( pts )
{
if( pts->_dwTID == tid )
{
break;
}
// advance
pts = pts->_pNext;
}
return pts;
}
HRESULT CleanupTSOnProcessDetach()
{
CLock lck(g_mxsMedia);
URLMON_TS* pts = NULL;
URLMON_TS* ptsToFree = NULL;
pts = g_pHeadURLMONTSList;
while( pts )
{
if( pts->_dwTID == GetCurrentThreadId() )
{
// destroy the window (the owner thread can do so)
DestroyWindow(pts->_hwndNotify);
DbgLog2(
tagUrlDllErr,
NULL,
">>> tid: %lx -> DestroyWindow :%p",
pts->_dwTID,
pts->_hwndNotify
);
}
else
{
// we are on a thread different from the window owner
// so we can only Post message
// set wndproc to user32's
SetWindowLongPtr(
pts->_hwndNotify,
GWLP_WNDPROC,
(LONG_PTR)DefWindowProc);
// post message
PostMessage(pts->_hwndNotify, WM_CLOSE, 0, 0);
DbgLog2(
tagUrlDllErr,
NULL,
">>> tid: %lx -> PostMessage WM_CLOSE :%p",
pts->_dwTID,
pts->_hwndNotify
);
}
// save this pts since we are to free it
ptsToFree = pts;
// walk down the list
pts = pts->_pNext;
// free the pts
if( ptsToFree )
{
delete ptsToFree;
ptsToFree = NULL;
}
}
// mark list empty
g_pHeadURLMONTSList = NULL;
return NOERROR;
}
//+-------------------------------------------------------------------------
//
// Function: TLSAllocData
//
// Synopsis: Allocates the thread local storage block
//
// Returns: S_OK - allocated the data
// E_OUTOFMEMORY - could not allocate the data
//
//--------------------------------------------------------------------------
HRESULT CUrlMkTls::TLSAllocData(void)
{
Win4Assert(TlsGetValue(gTlsIndex) == 0);
Win4Assert(g_hHeap != NULL);
_pData = (SUrlMkTlsData *) HeapAlloc(g_hHeap, HEAP_SERIALIZE,
sizeof(SUrlMkTlsData));
if (_pData)
{
// This avoids having to set most fields to NULL, 0, etc and
// is needed cause on debug builds memory is not guaranteed to
// be zeroed.
memset(_pData, 0, sizeof(SUrlMkTlsData));
// fill in the non-zero values
_pData->dwFlags = URLMKTLS_LOCALTID;
#ifdef ENABLE_DEBUG
_pData->ThreadId = GetCurrentThreadId();
#endif // ENABLE_DEBUG
// store the data ptr in TLS
if (TlsSetValue(gTlsIndex, _pData))
{
return S_OK;
}
// error, cleanup and fallthru to error exit
HeapFree(g_hHeap, HEAP_SERIALIZE, _pData);
_pData = NULL;
}
UrlMkDebugOut((DEB_TRACE, "TLSAllocData failed.\n"));
return E_OUTOFMEMORY;
}
//+---------------------------------------------------------------------------
//
// Function: DoThreadCleanup
//
// Synopsis: Called to perform cleanup on all this threads data
// structures, and to call CoUninitialize() if needed.
//
// Could be called by DLL_THREAD_DETACH or DLL_PROCESS_DETACH
//
//
//----------------------------------------------------------------------------
extern CMutexSem g_mxsTransMgr;
void DoThreadCleanup(BOOL bInThreadDetach)
{
SUrlMkTlsData *pTls = (SUrlMkTlsData *) TlsGetValue(gTlsIndex);
if (pTls != NULL)
{
// Because of the DLL unload rules in NT we need to be careful
// what we do in clean up. We notify the routines with special
// behavior here.
pTls->dwFlags |= URLMKTLS_INTHREADDETACH;
if (pTls->pCTransMgr != NULL)
{
// If the Release() returns non-zero,
// AND we're not really in ThreadDetach, then we have other references on
// the Transaction Manager. Put back our reference and leave.
//
if (bInThreadDetach == FALSE)
{
CLock lck(g_mxsTransMgr);
if (pTls->pCTransMgr->Release())
{
pTls->pCTransMgr->AddRef();
pTls->dwFlags &= ~URLMKTLS_INTHREADDETACH;
goto Exit;
}
}
else
{
pTls->pCTransMgr->Release();
}
}
if (pTls->pCodeDownloadList != NULL)
{
delete pTls->pCodeDownloadList;
}
if (pTls->pRejectedFeaturesList != NULL)
{
LISTPOSITION curpos;
LPCWSTR pwszRejectedFeature = NULL;
int iNumRejected;
int i;
iNumRejected = pTls->pRejectedFeaturesList->GetCount();
curpos = pTls->pRejectedFeaturesList->GetHeadPosition();
// walk thru all the rejected features in the thread and delete
for (i=0; i < iNumRejected; i++) {
pwszRejectedFeature = pTls->pRejectedFeaturesList->GetNext(curpos);
delete (LPWSTR)pwszRejectedFeature;
}
delete pTls->pRejectedFeaturesList;
}
if (pTls->pSetupCookie != NULL)
{
delete pTls->pSetupCookie;
}
if (pTls->pTrustCookie != NULL)
{
delete pTls->pTrustCookie;
}
if (pTls->pCDLPacketMgr != NULL)
{
delete pTls->pCDLPacketMgr;
}
#ifdef PER_THREAD
if (pTls->pCMediaHolder != NULL)
{
delete pTls->pCMediaHolder;
}
#endif //PER_THREAD
// reset the index so we dont find this data again.
TlsSetValue(gTlsIndex, NULL);
// cleanup hwnd (not on TLS, but on urlmon's global table)
DWORD tid = GetCurrentThreadId();
if( GetTS(tid))
{
RemoveTSFromList(tid);
}
if (pTls->hwndUrlMkNotify != NULL)
{
DbgLog1(tagUrlDllErr, NULL, "ASSERT!!! tld: %lx ->hwnd !NULL", tid);
}
/*******************************************************************
if (pTls->hwndUrlMkNotify != NULL)
{
HWND h = pTls->hwndUrlMkNotify;
DestroyWindow(pTls->hwndUrlMkNotify);
}
********************************************************************/
HeapFree(g_hHeap, HEAP_SERIALIZE, pTls);
}
// else
// there is no TLS for this thread, so there can't be anything
// to cleanup.
Exit:;
}
//+-------------------------------------------------------------------------
//
// Function: TlsDllMain
//
// Synopsis: Dll entry point
//
// Arguments: [hIntance] -- a handle to the dll instance
// [dwReason] -- the reason LibMain was called
// [lpvReserved] - NULL - called due to FreeLibrary
// - non-NULL - called due to process exit
//
// Returns: TRUE on success, FALSE otherwise
//
// Notes: other one time initialization occurs in ctors for
// global objects
//
// WARNING: if we are called because of FreeLibrary, then we should do as
// much cleanup as we can. If we are called because of process
// termination, we should not do any cleanup, as other threads in
// this process will have already been killed, potentially while
// holding locks around resources.
//
//
//--------------------------------------------------------------------------
STDAPI_(BOOL) TlsDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved )
{
BOOL fResult = FALSE;
#if DBG==1 || defined(PERFTAGS)
if (dwReason == DLL_THREAD_ATTACH || dwReason == DLL_THREAD_DETACH)
PerfDbgLog1(tagUrlDll, NULL, "+TlsDllMain %s", dwReason == DLL_THREAD_ATTACH ?
"DLL_THREAD_ATTACH" : "DLL_THREAD_DETACH");
#endif
switch (dwReason)
{
case DLL_THREAD_ATTACH:
// new thread is starting
{
HRESULT hr;
CUrlMkTls tls(hr);
if (FAILED(hr))
{
goto ret;
}
}
break;
case DLL_THREAD_DETACH:
// Thread is exiting, clean up resources associated with threads.
DoThreadCleanup(TRUE);
break;
case DLL_PROCESS_ATTACH:
// Initial setup. Get a thread local storage index for use by OLE
g_hInst = hInstance;
if ((g_hHeap = GetProcessHeap()) == 0)
{
// can continue E_OUTOFMEMORY;
UrlMkAssert("Call GetProcessHeap failed.");
goto ret;
}
gTlsIndex = TlsAlloc();
if (gTlsIndex == 0xffffffff)
{
UrlMkAssert("Could not get TLS Index.");
goto ret;
}
{
HRESULT hr;
CUrlMkTls tls(hr);
if (FAILED(hr))
{
goto ret;
}
}
break;
case DLL_PROCESS_DETACH:
UrlMkDebugOut((DEB_DLL,"DLL_PROCESS_DETACH:\n"));
//if (NULL == lpvReserved)
{
// exiting because of FreeLibrary, so try to cleanup
// DLL_PROCESS_DETACH is called when we unload. The thread that is
// currently calling has not done thread specific cleanup yet.
//
DoThreadCleanup(TRUE);
UnregisterUrlMkWndClass();
if (g_pCMHolder != NULL)
{
UrlMkDebugOut((DEB_DLL | DEB_ITRACE,">>> DoThreadCleanup delete process pCMediaHolder:%p \n", g_pCMHolder));
delete g_pCMHolder;
g_pCMHolder = 0;
}
DeleteOInetSession(0);
if (g_hSession)
{
// BUGBUG: do not close the session handle - check with RFirth
InternetCloseHandle(g_hSession);
g_hSession = NULL;
}
TlsFree(gTlsIndex);
}
UrlMkDebugOut((DEB_DLL,"DLL_PROCESS_DETACH: done\n"));
break;
}
fResult = TRUE;
ret:
#if DBG==1 || defined(PERFTAGS)
if (dwReason == DLL_THREAD_ATTACH || dwReason == DLL_THREAD_DETACH)
PerfDbgLog(tagUrlDll, NULL, "-TlsDllMain");
#endif
return fResult;
}