|
|
//+---------------------------------------------------------------------------
//
// 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; }
|