diff options
Diffstat (limited to 'winsup/mingw/tlssup.c')
-rw-r--r-- | winsup/mingw/tlssup.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/winsup/mingw/tlssup.c b/winsup/mingw/tlssup.c new file mode 100644 index 000000000..b101d1124 --- /dev/null +++ b/winsup/mingw/tlssup.c @@ -0,0 +1,213 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + * + * Written by Kai Tietz <kai.tietz@onevision.com> + */ + +#ifdef CRTDLL +#undef CRTDLL +#endif + +#include <windows.h> +#include <stdio.h> +#include <memory.h> +#include <malloc.h> + +#ifndef _CRTALLOC +#define _CRTALLOC(x) __attribute__ ((section (x) )) +#endif + +#ifndef __INTERNAL_FUNC_DEFINED +#define __INTERNAL_FUNC_DEFINED + typedef void (__cdecl *_PVFV)(void); + typedef int (__cdecl *_PIFV)(void); + typedef void (__cdecl *_PVFI)(int); +#endif + +extern WINBOOL __mingw_TLScallback (HANDLE hDllHandle, DWORD reason, LPVOID reserved); + +#define FUNCS_PER_NODE 30 + +typedef struct TlsDtorNode { + int count; + struct TlsDtorNode *next; + _PVFV funcs[FUNCS_PER_NODE]; +} TlsDtorNode; + +ULONG _tls_index = 0; + +/* TLS raw template data start and end. */ +_CRTALLOC(".tls$AAA") char _tls_start = 0; +_CRTALLOC(".tls$ZZZ") char _tls_end = 0; + +_CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0; +_CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0; + +#ifdef _WIN64 +_CRTALLOC(".tls") const IMAGE_TLS_DIRECTORY64 _tls_used = { + (ULONGLONG) &_tls_start+1, (ULONGLONG) &_tls_end, (ULONGLONG) &_tls_index, + (ULONGLONG) (&__xl_a+1), (ULONG) 0, (ULONG) 0 +}; +#else +_CRTALLOC(".tls") const IMAGE_TLS_DIRECTORY _tls_used = { + (ULONG)(ULONG_PTR) &_tls_start+1, (ULONG)(ULONG_PTR) &_tls_end, + (ULONG)(ULONG_PTR) &_tls_index, (ULONG)(ULONG_PTR) (&__xl_a+1), + (ULONG) 0, (ULONG) 0 +}; +#endif + +#ifndef __CRT_THREAD +#ifdef HAVE_ATTRIBUTE_THREAD +#define __CRT_THREAD __declspec(thread) +#else +#define __CRT_THREAD __thread +#endif +#endif + +#define DISABLE_MS_TLS 1 + +static _CRTALLOC(".CRT$XDA") _PVFV __xd_a = 0; +static _CRTALLOC(".CRT$XDZ") _PVFV __xd_z = 0; + +#if !defined (DISABLE_MS_TLS) +static __CRT_THREAD TlsDtorNode *dtor_list; +static __CRT_THREAD TlsDtorNode dtor_list_head; +#endif + +extern int _CRT_MT; + +#ifndef _WIN64 +#define MINGWM10_DLL "mingwm10.dll" +typedef int (*fMTRemoveKeyDtor)(DWORD key); +typedef int (*fMTKeyDtor)(DWORD key, void (*dtor)(void *)); +fMTRemoveKeyDtor __mingw_gMTRemoveKeyDtor; +fMTKeyDtor __mingw_gMTKeyDtor; +int __mingw_usemthread_dll; +static HANDLE __mingw_mthread_hdll; +#endif + +BOOL WINAPI __dyn_tls_init (HANDLE, DWORD, LPVOID); + +BOOL WINAPI +__dyn_tls_init (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) +{ + _PVFV *pfunc; + +#ifndef _WIN64 + if (_winmajor < 4) + { + __mingw_usemthread_dll = 1; + __mingw_mthread_hdll = LoadLibrary (MINGWM10_DLL); + if (__mingw_mthread_hdll != NULL) + { + __mingw_gMTRemoveKeyDtor = (fMTRemoveKeyDtor) GetProcAddress (__mingw_mthread_hdll, "__mingwthr_remove_key_dtor"); + __mingw_gMTKeyDtor = (fMTKeyDtor) GetProcAddress (__mingw_mthread_hdll, "__mingwthr_key_dtor"); + } + if (__mingw_mthread_hdll == NULL || !__mingw_gMTRemoveKeyDtor || !__mingw_gMTKeyDtor) + { + __mingw_gMTKeyDtor = NULL; + __mingw_gMTRemoveKeyDtor = NULL; + if (__mingw_mthread_hdll) + FreeLibrary (__mingw_mthread_hdll); + __mingw_mthread_hdll = NULL; + _CRT_MT = 0; + return TRUE; + } + _CRT_MT = 1; + return TRUE; + } +#endif + /* We don't let us trick here. */ + if (_CRT_MT != 2) + _CRT_MT = 2; + + if (dwReason != DLL_THREAD_ATTACH) + { + if (dwReason == DLL_PROCESS_ATTACH) + __mingw_TLScallback (hDllHandle, dwReason, lpreserved); + return TRUE; + } + + for (pfunc = &__xd_a + 1; pfunc != &__xd_z; ++pfunc) + { + if (*pfunc != NULL) + (*pfunc)(); + } + return TRUE; +} + +const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback = (const PIMAGE_TLS_CALLBACK) __dyn_tls_init; +_CRTALLOC(".CRT$XLC") PIMAGE_TLS_CALLBACK __xl_c = (PIMAGE_TLS_CALLBACK) __dyn_tls_init; + +int __cdecl __tlregdtor (_PVFV); + +int __cdecl +__tlregdtor (_PVFV func) +{ + if (!func) + return 0; +#if !defined (DISABLE_MS_TLS) + if (dtor_list == NULL) + { + dtor_list = &dtor_list_head; + dtor_list_head.count = 0; + } + else if (dtor_list->count == FUNCS_PER_NODE) + { + TlsDtorNode *pnode = (TlsDtorNode *) malloc (sizeof (TlsDtorNode)); + if (pnode == NULL) + return -1; + pnode->count = 0; + pnode->next = dtor_list; + dtor_list = pnode; + + dtor_list->count = 0; + } + dtor_list->funcs[dtor_list->count++] = func; +#endif + return 0; +} + +static BOOL WINAPI +__dyn_tls_dtor (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) +{ +#if !defined (DISABLE_MS_TLS) + TlsDtorNode *pnode, *pnext; + int i; +#endif + + if (dwReason != DLL_THREAD_DETACH && dwReason != DLL_PROCESS_DETACH) + return TRUE; + /* As TLS variables are detroyed already by DLL_THREAD_DETACH + call, we have to avoid access on the possible DLL_PROCESS_DETACH + call the already destroyed TLS vars. + TODO: The used local thread based variables have to be handled + manually, so that we can control their lifetime here. */ +#if !defined (DISABLE_MS_TLS) + if (dwReason != DLL_PROCESS_DETACH) + { + for (pnode = dtor_list; pnode != NULL; pnode = pnext) + { + for (i = pnode->count - 1; i >= 0; --i) + { + if (pnode->funcs[i] != NULL) + (*pnode->funcs[i])(); + } + pnext = pnode->next; + if (pnext != NULL) + free ((void *) pnode); + } + } +#endif + __mingw_TLScallback (hDllHandle, dwReason, lpreserved); + return TRUE; +} + +_CRTALLOC(".CRT$XLD") PIMAGE_TLS_CALLBACK __xl_d = (PIMAGE_TLS_CALLBACK) __dyn_tls_dtor; + + +int mingw_initltsdrot_force = 0; +int mingw_initltsdyn_force=0; +int mingw_initltssuo_force = 0; |