Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: tls.cxx
  7. //
  8. // Contents: Thread Local Storage initialization and cleanup.
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 12-02-95 JohannP (Johann Posch) Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <mon.h>
  18. #ifndef unix
  19. #include "..\trans\transact.hxx"
  20. #include "..\download\cdl.h"
  21. #else
  22. #include "../trans/transact.hxx"
  23. #include "../download/cdl.h"
  24. #endif /* unix */
  25. #include <tls.h>
  26. PerfDbgExtern(tagUrlDll)
  27. DbgTag(tagUrlDllErr, "Urlmon", "Log CBinding Errors", DEB_BINDING|DEB_ERROR);
  28. // Thread Local Storage index.
  29. DWORD gTlsIndex;
  30. HINSTANCE g_hInst = 0;
  31. HANDLE g_hHeap = 0; // used for tls data
  32. // Heap Handle
  33. extern HANDLE g_hHeap;
  34. #define HEAP_SERIALIZE 0
  35. BOOL UnregisterUrlMkWndClass();
  36. HRESULT DeleteOInetSession(DWORD dwReserved);
  37. extern URLMON_TS* g_pHeadURLMONTSList;
  38. HRESULT AddTSToList(URLMON_TS* pts)
  39. {
  40. CLock lck(g_mxsMedia);
  41. pts->_pNext = g_pHeadURLMONTSList;
  42. g_pHeadURLMONTSList = pts;
  43. return NOERROR;
  44. }
  45. HRESULT RemoveTSFromList(DWORD tid)
  46. {
  47. // this can only be called from ThreadDetach time
  48. CLock lck(g_mxsMedia);
  49. URLMON_TS* pts = NULL;
  50. URLMON_TS* ptsPrev = NULL;
  51. pts = g_pHeadURLMONTSList;
  52. while( pts )
  53. {
  54. if( pts->_dwTID == tid )
  55. {
  56. if( ptsPrev == NULL )
  57. {
  58. // this is the head of the list
  59. g_pHeadURLMONTSList = pts->_pNext;
  60. }
  61. else
  62. {
  63. ptsPrev->_pNext = pts->_pNext;
  64. }
  65. // destroy the window
  66. // can only be called from current thread
  67. DestroyWindow(pts->_hwndNotify);
  68. // delete pts
  69. delete pts;
  70. break;
  71. }
  72. // advance
  73. ptsPrev = pts;
  74. pts = pts->_pNext;
  75. }
  76. return NOERROR;
  77. }
  78. URLMON_TS* GetTS(DWORD tid)
  79. {
  80. CLock lck(g_mxsMedia);
  81. URLMON_TS* pts = NULL;
  82. pts = g_pHeadURLMONTSList;
  83. while( pts )
  84. {
  85. if( pts->_dwTID == tid )
  86. {
  87. break;
  88. }
  89. // advance
  90. pts = pts->_pNext;
  91. }
  92. return pts;
  93. }
  94. HRESULT CleanupTSOnProcessDetach()
  95. {
  96. CLock lck(g_mxsMedia);
  97. URLMON_TS* pts = NULL;
  98. URLMON_TS* ptsToFree = NULL;
  99. pts = g_pHeadURLMONTSList;
  100. while( pts )
  101. {
  102. if( pts->_dwTID == GetCurrentThreadId() )
  103. {
  104. // destroy the window (the owner thread can do so)
  105. DestroyWindow(pts->_hwndNotify);
  106. DbgLog2(
  107. tagUrlDllErr,
  108. NULL,
  109. ">>> tid: %lx -> DestroyWindow :%p",
  110. pts->_dwTID,
  111. pts->_hwndNotify
  112. );
  113. }
  114. else
  115. {
  116. // we are on a thread different from the window owner
  117. // so we can only Post message
  118. // set wndproc to user32's
  119. SetWindowLongPtr(
  120. pts->_hwndNotify,
  121. GWLP_WNDPROC,
  122. (LONG_PTR)DefWindowProc);
  123. // post message
  124. PostMessage(pts->_hwndNotify, WM_CLOSE, 0, 0);
  125. DbgLog2(
  126. tagUrlDllErr,
  127. NULL,
  128. ">>> tid: %lx -> PostMessage WM_CLOSE :%p",
  129. pts->_dwTID,
  130. pts->_hwndNotify
  131. );
  132. }
  133. // save this pts since we are to free it
  134. ptsToFree = pts;
  135. // walk down the list
  136. pts = pts->_pNext;
  137. // free the pts
  138. if( ptsToFree )
  139. {
  140. delete ptsToFree;
  141. ptsToFree = NULL;
  142. }
  143. }
  144. // mark list empty
  145. g_pHeadURLMONTSList = NULL;
  146. return NOERROR;
  147. }
  148. //+-------------------------------------------------------------------------
  149. //
  150. // Function: TLSAllocData
  151. //
  152. // Synopsis: Allocates the thread local storage block
  153. //
  154. // Returns: S_OK - allocated the data
  155. // E_OUTOFMEMORY - could not allocate the data
  156. //
  157. //--------------------------------------------------------------------------
  158. HRESULT CUrlMkTls::TLSAllocData(void)
  159. {
  160. Win4Assert(TlsGetValue(gTlsIndex) == 0);
  161. Win4Assert(g_hHeap != NULL);
  162. _pData = (SUrlMkTlsData *) HeapAlloc(g_hHeap, HEAP_SERIALIZE,
  163. sizeof(SUrlMkTlsData));
  164. if (_pData)
  165. {
  166. // This avoids having to set most fields to NULL, 0, etc and
  167. // is needed cause on debug builds memory is not guaranteed to
  168. // be zeroed.
  169. memset(_pData, 0, sizeof(SUrlMkTlsData));
  170. // fill in the non-zero values
  171. _pData->dwFlags = URLMKTLS_LOCALTID;
  172. #ifdef ENABLE_DEBUG
  173. _pData->ThreadId = GetCurrentThreadId();
  174. #endif // ENABLE_DEBUG
  175. // store the data ptr in TLS
  176. if (TlsSetValue(gTlsIndex, _pData))
  177. {
  178. return S_OK;
  179. }
  180. // error, cleanup and fallthru to error exit
  181. HeapFree(g_hHeap, HEAP_SERIALIZE, _pData);
  182. _pData = NULL;
  183. }
  184. UrlMkDebugOut((DEB_TRACE, "TLSAllocData failed.\n"));
  185. return E_OUTOFMEMORY;
  186. }
  187. //+---------------------------------------------------------------------------
  188. //
  189. // Function: DoThreadCleanup
  190. //
  191. // Synopsis: Called to perform cleanup on all this threads data
  192. // structures, and to call CoUninitialize() if needed.
  193. //
  194. // Could be called by DLL_THREAD_DETACH or DLL_PROCESS_DETACH
  195. //
  196. //
  197. //----------------------------------------------------------------------------
  198. extern CMutexSem g_mxsTransMgr;
  199. void DoThreadCleanup(BOOL bInThreadDetach)
  200. {
  201. SUrlMkTlsData *pTls = (SUrlMkTlsData *) TlsGetValue(gTlsIndex);
  202. if (pTls != NULL)
  203. {
  204. // Because of the DLL unload rules in NT we need to be careful
  205. // what we do in clean up. We notify the routines with special
  206. // behavior here.
  207. pTls->dwFlags |= URLMKTLS_INTHREADDETACH;
  208. if (pTls->pCTransMgr != NULL)
  209. {
  210. // If the Release() returns non-zero,
  211. // AND we're not really in ThreadDetach, then we have other references on
  212. // the Transaction Manager. Put back our reference and leave.
  213. //
  214. if (bInThreadDetach == FALSE)
  215. {
  216. CLock lck(g_mxsTransMgr);
  217. if (pTls->pCTransMgr->Release())
  218. {
  219. pTls->pCTransMgr->AddRef();
  220. pTls->dwFlags &= ~URLMKTLS_INTHREADDETACH;
  221. goto Exit;
  222. }
  223. }
  224. else
  225. {
  226. pTls->pCTransMgr->Release();
  227. }
  228. }
  229. if (pTls->pCodeDownloadList != NULL)
  230. {
  231. delete pTls->pCodeDownloadList;
  232. }
  233. if (pTls->pRejectedFeaturesList != NULL)
  234. {
  235. LISTPOSITION curpos;
  236. LPCWSTR pwszRejectedFeature = NULL;
  237. int iNumRejected;
  238. int i;
  239. iNumRejected = pTls->pRejectedFeaturesList->GetCount();
  240. curpos = pTls->pRejectedFeaturesList->GetHeadPosition();
  241. // walk thru all the rejected features in the thread and delete
  242. for (i=0; i < iNumRejected; i++) {
  243. pwszRejectedFeature = pTls->pRejectedFeaturesList->GetNext(curpos);
  244. delete (LPWSTR)pwszRejectedFeature;
  245. }
  246. delete pTls->pRejectedFeaturesList;
  247. }
  248. if (pTls->pSetupCookie != NULL)
  249. {
  250. delete pTls->pSetupCookie;
  251. }
  252. if (pTls->pTrustCookie != NULL)
  253. {
  254. delete pTls->pTrustCookie;
  255. }
  256. if (pTls->pCDLPacketMgr != NULL)
  257. {
  258. delete pTls->pCDLPacketMgr;
  259. }
  260. #ifdef PER_THREAD
  261. if (pTls->pCMediaHolder != NULL)
  262. {
  263. delete pTls->pCMediaHolder;
  264. }
  265. #endif //PER_THREAD
  266. // reset the index so we dont find this data again.
  267. TlsSetValue(gTlsIndex, NULL);
  268. // cleanup hwnd (not on TLS, but on urlmon's global table)
  269. DWORD tid = GetCurrentThreadId();
  270. if( GetTS(tid))
  271. {
  272. RemoveTSFromList(tid);
  273. }
  274. if (pTls->hwndUrlMkNotify != NULL)
  275. {
  276. DbgLog1(tagUrlDllErr, NULL, "ASSERT!!! tld: %lx ->hwnd !NULL", tid);
  277. }
  278. /*******************************************************************
  279. if (pTls->hwndUrlMkNotify != NULL)
  280. {
  281. HWND h = pTls->hwndUrlMkNotify;
  282. DestroyWindow(pTls->hwndUrlMkNotify);
  283. }
  284. ********************************************************************/
  285. HeapFree(g_hHeap, HEAP_SERIALIZE, pTls);
  286. }
  287. // else
  288. // there is no TLS for this thread, so there can't be anything
  289. // to cleanup.
  290. Exit:;
  291. }
  292. //+-------------------------------------------------------------------------
  293. //
  294. // Function: TlsDllMain
  295. //
  296. // Synopsis: Dll entry point
  297. //
  298. // Arguments: [hIntance] -- a handle to the dll instance
  299. // [dwReason] -- the reason LibMain was called
  300. // [lpvReserved] - NULL - called due to FreeLibrary
  301. // - non-NULL - called due to process exit
  302. //
  303. // Returns: TRUE on success, FALSE otherwise
  304. //
  305. // Notes: other one time initialization occurs in ctors for
  306. // global objects
  307. //
  308. // WARNING: if we are called because of FreeLibrary, then we should do as
  309. // much cleanup as we can. If we are called because of process
  310. // termination, we should not do any cleanup, as other threads in
  311. // this process will have already been killed, potentially while
  312. // holding locks around resources.
  313. //
  314. //
  315. //--------------------------------------------------------------------------
  316. STDAPI_(BOOL) TlsDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved )
  317. {
  318. BOOL fResult = FALSE;
  319. #if DBG==1 || defined(PERFTAGS)
  320. if (dwReason == DLL_THREAD_ATTACH || dwReason == DLL_THREAD_DETACH)
  321. PerfDbgLog1(tagUrlDll, NULL, "+TlsDllMain %s", dwReason == DLL_THREAD_ATTACH ?
  322. "DLL_THREAD_ATTACH" : "DLL_THREAD_DETACH");
  323. #endif
  324. switch (dwReason)
  325. {
  326. case DLL_THREAD_ATTACH:
  327. // new thread is starting
  328. {
  329. HRESULT hr;
  330. CUrlMkTls tls(hr);
  331. if (FAILED(hr))
  332. {
  333. goto ret;
  334. }
  335. }
  336. break;
  337. case DLL_THREAD_DETACH:
  338. // Thread is exiting, clean up resources associated with threads.
  339. DoThreadCleanup(TRUE);
  340. break;
  341. case DLL_PROCESS_ATTACH:
  342. // Initial setup. Get a thread local storage index for use by OLE
  343. g_hInst = hInstance;
  344. if ((g_hHeap = GetProcessHeap()) == 0)
  345. {
  346. // can continue E_OUTOFMEMORY;
  347. UrlMkAssert("Call GetProcessHeap failed.");
  348. goto ret;
  349. }
  350. gTlsIndex = TlsAlloc();
  351. if (gTlsIndex == 0xffffffff)
  352. {
  353. UrlMkAssert("Could not get TLS Index.");
  354. goto ret;
  355. }
  356. {
  357. HRESULT hr;
  358. CUrlMkTls tls(hr);
  359. if (FAILED(hr))
  360. {
  361. goto ret;
  362. }
  363. }
  364. break;
  365. case DLL_PROCESS_DETACH:
  366. UrlMkDebugOut((DEB_DLL,"DLL_PROCESS_DETACH:\n"));
  367. //if (NULL == lpvReserved)
  368. {
  369. // exiting because of FreeLibrary, so try to cleanup
  370. // DLL_PROCESS_DETACH is called when we unload. The thread that is
  371. // currently calling has not done thread specific cleanup yet.
  372. //
  373. DoThreadCleanup(TRUE);
  374. UnregisterUrlMkWndClass();
  375. if (g_pCMHolder != NULL)
  376. {
  377. UrlMkDebugOut((DEB_DLL | DEB_ITRACE,">>> DoThreadCleanup delete process pCMediaHolder:%p \n", g_pCMHolder));
  378. delete g_pCMHolder;
  379. g_pCMHolder = 0;
  380. }
  381. DeleteOInetSession(0);
  382. if (g_hSession)
  383. {
  384. // BUGBUG: do not close the session handle - check with RFirth
  385. InternetCloseHandle(g_hSession);
  386. g_hSession = NULL;
  387. }
  388. TlsFree(gTlsIndex);
  389. }
  390. UrlMkDebugOut((DEB_DLL,"DLL_PROCESS_DETACH: done\n"));
  391. break;
  392. }
  393. fResult = TRUE;
  394. ret:
  395. #if DBG==1 || defined(PERFTAGS)
  396. if (dwReason == DLL_THREAD_ATTACH || dwReason == DLL_THREAD_DETACH)
  397. PerfDbgLog(tagUrlDll, NULL, "-TlsDllMain");
  398. #endif
  399. return fResult;
  400. }