1 // Copyright (C) 2012-2018 Free Software Foundation, Inc. 2 // 3 // This file is part of GCC. 4 // 5 // GCC is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 3, or (at your option) 8 // any later version. 9 10 // GCC is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 15 // Under Section 7 of GPL version 3, you are granted additional 16 // permissions described in the GCC Runtime Library Exception, version 17 // 3.1, as published by the Free Software Foundation. 18 19 // You should have received a copy of the GNU General Public License and 20 // a copy of the GCC Runtime Library Exception along with this program; 21 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 // <http://www.gnu.org/licenses/>. 23 24 #include <cxxabi.h> 25 #include <cstdlib> 26 #include <new> 27 #include "bits/gthr.h" 28 #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32 29 #define WIN32_LEAN_AND_MEAN 30 #include <windows.h> 31 #endif 32 33 #if _GLIBCXX_HAVE___CXA_THREAD_ATEXIT 34 35 // Libc provides __cxa_thread_atexit definition. 36 37 #elif _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL 38 39 extern "C" int __cxa_thread_atexit_impl (void (*func) (void *), 40 void *arg, void *d); 41 extern "C" int 42 __cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), 43 void *obj, void *dso_handle) 44 _GLIBCXX_NOTHROW 45 { 46 return __cxa_thread_atexit_impl (dtor, obj, dso_handle); 47 } 48 49 #else /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */ 50 51 namespace { 52 // One element in a singly-linked stack of cleanups. 53 struct elt 54 { 55 void (*destructor)(void *); 56 void *object; 57 elt *next; 58 #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32 59 HMODULE dll; 60 #endif 61 }; 62 63 // Keep a per-thread list of cleanups in gthread_key storage. 64 __gthread_key_t key; 65 // But also support non-threaded mode. 66 elt *single_thread; 67 68 // Run the specified stack of cleanups. 69 void run (void *p) 70 { 71 elt *e = static_cast<elt*>(p); 72 while (e) 73 { 74 elt *old_e = e; 75 e->destructor (e->object); 76 #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32 77 /* Decrement DLL count */ 78 if (e->dll) 79 FreeLibrary (e->dll); 80 #endif 81 e = e->next; 82 delete (old_e); 83 } 84 } 85 86 // Run the stack of cleanups for the current thread. 87 void run () 88 { 89 void *e; 90 if (__gthread_active_p ()) 91 { 92 e = __gthread_getspecific (key); 93 __gthread_setspecific (key, NULL); 94 } 95 else 96 { 97 e = single_thread; 98 single_thread = NULL; 99 } 100 run (e); 101 } 102 103 // Initialize the key for the cleanup stack. We use a static local for 104 // key init/delete rather than atexit so that delete is run on dlclose. 105 void key_init() { 106 struct key_s { 107 key_s() { __gthread_key_create (&key, run); } 108 ~key_s() { __gthread_key_delete (key); } 109 }; 110 static key_s ks; 111 // Also make sure the destructors are run by std::exit. 112 // FIXME TLS cleanups should run before static cleanups and atexit 113 // cleanups. 114 std::atexit (run); 115 } 116 } 117 118 extern "C" int 119 __cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/) 120 _GLIBCXX_NOTHROW 121 { 122 // Do this initialization once. 123 if (__gthread_active_p ()) 124 { 125 // When threads are active use __gthread_once. 126 static __gthread_once_t once = __GTHREAD_ONCE_INIT; 127 __gthread_once (&once, key_init); 128 } 129 else 130 { 131 // And when threads aren't active use a static local guard. 132 static bool queued; 133 if (!queued) 134 { 135 queued = true; 136 std::atexit (run); 137 } 138 } 139 140 elt *first; 141 if (__gthread_active_p ()) 142 first = static_cast<elt*>(__gthread_getspecific (key)); 143 else 144 first = single_thread; 145 146 elt *new_elt = new (std::nothrow) elt; 147 if (!new_elt) 148 return -1; 149 new_elt->destructor = dtor; 150 new_elt->object = obj; 151 new_elt->next = first; 152 #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32 153 /* Store the DLL address for a later call to FreeLibrary in new_elt and 154 increment DLL load count. This blocks the unloading of the DLL 155 before the thread-local dtors have been called. This does NOT help 156 if FreeLibrary/dlclose is called in excess. */ 157 GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, 158 (LPCWSTR) dtor, &new_elt->dll); 159 #endif 160 161 if (__gthread_active_p ()) 162 __gthread_setspecific (key, new_elt); 163 else 164 single_thread = new_elt; 165 166 return 0; 167 } 168 169 #endif /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */ 170