214 lines
7.3 KiB
C
214 lines
7.3 KiB
C
|
/*==========================================================================
|
||
|
*
|
||
|
* Copyright (C) 2001 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: threadlocalptrs.h
|
||
|
* Content: Thread local pointer macros
|
||
|
*
|
||
|
* History:
|
||
|
* Date By Reason
|
||
|
* ==== == ======
|
||
|
* 03/21/2001 vanceo Created.
|
||
|
***************************************************************************/
|
||
|
|
||
|
#ifndef __THREADLOCALPTRS_H__
|
||
|
#define __THREADLOCALPTRS_H__
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// Structure definitions
|
||
|
//**********************************************************************
|
||
|
|
||
|
typedef struct _THREADLOCAL_HEADER THREADLOCAL_HEADER, * PTHREADLOCAL_HEADER;
|
||
|
|
||
|
struct _THREADLOCAL_HEADER
|
||
|
{
|
||
|
PTHREADLOCAL_HEADER pNext; // pointer to next allocated threadlocal structure header
|
||
|
PTHREADLOCAL_HEADER pPrev; // pointer to previous allocated threadlocal structure header
|
||
|
DWORD dwThreadID; // ID of thread that owns this header
|
||
|
|
||
|
//
|
||
|
// The actual thread local pointer structure follows this.
|
||
|
//
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// Macro definitions
|
||
|
//**********************************************************************
|
||
|
|
||
|
//
|
||
|
// Global thread local pointer declarations.
|
||
|
//
|
||
|
|
||
|
#define DECLARE_THREADLOCALPTRS(pointers) extern DWORD g_dw##pointers##TlsIndex;\
|
||
|
extern DNCRITICAL_SECTION g_csAllocated##pointers;\
|
||
|
extern PTHREADLOCAL_HEADER g_pAllocated##pointers;\
|
||
|
\
|
||
|
struct pointers
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Thread local pointer storage, define in only one location.
|
||
|
//
|
||
|
#define IMPL_THREADLOCALPTRS(pointers) DWORD g_dw##pointers##TlsIndex = -1;\
|
||
|
DNCRITICAL_SECTION g_csAllocated##pointers;\
|
||
|
PTHREADLOCAL_HEADER g_pAllocated##pointers = NULL
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Thread local pointer initialization, call only once (DLL_PROCESS_ATTACH),
|
||
|
// returns TRUE if successful, FALSE otherwise.
|
||
|
//
|
||
|
#define INIT_THREADLOCALPTRS(pointers) g_pAllocated##pointers = NULL, g_dw##pointers##TlsIndex = TlsAlloc(), ((g_dw##pointers##TlsIndex != -1) ? DNInitializeCriticalSection(&g_csAllocated##pointers) : FALSE)
|
||
|
|
||
|
|
||
|
//
|
||
|
// Total thread local pointer cleanup, call only once (DLL_PROCESS_DETACH).
|
||
|
//
|
||
|
#define DEINIT_THREADLOCALPTRS(pointers, pfnCleanup) {\
|
||
|
PTHREADLOCAL_HEADER pNext;\
|
||
|
\
|
||
|
\
|
||
|
if (g_dw##pointers##TlsIndex != -1)\
|
||
|
{\
|
||
|
DNDeleteCriticalSection(&g_csAllocated##pointers);\
|
||
|
\
|
||
|
TlsFree(g_dw##pointers##TlsIndex);\
|
||
|
g_dw##pointers##TlsIndex = -1;\
|
||
|
}\
|
||
|
\
|
||
|
while (g_pAllocated##pointers != NULL)\
|
||
|
{\
|
||
|
pNext = g_pAllocated##pointers->pNext;\
|
||
|
pfnCleanup((pointers *) (g_pAllocated##pointers + 1), g_pAllocated##pointers->dwThreadID);\
|
||
|
DNFree(g_pAllocated##pointers);\
|
||
|
g_pAllocated##pointers = pNext;\
|
||
|
}\
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Cleanup only current thread's local pointers (DLL_THREAD_DETACH).
|
||
|
//
|
||
|
#define RELEASE_CURRENTTHREAD_LOCALPTRS(pointers, pfnCleanup) {\
|
||
|
PTHREADLOCAL_HEADER pHeader;\
|
||
|
PTHREADLOCAL_HEADER pNext;\
|
||
|
\
|
||
|
\
|
||
|
pHeader = (PTHREADLOCAL_HEADER) TlsGetValue(g_dw##pointers##TlsIndex);\
|
||
|
if (pHeader != NULL)\
|
||
|
{\
|
||
|
DNEnterCriticalSection(&g_csAllocated##pointers);\
|
||
|
\
|
||
|
pNext = pHeader->pNext;\
|
||
|
if (pHeader->pPrev != NULL)\
|
||
|
{\
|
||
|
pHeader->pPrev->pNext = pNext;\
|
||
|
}\
|
||
|
if (pNext != NULL)\
|
||
|
{\
|
||
|
pNext->pPrev = pHeader->pPrev;\
|
||
|
}\
|
||
|
\
|
||
|
if (pHeader == g_pAllocated##pointers)\
|
||
|
{\
|
||
|
g_pAllocated##pointers = pNext;\
|
||
|
}\
|
||
|
\
|
||
|
DNLeaveCriticalSection(&g_csAllocated##pointers);\
|
||
|
\
|
||
|
DNASSERT(pHeader->dwThreadID == GetCurrentThreadId());\
|
||
|
pfnCleanup((pointers *) (pHeader + 1), pHeader->dwThreadID);\
|
||
|
DNFree(pHeader);\
|
||
|
}\
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Thread local pointer retrieval function.
|
||
|
//
|
||
|
#define GET_THREADLOCALPTR(pointers, name, pptr) {\
|
||
|
PTHREADLOCAL_HEADER pHeader;\
|
||
|
\
|
||
|
\
|
||
|
pHeader = (PTHREADLOCAL_HEADER) TlsGetValue(g_dw##pointers##TlsIndex);\
|
||
|
if (pHeader == NULL)\
|
||
|
{\
|
||
|
DPFX(DPFPREP, 9, "No header for " #name ".");\
|
||
|
(*pptr) = NULL;\
|
||
|
}\
|
||
|
else\
|
||
|
{\
|
||
|
DPFX(DPFPREP, 9, "Found header 0x%p, returning " #name " 0x%p.", pHeader, ((pointers *) (pHeader + 1))->name);\
|
||
|
(*pptr) = ((pointers *) (pHeader + 1))->name;\
|
||
|
}\
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Thread local pointer storage function.
|
||
|
//
|
||
|
#define SET_THREADLOCALPTR(pointers, name, ptr, pfResult) {\
|
||
|
PTHREADLOCAL_HEADER pHeader;\
|
||
|
\
|
||
|
\
|
||
|
pHeader = (PTHREADLOCAL_HEADER) TlsGetValue(g_dw##pointers##TlsIndex);\
|
||
|
if (pHeader == NULL)\
|
||
|
{\
|
||
|
pHeader = (PTHREADLOCAL_HEADER) DNMalloc(sizeof(THREADLOCAL_HEADER) + sizeof(pointers));\
|
||
|
if (pHeader == NULL)\
|
||
|
{\
|
||
|
(*pfResult) = FALSE;\
|
||
|
}\
|
||
|
else\
|
||
|
{\
|
||
|
memset(pHeader, 0, (sizeof(THREADLOCAL_HEADER) + sizeof(pointers)));\
|
||
|
pHeader->dwThreadID = GetCurrentThreadId();\
|
||
|
((pointers *) (pHeader + 1))->name = ptr;\
|
||
|
\
|
||
|
if (! TlsSetValue(g_dw##pointers##TlsIndex, pHeader))\
|
||
|
{\
|
||
|
DPFX(DPFPREP, 9, "Couldn't set thread local storage 0x%p!", pHeader);\
|
||
|
DNFree(pHeader);\
|
||
|
(*pfResult) = FALSE;\
|
||
|
}\
|
||
|
else\
|
||
|
{\
|
||
|
DPFX(DPFPREP, 9, "Setting 0x%p " #name " to 0x%p (create).", pHeader, ptr);\
|
||
|
\
|
||
|
DNEnterCriticalSection(&g_csAllocated##pointers);\
|
||
|
pHeader->pNext = g_pAllocated##pointers;\
|
||
|
if (g_pAllocated##pointers != NULL)\
|
||
|
{\
|
||
|
DNASSERT(g_pAllocated##pointers##->pPrev == NULL);\
|
||
|
g_pAllocated##pointers##->pPrev = pHeader;\
|
||
|
}\
|
||
|
g_pAllocated##pointers = pHeader;\
|
||
|
DNLeaveCriticalSection(&g_csAllocated##pointers);\
|
||
|
\
|
||
|
(*pfResult) = TRUE;\
|
||
|
}\
|
||
|
}\
|
||
|
}\
|
||
|
else\
|
||
|
{\
|
||
|
DPFX(DPFPREP, 9, "Setting 0x%p " #name " to 0x%p (existing).", pHeader, ptr);\
|
||
|
DNASSERT(((pointers *) (pHeader + 1))->name == NULL);\
|
||
|
((pointers *) (pHeader + 1))->name = ptr;\
|
||
|
(*pfResult) = TRUE;\
|
||
|
}\
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#endif // __THREADLOCALPTRS_H__
|