home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / AFXTLS.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  12.0 KB  |  489 lines

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