From d359eb2e1fe2486bc8a7340b64f6c25387dd1585 Mon Sep 17 00:00:00 2001 From: Chris Sutcliffe Date: Mon, 25 Jan 2010 22:58:03 +0000 Subject: [PATCH] 2010-01-25 Kai Tietz Implement TLS Callback. * tlsmcrt.c: New file. * tlsmthread.c: Ditto. * tlssup.c: Ditto. * tlsthrd.c: Ditto. * Makefile.in: Include new files. * crt1.c: Implement TLS Callback. * dllcrt1.c: Ditto. * mthr_stub.c: Remove. --- winsup/mingw/ChangeLog | 13 +++ winsup/mingw/Makefile.in | 14 ++- winsup/mingw/crt1.c | 7 ++ winsup/mingw/dllcrt1.c | 9 ++ winsup/mingw/mthr_stub.c | 44 -------- winsup/mingw/tlsmcrt.c | 13 +++ winsup/mingw/tlsmthread.c | 59 +++++++++++ winsup/mingw/tlssup.c | 213 ++++++++++++++++++++++++++++++++++++++ winsup/mingw/tlsthrd.c | 148 ++++++++++++++++++++++++++ 9 files changed, 472 insertions(+), 48 deletions(-) delete mode 100644 winsup/mingw/mthr_stub.c create mode 100644 winsup/mingw/tlsmcrt.c create mode 100644 winsup/mingw/tlsmthread.c create mode 100644 winsup/mingw/tlssup.c create mode 100644 winsup/mingw/tlsthrd.c diff --git a/winsup/mingw/ChangeLog b/winsup/mingw/ChangeLog index 733d56e10..c83c8e38b 100644 --- a/winsup/mingw/ChangeLog +++ b/winsup/mingw/ChangeLog @@ -1,3 +1,16 @@ +2010-01-25 Kai Tietz + + Implement TLS Callback. + + * tlsmcrt.c: New file. + * tlsmthread.c: Ditto. + * tlssup.c: Ditto. + * tlsthrd.c: Ditto. + * Makefile.in: Include new files. + * crt1.c: Implement TLS Callback. + * dllcrt1.c: Ditto. + * mthr_stub.c: Remove. + 2009-11-29 Chris Sutcliffe * include/_mingw.h: Increment version to 3.17. diff --git a/winsup/mingw/Makefile.in b/winsup/mingw/Makefile.in index 7a51a9f16..8f7358314 100644 --- a/winsup/mingw/Makefile.in +++ b/winsup/mingw/Makefile.in @@ -227,8 +227,9 @@ FLAGS_TO_PASS:=\ CRT0S = crt1.o dllcrt1.o crt2.o dllcrt2.o CRT_noglob.o crtmt.o crtst.o \ CRT_fp8.o CRT_fp10.o txtmode.o binmode.o MINGW_OBJS = CRTglob.o CRTfmode.o CRTinit.o dllmain.o gccmain.o \ - main.o crtst.o mthr_stub.o CRT_fp10.o txtmode.o \ - pseudo-reloc.o pseudo-reloc-list.o cpu_features.o + main.o crtst.o CRT_fp10.o txtmode.o \ + pseudo-reloc.o pseudo-reloc-list.o cpu_features.o \ + tlsmcrt.o tlsmthread.o tlssup.o tlsthrd.o MOLD_OBJS = isascii.o iscsym.o iscsymf.o toascii.o \ strcasecmp.o strncasecmp.o wcscmpi.o @@ -247,6 +248,7 @@ LIBS = libcrtdll.a \ libmoldname80.a libmoldname80d.a \ libmoldname90.a libmoldname90d.a \ $(LIBM_A) \ + libmingwthrd_old.a \ libmingwthrd.a DLLS = $(THREAD_DLL_NAME) @@ -260,7 +262,7 @@ Makefile.in README TODO config.guess config.sub configure configure.in \ aclocal.m4 crt1.c crtdll.def crtmt.c crtst.c dllcrt1.c dllmain.c \ gccmain.c init.c install-sh jamfile main.c mkinstalldirs \ moldname.def.in msvcrt.def.in ofmt_stub.s \ -mthr.c mthr_init.c mthr_stub.c readme.txt \ +mthr.c mthr_init.c tlsmcrt.c tlsmthread.c tlssup.c tlsthrd.c readme.txt \ isascii.c iscsym.c iscsymf.c toascii.c \ strcasecmp.c strncasecmp.c wcscmpi.c \ CRT_fp8.c CRT_fp10.c test_headers.c txtmode.c binmode.c pseudo-reloc.c \ @@ -290,7 +292,11 @@ libm.a: _libm_dummy.o $(AR) rc $@ _libm_dummy.o $(RANLIB) $@ -libmingwthrd.a: crtmt.o mingwthrd.def +libmingwthrd.a: crtmt.o + $(AR) $(ARFLAGS) $@ crtmt.o + $(RANLIB) $@ + +libmingwthrd_old.a: crtmt.o mingwthrd.def $(DLLTOOL) $(DLLTOOL_FLAGS) --dllname $(THREAD_DLL_NAME) \ --def mingwthrd.def --output-lib $@ $(AR) $(ARFLAGS) $@ crtmt.o diff --git a/winsup/mingw/crt1.c b/winsup/mingw/crt1.c index ad3ed7147..104f6b783 100644 --- a/winsup/mingw/crt1.c +++ b/winsup/mingw/crt1.c @@ -34,6 +34,9 @@ extern void _pei386_runtime_relocator (void); extern int main (int, char **, char **); +/* TLS initialization hook. */ +extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback; + /* * Must have the correct app type for MSVCRT. */ @@ -186,6 +189,10 @@ __mingw_CRTStartup (void) { int nRet; + /* Initialize TLS callback. */ + if (__dyn_tls_init_callback != NULL) + __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL); + /* * Set up the top-level exception handler so that signal handling * works as expected. The mapping between ANSI/POSIX signals and diff --git a/winsup/mingw/dllcrt1.c b/winsup/mingw/dllcrt1.c index dda8a24c7..ee03be3e6 100644 --- a/winsup/mingw/dllcrt1.c +++ b/winsup/mingw/dllcrt1.c @@ -14,6 +14,9 @@ #include #include +/* TLS initialization hook. */ +extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback; + /* Unlike normal crt1, I don't initialize the FPU, because the process * should have done that already. I also don't set the file handle modes, * because that would be rude. */ @@ -62,6 +65,12 @@ DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) *first_atexit = NULL; next_atexit = first_atexit; + /* Initialize TLS callback. */ + if (__dyn_tls_init_callback != NULL) + { + __dyn_tls_init_callback (hDll, DLL_THREAD_ATTACH, lpReserved); + } + /* Adust references to dllimported data (from other DLL's) that have non-zero offsets. */ _pei386_runtime_relocator (); diff --git a/winsup/mingw/mthr_stub.c b/winsup/mingw/mthr_stub.c deleted file mode 100644 index e337b9a1c..000000000 --- a/winsup/mingw/mthr_stub.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * mthr_stub.c - * - * Implement Mingw thread-support stubs for single-threaded C++ apps. - * - * This file is used by if gcc is built with --enable-threads=win32 and - * iff gcc does *NOT* use -mthreads option. - * - * The -mthreads implementation is in mthr.c. - * - * Created by Mumit Khan - * - */ - -#define WIN32_LEAN_AND_MEAN -#include -#undef WIN32_LEAN_AND_MEAN - -/* - * __mingwthr_register_key_dtor (DWORD key, void (*dtor) (void *)) - * - * Public interface called by C++ exception handling mechanism in - * libgcc (cf: __gthread_key_create). - * No-op versions. - */ - -int -__mingwthr_key_dtor (DWORD key, void (*dtor) (void *)) -{ -#ifdef DEBUG - printf ("%s: ignoring key: (%ld) / dtor: (%x)\n", - __FUNCTION__, key, dtor); -#endif - return 0; -} - -int -__mingwthr_remove_key_dtor (DWORD key ) -{ -#ifdef DEBUG - printf ("%s: ignoring key: (%ld)\n", __FUNCTION__, key ); -#endif - return 0; -} diff --git a/winsup/mingw/tlsmcrt.c b/winsup/mingw/tlsmcrt.c new file mode 100644 index 000000000..45bead291 --- /dev/null +++ b/winsup/mingw/tlsmcrt.c @@ -0,0 +1,13 @@ +/** + * 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 + */ + +/* We support TLS cleanup code in any case. If shared version of libgcc is used _CRT_MT has value 1, + otherwise + we do tls cleanup in runtime and _CRT_MT has value 2. */ +int _CRT_MT = 2; + diff --git a/winsup/mingw/tlsmthread.c b/winsup/mingw/tlsmthread.c new file mode 100644 index 000000000..f30e70137 --- /dev/null +++ b/winsup/mingw/tlsmthread.c @@ -0,0 +1,59 @@ +/** + * 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 + */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +int __mingwthr_key_dtor (DWORD key, void (*dtor)(void *)); +int __mingwthr_remove_key_dtor (DWORD key); + +extern int ___w64_mingwthr_remove_key_dtor (DWORD key); +extern int ___w64_mingwthr_add_key_dtor (DWORD key, void (*dtor)(void *)); + + +#ifndef _WIN64 +#define MINGWM10_DLL "mingwm10.dll" +typedef int (*fMTRemoveKeyDtor)(DWORD key); +typedef int (*fMTKeyDtor)(DWORD key, void (*dtor)(void *)); +extern fMTRemoveKeyDtor __mingw_gMTRemoveKeyDtor; +extern fMTKeyDtor __mingw_gMTKeyDtor; +extern int __mingw_usemthread_dll; +#endif + +int +__mingwthr_remove_key_dtor (DWORD key) +{ +#ifndef _WIN64 + if (!__mingw_usemthread_dll) +#endif + return ___w64_mingwthr_remove_key_dtor (key); +#ifndef _WIN64 + if (__mingw_gMTRemoveKeyDtor) + return (*__mingw_gMTRemoveKeyDtor) (key); + return 0; +#endif +} + +int +__mingwthr_key_dtor (DWORD key, void (*dtor)(void *)) +{ + if (dtor) + { +#ifndef _WIN64 + if (!__mingw_usemthread_dll) +#endif + return ___w64_mingwthr_add_key_dtor (key, dtor); +#ifndef _WIN64 + if (__mingw_gMTKeyDtor) + return (*__mingw_gMTKeyDtor) (key, dtor); +#endif + } + return 0; +} 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 + */ + +#ifdef CRTDLL +#undef CRTDLL +#endif + +#include +#include +#include +#include + +#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; diff --git a/winsup/mingw/tlsthrd.c b/winsup/mingw/tlsthrd.c new file mode 100644 index 000000000..a3758076d --- /dev/null +++ b/winsup/mingw/tlsthrd.c @@ -0,0 +1,148 @@ +/** + * 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 + * + * This file is used by if gcc is built with --enable-threads=win32. + * + * Based on version created by Mumit Khan + * + */ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +WINBOOL __mingw_TLScallback (HANDLE hDllHandle, DWORD reason, LPVOID reserved); +int ___w64_mingwthr_remove_key_dtor (DWORD key); +int ___w64_mingwthr_add_key_dtor (DWORD key, void (*dtor)(void *)); + +/* To protect the thread/key association data structure modifications. */ +static CRITICAL_SECTION __mingwthr_cs; +static volatile int __mingwthr_cs_init = 0; + +typedef struct __mingwthr_key __mingwthr_key_t; + +/* The list of threads active with key/dtor pairs. */ +struct __mingwthr_key { + DWORD key; + void (*dtor)(void *); + __mingwthr_key_t volatile *next; +}; + + +static __mingwthr_key_t volatile *key_dtor_list; + +int +___w64_mingwthr_add_key_dtor (DWORD key, void (*dtor)(void *)) +{ + __mingwthr_key_t *new_key; + + if (__mingwthr_cs_init == 0) + return 0; + new_key = (__mingwthr_key_t *) calloc (1, sizeof (__mingwthr_key_t)); + if (new_key == NULL) + return -1; + + new_key->key = key; + new_key->dtor = dtor; + + EnterCriticalSection (&__mingwthr_cs); + + new_key->next = key_dtor_list; + key_dtor_list = new_key; + + LeaveCriticalSection (&__mingwthr_cs); + return 0; +} + +int +___w64_mingwthr_remove_key_dtor (DWORD key) +{ + __mingwthr_key_t volatile *prev_key; + __mingwthr_key_t volatile *cur_key; + + if (__mingwthr_cs_init == 0) + return 0; + + EnterCriticalSection (&__mingwthr_cs); + + prev_key = NULL; + cur_key = key_dtor_list; + + while (cur_key != NULL) + { + if ( cur_key->key == key) + { + if (prev_key == NULL) + key_dtor_list = cur_key->next; + else + prev_key->next = cur_key->next; + + free ((void*)cur_key); + break; + } + prev_key = cur_key; + cur_key = cur_key->next; + } + + LeaveCriticalSection (&__mingwthr_cs); + return 0; +} + +static void +__mingwthr_run_key_dtors (void) +{ + __mingwthr_key_t volatile *keyp; + + if (__mingwthr_cs_init == 0) + return; + EnterCriticalSection (&__mingwthr_cs); + + for (keyp = key_dtor_list; keyp; ) + { + LPVOID value = TlsGetValue (keyp->key); + if (GetLastError () == ERROR_SUCCESS) + { + if (value) + (*keyp->dtor) (value); + } + keyp = keyp->next; + } + + LeaveCriticalSection (&__mingwthr_cs); +} + +WINBOOL +__mingw_TLScallback (HANDLE hDllHandle __attribute__ ((__unused__)), + DWORD reason, + LPVOID reserved __attribute__ ((__unused__))) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + if (__mingwthr_cs_init == 0) + InitializeCriticalSection (&__mingwthr_cs); + __mingwthr_cs_init = 1; + break; + case DLL_PROCESS_DETACH: + __mingwthr_run_key_dtors(); + if (__mingwthr_cs_init == 1) + { + __mingwthr_cs_init = 0; + DeleteCriticalSection (&__mingwthr_cs); + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + __mingwthr_run_key_dtors(); + break; + } + return TRUE; +} +