home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
- #include <stddef.h>
-
- #ifdef AFX_INIT_SEG
- #pragma code_seg(AFX_INIT_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
- // CSimpleList
-
- void CSimpleList::AddHead(void* p)
- {
- ASSERT(p != NULL);
- ASSERT(*GetNextPtr(p) == NULL);
-
- *GetNextPtr(p) = m_pHead;
- m_pHead = p;
- }
-
- BOOL CSimpleList::Remove(void* p)
- {
- ASSERT(p != NULL);
-
- if (m_pHead == NULL)
- return FALSE;
-
- BOOL bResult = FALSE;
- if (m_pHead == p)
- {
- m_pHead = *GetNextPtr(p);
- DEBUG_ONLY(*GetNextPtr(p) = NULL);
- bResult = TRUE;
- }
- else
- {
- void* pTest = m_pHead;
- while (pTest != NULL && *GetNextPtr(pTest) != p)
- pTest = *GetNextPtr(pTest);
- if (pTest != NULL)
- {
- *GetNextPtr(pTest) = *GetNextPtr(p);
- DEBUG_ONLY(*GetNextPtr(p) = NULL);
- bResult = TRUE;
- }
- }
- return bResult;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CNoTrackObject
-
- #if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
- void* PASCAL CNoTrackObject::operator new(size_t nSize, LPCSTR, int)
- {
- return CNoTrackObject::operator new(nSize);
- }
-
- #if _MSC_VER >= 1200
- void PASCAL CNoTrackObject::operator delete(void* pObject, LPCSTR, int)
- {
- if (pObject != NULL)
- ::LocalFree(pObject);
- }
- #endif
- #endif
-
- void* PASCAL CNoTrackObject::operator new(size_t nSize)
- {
- void* p = ::LocalAlloc(LPTR, nSize);
- if (p == NULL)
- AfxThrowMemoryException();
- return p;
- }
-
- void PASCAL CNoTrackObject::operator delete(void* p)
- {
- if (p != NULL)
- ::LocalFree(p);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CThreadSlotData
-
- // global _afxThreadData used to allocate thread local indexes
- BYTE __afxThreadData[sizeof(CThreadSlotData)];
- CThreadSlotData* _afxThreadData;
-
- struct CThreadData : public CNoTrackObject
- {
- CThreadData* pNext; // required to be member of CSimpleList
- int nCount; // current size of pData
- LPVOID* pData; // actual thread local data (indexed by nSlot)
- };
-
- struct CSlotData
- {
- DWORD dwFlags; // slot flags (allocated/not allocated)
- HINSTANCE hInst; // module which owns this slot
- };
-
- // flags used for CSlotData::dwFlags above
- #define SLOT_USED 0x01 // slot is allocated
-
- __declspec(nothrow) CThreadSlotData::CThreadSlotData()
- {
- m_list.Construct(offsetof(CThreadData, pNext));
-
- // initialize state and allocate TLS index
- m_nAlloc = 0;
- m_nRover = 1; // first slot (0) is always reserved
- m_nMax = 0;
- m_pSlotData = NULL;
-
- // init m_tlsIndex to -1 if !bThreadLocal, otherwise TlsAlloc
- m_tlsIndex = TlsAlloc();
- if (m_tlsIndex == (DWORD)-1)
- AfxThrowMemoryException();
-
- InitializeCriticalSection(&m_sect);
- }
-
- CThreadSlotData::~CThreadSlotData()
- {
- if (m_tlsIndex != (DWORD)-1)
- {
- TlsFree(m_tlsIndex);
- DEBUG_ONLY(m_tlsIndex = (DWORD)-1);
- }
-
- CThreadData* pData = m_list;
- while (pData != NULL)
- {
- CThreadData* pDataNext = pData->pNext;
- DeleteValues(pData, NULL);
- pData = pDataNext;
- }
-
- if (m_pSlotData != NULL)
- {
- HGLOBAL hSlotData = GlobalHandle(m_pSlotData);
- GlobalUnlock(hSlotData);
- GlobalFree(hSlotData);
- DEBUG_ONLY(m_pSlotData = NULL);
- }
-
- DeleteCriticalSection(&m_sect);
- }
-
- int CThreadSlotData::AllocSlot()
- {
- EnterCriticalSection(&m_sect);
- int nAlloc = m_nAlloc;
- int nSlot = m_nRover;
- if (nSlot >= nAlloc || (m_pSlotData[nSlot].dwFlags & SLOT_USED))
- {
- // search for first free slot, starting at beginning
- for (nSlot = 1;
- nSlot < nAlloc && (m_pSlotData[nSlot].dwFlags & SLOT_USED); nSlot++)
- ;
-
- // if none found, need to allocate more space
- if (nSlot >= nAlloc)
- {
- // realloc memory for the bit array and the slot memory
- int nNewAlloc = m_nAlloc+32;
-
- // m_pSlotData is allocated GMEM_SHARE because on Win32s it needs
- // to be shared between processes (memory is owned by the MFC DLL).
- HGLOBAL hSlotData;
- if (m_pSlotData == NULL)
- {
- hSlotData = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,
- nNewAlloc*sizeof(CSlotData));
- }
- else
- {
- hSlotData = GlobalHandle(m_pSlotData);
- GlobalUnlock(hSlotData);
- hSlotData = GlobalReAlloc(hSlotData, nNewAlloc*sizeof(CSlotData),
- GMEM_MOVEABLE|GMEM_SHARE);
- }
- if (hSlotData == NULL)
- {
- GlobalLock(GlobalHandle(m_pSlotData));
- LeaveCriticalSection(&m_sect);
- AfxThrowMemoryException();
- }
- CSlotData* pSlotData = (CSlotData*)GlobalLock(hSlotData);
-
- // always zero initialize after success
- memset(pSlotData+m_nAlloc, 0, (nNewAlloc-m_nAlloc)*sizeof(CSlotData));
- m_nAlloc = nNewAlloc;
- m_pSlotData = pSlotData;
- }
- }
- ASSERT(nSlot != 0); // first slot (0) is reserved
-
- // adjust m_nMax to largest slot ever allocated
- if (nSlot >= m_nMax)
- m_nMax = nSlot+1;
-
- ASSERT(!(m_pSlotData[nSlot].dwFlags & SLOT_USED));
- m_pSlotData[nSlot].dwFlags |= SLOT_USED;
- // update m_nRover (likely place to find a free slot is next one)
- m_nRover = nSlot+1;
-
- LeaveCriticalSection(&m_sect);
- return nSlot; // slot can be used for FreeSlot, GetValue, SetValue
- }
-
- void CThreadSlotData::FreeSlot(int nSlot)
- {
- EnterCriticalSection(&m_sect);
- ASSERT(nSlot != 0 && nSlot < m_nMax);
- ASSERT(m_pSlotData != NULL);
- ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
-
- // delete the data from all threads/processes
- CThreadData* pData = m_list;
- while (pData != NULL)
- {
- if (nSlot < pData->nCount)
- {
- delete (CNoTrackObject*)pData->pData[nSlot];
- pData->pData[nSlot] = NULL;
- }
- pData = pData->pNext;
- }
- // free the slot itself
- m_pSlotData[nSlot].dwFlags &= ~SLOT_USED;
- LeaveCriticalSection(&m_sect);
- }
-
- // special version of CThreadSlotData::GetData that only works with
- // thread local storage (and not process local storage)
- // this version is inlined and simplified for speed
- inline void* CThreadSlotData::GetThreadValue(int nSlot)
- {
- ASSERT(nSlot != 0 && nSlot < m_nMax);
- ASSERT(m_pSlotData != NULL);
- ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
- ASSERT(m_tlsIndex != (DWORD)-1);
-
- CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
- if (pData == NULL || nSlot >= pData->nCount)
- return NULL;
- return pData->pData[nSlot];
- }
-
- void CThreadSlotData::SetValue(int nSlot, void* pValue)
- {
- ASSERT(nSlot != 0 && nSlot < m_nMax);
- ASSERT(m_pSlotData != NULL);
- ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
-
- CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
- if (pData == NULL || nSlot >= pData->nCount && pValue != NULL)
- {
- // if pData is NULL then this thread has not been visited yet
- if (pData == NULL)
- {
- pData = new CThreadData;
- pData->nCount = 0;
- pData->pData = NULL;
- DEBUG_ONLY(pData->pNext = NULL);
-
- // protect while adding to global list
- EnterCriticalSection(&m_sect);
- m_list.AddHead(pData);
- LeaveCriticalSection(&m_sect);
- }
-
- // grow to now current size
- if (pData->pData == NULL)
- pData->pData = (void**)LocalAlloc(LMEM_FIXED, m_nMax*sizeof(LPVOID));
- else
- pData->pData = (void**)LocalReAlloc(pData->pData, m_nMax*sizeof(LPVOID),
- LMEM_MOVEABLE);
- if (pData->pData == NULL)
- AfxThrowMemoryException();
-
- // initialize the newly allocated part
- memset(pData->pData + pData->nCount, 0,
- (m_nMax - pData->nCount) * sizeof(LPVOID));
- pData->nCount = m_nMax;
- TlsSetValue(m_tlsIndex, pData);
- }
- ASSERT(pData->pData != NULL && nSlot < pData->nCount);
- pData->pData[nSlot] = pValue;
- }
-
- void CThreadSlotData::AssignInstance(HINSTANCE hInst)
- {
- EnterCriticalSection(&m_sect);
- ASSERT(m_pSlotData != NULL);
- ASSERT(hInst != NULL);
-
- for (int i = 1; i < m_nMax; i++)
- {
- if (m_pSlotData[i].hInst == NULL && (m_pSlotData[i].dwFlags & SLOT_USED))
- m_pSlotData[i].hInst = hInst;
- }
- LeaveCriticalSection(&m_sect);
- }
-
- void CThreadSlotData::DeleteValues(CThreadData* pData, HINSTANCE hInst)
- {
- // Note: does not lock critical section because only meant to be called
- // from DeleteValues(HINSTANCE, BOOL).
-
- ASSERT(pData != NULL);
-
- // free each element in the table
- BOOL bDelete = TRUE;
- for (int i = 1; i < pData->nCount; i++)
- {
- if (hInst == NULL || m_pSlotData[i].hInst == hInst)
- {
- // delete the data since hInst matches (or is NULL)
- delete (CNoTrackObject*)pData->pData[i];
- pData->pData[i] = NULL;
- }
- else if (pData->pData[i] != NULL)
- {
- // don't delete thread data if other modules still alive
- bDelete = FALSE;
- }
- }
-
- if (bDelete)
- {
- // remove from master list and free it
- EnterCriticalSection(&m_sect);
- m_list.Remove(pData);
- LeaveCriticalSection(&m_sect);
- LocalFree(pData->pData);
- delete pData;
-
- // clear TLS index to prevent from re-use
- TlsSetValue(m_tlsIndex, NULL);
- }
- }
-
- void CThreadSlotData::DeleteValues(HINSTANCE hInst, BOOL bAll)
- {
- EnterCriticalSection(&m_sect);
- if (!bAll)
- {
- // delete the values only for the current thread
- CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
- if (pData != NULL)
- DeleteValues(pData, hInst);
- }
- else
- {
- // delete the values for all threads
- CThreadData* pData = m_list;
- while (pData != NULL)
- {
- CThreadData* pDataNext = pData->pNext;
- DeleteValues(pData, hInst);
- pData = pDataNext;
- }
- }
- LeaveCriticalSection(&m_sect);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CThreadLocalObject
-
- CNoTrackObject* CThreadLocalObject::GetData(
- CNoTrackObject* (AFXAPI* pfnCreateObject)())
- {
- if (m_nSlot == 0)
- {
- if (_afxThreadData == NULL)
- {
- _afxThreadData = new(__afxThreadData) CThreadSlotData;
- ASSERT(_afxThreadData != NULL);
- }
- m_nSlot = _afxThreadData->AllocSlot();
- ASSERT(m_nSlot != 0);
- }
- CNoTrackObject* pValue =
- (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
- if (pValue == NULL)
- {
- // allocate zero-init object
- pValue = (*pfnCreateObject)();
-
- // set tls data to newly created object
- _afxThreadData->SetValue(m_nSlot, pValue);
- ASSERT(_afxThreadData->GetThreadValue(m_nSlot) == pValue);
- }
- return pValue;
- }
-
- CNoTrackObject* CThreadLocalObject::GetDataNA()
- {
- if (m_nSlot == 0 || _afxThreadData == NULL)
- return NULL;
-
- CNoTrackObject* pValue =
- (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
- return pValue;
- }
-
- CThreadLocalObject::~CThreadLocalObject()
- {
- if (m_nSlot != 0 && _afxThreadData != NULL)
- _afxThreadData->FreeSlot(m_nSlot);
- m_nSlot = 0;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CProcessLocalData
-
- CNoTrackObject* CProcessLocalObject::GetData(
- CNoTrackObject* (AFXAPI* pfnCreateObject)())
- {
- if (m_pObject == NULL)
- {
- AfxLockGlobals(CRIT_PROCESSLOCAL);
- TRY
- {
- if (m_pObject == NULL)
- m_pObject = (*pfnCreateObject)();
- }
- CATCH_ALL(e)
- {
- AfxUnlockGlobals(CRIT_PROCESSLOCAL);
- THROW_LAST();
- }
- END_CATCH_ALL
- AfxUnlockGlobals(CRIT_PROCESSLOCAL);
- }
- return m_pObject;
- }
-
- CProcessLocalObject::~CProcessLocalObject()
- {
- if (m_pObject != NULL)
- delete m_pObject;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Init/Term for thread/process local data
-
- void AFXAPI AfxInitLocalData(HINSTANCE hInst)
- {
- if (_afxThreadData != NULL)
- _afxThreadData->AssignInstance(hInst);
- }
-
- void AFXAPI AfxTermLocalData(HINSTANCE hInst, BOOL bAll)
- {
- if (_afxThreadData != NULL)
- _afxThreadData->DeleteValues(hInst, bAll);
- }
-
- // This reference count is needed to support Win32s, such that the
- // thread-local and process-local data is not destroyed prematurely.
- // It is basically a reference count of the number of processes that
- // have attached to the MFC DLL.
-
- AFX_STATIC_DATA long _afxTlsRef = 0;
-
- void AFXAPI AfxTlsAddRef()
- {
- ++_afxTlsRef;
- }
-
- void AFXAPI AfxTlsRelease()
- {
- if (_afxTlsRef == 0 || --_afxTlsRef == 0)
- {
- if (_afxThreadData != NULL)
- {
- _afxThreadData->~CThreadSlotData();
- _afxThreadData = NULL;
- }
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
-