afxtls.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #include <stddef.h>
  12. #ifdef AFX_INIT_SEG
  13. #pragma code_seg(AFX_INIT_SEG)
  14. #endif
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CSimpleList
  21. void CSimpleList::AddHead(void* p)
  22. {
  23. ASSERT(p != NULL);
  24. ASSERT(*GetNextPtr(p) == NULL);
  25. *GetNextPtr(p) = m_pHead;
  26. m_pHead = p;
  27. }
  28. BOOL CSimpleList::Remove(void* p)
  29. {
  30. ASSERT(p != NULL);
  31. if (m_pHead == NULL)
  32. return FALSE;
  33. BOOL bResult = FALSE;
  34. if (m_pHead == p)
  35. {
  36. m_pHead = *GetNextPtr(p);
  37. DEBUG_ONLY(*GetNextPtr(p) = NULL);
  38. bResult = TRUE;
  39. }
  40. else
  41. {
  42. void* pTest = m_pHead;
  43. while (pTest != NULL && *GetNextPtr(pTest) != p)
  44. pTest = *GetNextPtr(pTest);
  45. if (pTest != NULL)
  46. {
  47. *GetNextPtr(pTest) = *GetNextPtr(p);
  48. DEBUG_ONLY(*GetNextPtr(p) = NULL);
  49. bResult = TRUE;
  50. }
  51. }
  52. return bResult;
  53. }
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CNoTrackObject
  56. #if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
  57. void* PASCAL CNoTrackObject::operator new(size_t nSize, LPCSTR, int)
  58. {
  59. return CNoTrackObject::operator new(nSize);
  60. }
  61. #if _MSC_VER >= 1200
  62. void PASCAL CNoTrackObject::operator delete(void* pObject, LPCSTR, int)
  63. {
  64. if (pObject != NULL)
  65. ::LocalFree(pObject);
  66. }
  67. #endif
  68. #endif
  69. void* PASCAL CNoTrackObject::operator new(size_t nSize)
  70. {
  71. void* p = ::LocalAlloc(LPTR, nSize);
  72. if (p == NULL)
  73. AfxThrowMemoryException();
  74. return p;
  75. }
  76. void PASCAL CNoTrackObject::operator delete(void* p)
  77. {
  78. if (p != NULL)
  79. ::LocalFree(p);
  80. }
  81. /////////////////////////////////////////////////////////////////////////////
  82. // CThreadSlotData
  83. // global _afxThreadData used to allocate thread local indexes
  84. BYTE __afxThreadData[sizeof(CThreadSlotData)];
  85. CThreadSlotData* _afxThreadData;
  86. struct CThreadData : public CNoTrackObject
  87. {
  88. CThreadData* pNext; // required to be member of CSimpleList
  89. int nCount; // current size of pData
  90. LPVOID* pData; // actual thread local data (indexed by nSlot)
  91. };
  92. struct CSlotData
  93. {
  94. DWORD dwFlags; // slot flags (allocated/not allocated)
  95. HINSTANCE hInst; // module which owns this slot
  96. };
  97. // flags used for CSlotData::dwFlags above
  98. #define SLOT_USED 0x01 // slot is allocated
  99. __declspec(nothrow) CThreadSlotData::CThreadSlotData()
  100. {
  101. m_list.Construct(offsetof(CThreadData, pNext));
  102. // initialize state and allocate TLS index
  103. m_nAlloc = 0;
  104. m_nRover = 1; // first slot (0) is always reserved
  105. m_nMax = 0;
  106. m_pSlotData = NULL;
  107. // init m_tlsIndex to -1 if !bThreadLocal, otherwise TlsAlloc
  108. m_tlsIndex = TlsAlloc();
  109. if (m_tlsIndex == (DWORD)-1)
  110. AfxThrowMemoryException();
  111. InitializeCriticalSection(&m_sect);
  112. }
  113. CThreadSlotData::~CThreadSlotData()
  114. {
  115. if (m_tlsIndex != (DWORD)-1)
  116. {
  117. TlsFree(m_tlsIndex);
  118. DEBUG_ONLY(m_tlsIndex = (DWORD)-1);
  119. }
  120. CThreadData* pData = m_list;
  121. while (pData != NULL)
  122. {
  123. CThreadData* pDataNext = pData->pNext;
  124. DeleteValues(pData, NULL);
  125. pData = pDataNext;
  126. }
  127. if (m_pSlotData != NULL)
  128. {
  129. HGLOBAL hSlotData = GlobalHandle(m_pSlotData);
  130. GlobalUnlock(hSlotData);
  131. GlobalFree(hSlotData);
  132. DEBUG_ONLY(m_pSlotData = NULL);
  133. }
  134. DeleteCriticalSection(&m_sect);
  135. }
  136. int CThreadSlotData::AllocSlot()
  137. {
  138. EnterCriticalSection(&m_sect);
  139. int nAlloc = m_nAlloc;
  140. int nSlot = m_nRover;
  141. if (nSlot >= nAlloc || (m_pSlotData[nSlot].dwFlags & SLOT_USED))
  142. {
  143. // search for first free slot, starting at beginning
  144. for (nSlot = 1;
  145. nSlot < nAlloc && (m_pSlotData[nSlot].dwFlags & SLOT_USED); nSlot++)
  146. ;
  147. // if none found, need to allocate more space
  148. if (nSlot >= nAlloc)
  149. {
  150. // realloc memory for the bit array and the slot memory
  151. int nNewAlloc = m_nAlloc+32;
  152. // m_pSlotData is allocated GMEM_SHARE because on Win32s it needs
  153. // to be shared between processes (memory is owned by the MFC DLL).
  154. HGLOBAL hSlotData;
  155. if (m_pSlotData == NULL)
  156. {
  157. hSlotData = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,
  158. nNewAlloc*sizeof(CSlotData));
  159. }
  160. else
  161. {
  162. hSlotData = GlobalHandle(m_pSlotData);
  163. GlobalUnlock(hSlotData);
  164. hSlotData = GlobalReAlloc(hSlotData, nNewAlloc*sizeof(CSlotData),
  165. GMEM_MOVEABLE|GMEM_SHARE);
  166. }
  167. if (hSlotData == NULL)
  168. {
  169. GlobalLock(GlobalHandle(m_pSlotData));
  170. LeaveCriticalSection(&m_sect);
  171. AfxThrowMemoryException();
  172. }
  173. CSlotData* pSlotData = (CSlotData*)GlobalLock(hSlotData);
  174. // always zero initialize after success
  175. memset(pSlotData+m_nAlloc, 0, (nNewAlloc-m_nAlloc)*sizeof(CSlotData));
  176. m_nAlloc = nNewAlloc;
  177. m_pSlotData = pSlotData;
  178. }
  179. }
  180. ASSERT(nSlot != 0); // first slot (0) is reserved
  181. // adjust m_nMax to largest slot ever allocated
  182. if (nSlot >= m_nMax)
  183. m_nMax = nSlot+1;
  184. ASSERT(!(m_pSlotData[nSlot].dwFlags & SLOT_USED));
  185. m_pSlotData[nSlot].dwFlags |= SLOT_USED;
  186. // update m_nRover (likely place to find a free slot is next one)
  187. m_nRover = nSlot+1;
  188. LeaveCriticalSection(&m_sect);
  189. return nSlot; // slot can be used for FreeSlot, GetValue, SetValue
  190. }
  191. void CThreadSlotData::FreeSlot(int nSlot)
  192. {
  193. EnterCriticalSection(&m_sect);
  194. ASSERT(nSlot != 0 && nSlot < m_nMax);
  195. ASSERT(m_pSlotData != NULL);
  196. ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
  197. // delete the data from all threads/processes
  198. CThreadData* pData = m_list;
  199. while (pData != NULL)
  200. {
  201. if (nSlot < pData->nCount)
  202. {
  203. delete (CNoTrackObject*)pData->pData[nSlot];
  204. pData->pData[nSlot] = NULL;
  205. }
  206. pData = pData->pNext;
  207. }
  208. // free the slot itself
  209. m_pSlotData[nSlot].dwFlags &= ~SLOT_USED;
  210. LeaveCriticalSection(&m_sect);
  211. }
  212. // special version of CThreadSlotData::GetData that only works with
  213. // thread local storage (and not process local storage)
  214. // this version is inlined and simplified for speed
  215. inline void* CThreadSlotData::GetThreadValue(int nSlot)
  216. {
  217. ASSERT(nSlot != 0 && nSlot < m_nMax);
  218. ASSERT(m_pSlotData != NULL);
  219. ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
  220. ASSERT(m_tlsIndex != (DWORD)-1);
  221. CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
  222. if (pData == NULL || nSlot >= pData->nCount)
  223. return NULL;
  224. return pData->pData[nSlot];
  225. }
  226. void CThreadSlotData::SetValue(int nSlot, void* pValue)
  227. {
  228. ASSERT(nSlot != 0 && nSlot < m_nMax);
  229. ASSERT(m_pSlotData != NULL);
  230. ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
  231. CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
  232. if (pData == NULL || nSlot >= pData->nCount && pValue != NULL)
  233. {
  234. // if pData is NULL then this thread has not been visited yet
  235. if (pData == NULL)
  236. {
  237. pData = new CThreadData;
  238. pData->nCount = 0;
  239. pData->pData = NULL;
  240. DEBUG_ONLY(pData->pNext = NULL);
  241. // protect while adding to global list
  242. EnterCriticalSection(&m_sect);
  243. m_list.AddHead(pData);
  244. LeaveCriticalSection(&m_sect);
  245. }
  246. // grow to now current size
  247. if (pData->pData == NULL)
  248. pData->pData = (void**)LocalAlloc(LMEM_FIXED, m_nMax*sizeof(LPVOID));
  249. else
  250. pData->pData = (void**)LocalReAlloc(pData->pData, m_nMax*sizeof(LPVOID),
  251. LMEM_MOVEABLE);
  252. if (pData->pData == NULL)
  253. AfxThrowMemoryException();
  254. // initialize the newly allocated part
  255. memset(pData->pData + pData->nCount, 0,
  256. (m_nMax - pData->nCount) * sizeof(LPVOID));
  257. pData->nCount = m_nMax;
  258. TlsSetValue(m_tlsIndex, pData);
  259. }
  260. ASSERT(pData->pData != NULL && nSlot < pData->nCount);
  261. pData->pData[nSlot] = pValue;
  262. }
  263. void CThreadSlotData::AssignInstance(HINSTANCE hInst)
  264. {
  265. EnterCriticalSection(&m_sect);
  266. ASSERT(m_pSlotData != NULL);
  267. ASSERT(hInst != NULL);
  268. for (int i = 1; i < m_nMax; i++)
  269. {
  270. if (m_pSlotData[i].hInst == NULL && (m_pSlotData[i].dwFlags & SLOT_USED))
  271. m_pSlotData[i].hInst = hInst;
  272. }
  273. LeaveCriticalSection(&m_sect);
  274. }
  275. void CThreadSlotData::DeleteValues(CThreadData* pData, HINSTANCE hInst)
  276. {
  277. // Note: does not lock critical section because only meant to be called
  278. // from DeleteValues(HINSTANCE, BOOL).
  279. ASSERT(pData != NULL);
  280. // free each element in the table
  281. BOOL bDelete = TRUE;
  282. for (int i = 1; i < pData->nCount; i++)
  283. {
  284. if (hInst == NULL || m_pSlotData[i].hInst == hInst)
  285. {
  286. // delete the data since hInst matches (or is NULL)
  287. delete (CNoTrackObject*)pData->pData[i];
  288. pData->pData[i] = NULL;
  289. }
  290. else if (pData->pData[i] != NULL)
  291. {
  292. // don't delete thread data if other modules still alive
  293. bDelete = FALSE;
  294. }
  295. }
  296. if (bDelete)
  297. {
  298. // remove from master list and free it
  299. EnterCriticalSection(&m_sect);
  300. m_list.Remove(pData);
  301. LeaveCriticalSection(&m_sect);
  302. LocalFree(pData->pData);
  303. delete pData;
  304. // clear TLS index to prevent from re-use
  305. TlsSetValue(m_tlsIndex, NULL);
  306. }
  307. }
  308. void CThreadSlotData::DeleteValues(HINSTANCE hInst, BOOL bAll)
  309. {
  310. EnterCriticalSection(&m_sect);
  311. if (!bAll)
  312. {
  313. // delete the values only for the current thread
  314. CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
  315. if (pData != NULL)
  316. DeleteValues(pData, hInst);
  317. }
  318. else
  319. {
  320. // delete the values for all threads
  321. CThreadData* pData = m_list;
  322. while (pData != NULL)
  323. {
  324. CThreadData* pDataNext = pData->pNext;
  325. DeleteValues(pData, hInst);
  326. pData = pDataNext;
  327. }
  328. }
  329. LeaveCriticalSection(&m_sect);
  330. }
  331. /////////////////////////////////////////////////////////////////////////////
  332. // CThreadLocalObject
  333. CNoTrackObject* CThreadLocalObject::GetData(
  334. CNoTrackObject* (AFXAPI* pfnCreateObject)())
  335. {
  336. if (m_nSlot == 0)
  337. {
  338. if (_afxThreadData == NULL)
  339. {
  340. _afxThreadData = new(__afxThreadData) CThreadSlotData;
  341. ASSERT(_afxThreadData != NULL);
  342. }
  343. m_nSlot = _afxThreadData->AllocSlot();
  344. ASSERT(m_nSlot != 0);
  345. }
  346. CNoTrackObject* pValue =
  347. (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
  348. if (pValue == NULL)
  349. {
  350. // allocate zero-init object
  351. pValue = (*pfnCreateObject)();
  352. // set tls data to newly created object
  353. _afxThreadData->SetValue(m_nSlot, pValue);
  354. ASSERT(_afxThreadData->GetThreadValue(m_nSlot) == pValue);
  355. }
  356. return pValue;
  357. }
  358. CNoTrackObject* CThreadLocalObject::GetDataNA()
  359. {
  360. if (m_nSlot == 0 || _afxThreadData == NULL)
  361. return NULL;
  362. CNoTrackObject* pValue =
  363. (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
  364. return pValue;
  365. }
  366. CThreadLocalObject::~CThreadLocalObject()
  367. {
  368. if (m_nSlot != 0 && _afxThreadData != NULL)
  369. _afxThreadData->FreeSlot(m_nSlot);
  370. m_nSlot = 0;
  371. }
  372. /////////////////////////////////////////////////////////////////////////////
  373. // CProcessLocalData
  374. CNoTrackObject* CProcessLocalObject::GetData(
  375. CNoTrackObject* (AFXAPI* pfnCreateObject)())
  376. {
  377. if (m_pObject == NULL)
  378. {
  379. AfxLockGlobals(CRIT_PROCESSLOCAL);
  380. TRY
  381. {
  382. if (m_pObject == NULL)
  383. m_pObject = (*pfnCreateObject)();
  384. }
  385. CATCH_ALL(e)
  386. {
  387. AfxUnlockGlobals(CRIT_PROCESSLOCAL);
  388. THROW_LAST();
  389. }
  390. END_CATCH_ALL
  391. AfxUnlockGlobals(CRIT_PROCESSLOCAL);
  392. }
  393. return m_pObject;
  394. }
  395. CProcessLocalObject::~CProcessLocalObject()
  396. {
  397. if (m_pObject != NULL)
  398. delete m_pObject;
  399. }
  400. /////////////////////////////////////////////////////////////////////////////
  401. // Init/Term for thread/process local data
  402. void AFXAPI AfxInitLocalData(HINSTANCE hInst)
  403. {
  404. if (_afxThreadData != NULL)
  405. _afxThreadData->AssignInstance(hInst);
  406. }
  407. void AFXAPI AfxTermLocalData(HINSTANCE hInst, BOOL bAll)
  408. {
  409. if (_afxThreadData != NULL)
  410. _afxThreadData->DeleteValues(hInst, bAll);
  411. }
  412. // This reference count is needed to support Win32s, such that the
  413. // thread-local and process-local data is not destroyed prematurely.
  414. // It is basically a reference count of the number of processes that
  415. // have attached to the MFC DLL.
  416. AFX_STATIC_DATA long _afxTlsRef = 0;
  417. void AFXAPI AfxTlsAddRef()
  418. {
  419. ++_afxTlsRef;
  420. }
  421. void AFXAPI AfxTlsRelease()
  422. {
  423. if (_afxTlsRef == 0 || --_afxTlsRef == 0)
  424. {
  425. if (_afxThreadData != NULL)
  426. {
  427. _afxThreadData->~CThreadSlotData();
  428. _afxThreadData = NULL;
  429. }
  430. }
  431. }
  432. /////////////////////////////////////////////////////////////////////////////