/*========================================================================== * * 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__