1*8feb0f0bSmrg // Copyright (C) 2012-2020 Free Software Foundation, Inc.
21debfc3dSmrg //
31debfc3dSmrg // This file is part of GCC.
41debfc3dSmrg //
51debfc3dSmrg // GCC is free software; you can redistribute it and/or modify
61debfc3dSmrg // it under the terms of the GNU General Public License as published by
71debfc3dSmrg // the Free Software Foundation; either version 3, or (at your option)
81debfc3dSmrg // any later version.
91debfc3dSmrg
101debfc3dSmrg // GCC is distributed in the hope that it will be useful,
111debfc3dSmrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
121debfc3dSmrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
131debfc3dSmrg // GNU General Public License for more details.
141debfc3dSmrg
151debfc3dSmrg // Under Section 7 of GPL version 3, you are granted additional
161debfc3dSmrg // permissions described in the GCC Runtime Library Exception, version
171debfc3dSmrg // 3.1, as published by the Free Software Foundation.
181debfc3dSmrg
191debfc3dSmrg // You should have received a copy of the GNU General Public License and
201debfc3dSmrg // a copy of the GCC Runtime Library Exception along with this program;
211debfc3dSmrg // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
221debfc3dSmrg // <http://www.gnu.org/licenses/>.
231debfc3dSmrg
241debfc3dSmrg #include <cxxabi.h>
251debfc3dSmrg #include <cstdlib>
261debfc3dSmrg #include <new>
271debfc3dSmrg #include "bits/gthr.h"
281debfc3dSmrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
291debfc3dSmrg #define WIN32_LEAN_AND_MEAN
301debfc3dSmrg #include <windows.h>
311debfc3dSmrg #endif
321debfc3dSmrg
331debfc3dSmrg #if _GLIBCXX_HAVE___CXA_THREAD_ATEXIT
341debfc3dSmrg
351debfc3dSmrg // Libc provides __cxa_thread_atexit definition.
361debfc3dSmrg
371debfc3dSmrg #elif _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL
381debfc3dSmrg
391debfc3dSmrg extern "C" int __cxa_thread_atexit_impl (void (*func) (void *),
401debfc3dSmrg void *arg, void *d);
411debfc3dSmrg extern "C" int
__cxa_thread_atexit(void (* dtor)(void *),void * obj,void * dso_handle)421debfc3dSmrg __cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *),
431debfc3dSmrg void *obj, void *dso_handle)
441debfc3dSmrg _GLIBCXX_NOTHROW
451debfc3dSmrg {
461debfc3dSmrg return __cxa_thread_atexit_impl (dtor, obj, dso_handle);
471debfc3dSmrg }
481debfc3dSmrg
491debfc3dSmrg #else /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
501debfc3dSmrg
511debfc3dSmrg namespace {
521debfc3dSmrg // One element in a singly-linked stack of cleanups.
531debfc3dSmrg struct elt
541debfc3dSmrg {
551debfc3dSmrg void (*destructor)(void *);
561debfc3dSmrg void *object;
571debfc3dSmrg elt *next;
581debfc3dSmrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
591debfc3dSmrg HMODULE dll;
601debfc3dSmrg #endif
611debfc3dSmrg };
621debfc3dSmrg
631debfc3dSmrg // Keep a per-thread list of cleanups in gthread_key storage.
641debfc3dSmrg __gthread_key_t key;
651debfc3dSmrg // But also support non-threaded mode.
661debfc3dSmrg elt *single_thread;
671debfc3dSmrg
681debfc3dSmrg // Run the specified stack of cleanups.
run(void * p)691debfc3dSmrg void run (void *p)
701debfc3dSmrg {
711debfc3dSmrg elt *e = static_cast<elt*>(p);
721debfc3dSmrg while (e)
731debfc3dSmrg {
741debfc3dSmrg elt *old_e = e;
751debfc3dSmrg e->destructor (e->object);
761debfc3dSmrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
771debfc3dSmrg /* Decrement DLL count */
781debfc3dSmrg if (e->dll)
791debfc3dSmrg FreeLibrary (e->dll);
801debfc3dSmrg #endif
811debfc3dSmrg e = e->next;
821debfc3dSmrg delete (old_e);
831debfc3dSmrg }
841debfc3dSmrg }
851debfc3dSmrg
861debfc3dSmrg // Run the stack of cleanups for the current thread.
run()871debfc3dSmrg void run ()
881debfc3dSmrg {
891debfc3dSmrg void *e;
901debfc3dSmrg if (__gthread_active_p ())
911debfc3dSmrg {
921debfc3dSmrg e = __gthread_getspecific (key);
931debfc3dSmrg __gthread_setspecific (key, NULL);
941debfc3dSmrg }
951debfc3dSmrg else
961debfc3dSmrg {
971debfc3dSmrg e = single_thread;
981debfc3dSmrg single_thread = NULL;
991debfc3dSmrg }
1001debfc3dSmrg run (e);
1011debfc3dSmrg }
1021debfc3dSmrg
1031debfc3dSmrg // Initialize the key for the cleanup stack. We use a static local for
1041debfc3dSmrg // key init/delete rather than atexit so that delete is run on dlclose.
key_init()1051debfc3dSmrg void key_init() {
1061debfc3dSmrg struct key_s {
1071debfc3dSmrg key_s() { __gthread_key_create (&key, run); }
1081debfc3dSmrg ~key_s() { __gthread_key_delete (key); }
1091debfc3dSmrg };
1101debfc3dSmrg static key_s ks;
1111debfc3dSmrg // Also make sure the destructors are run by std::exit.
1121debfc3dSmrg // FIXME TLS cleanups should run before static cleanups and atexit
1131debfc3dSmrg // cleanups.
1141debfc3dSmrg std::atexit (run);
1151debfc3dSmrg }
1161debfc3dSmrg }
1171debfc3dSmrg
1181debfc3dSmrg extern "C" int
__cxa_thread_atexit(void (* dtor)(void *),void * obj,void *)1191debfc3dSmrg __cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/)
1201debfc3dSmrg _GLIBCXX_NOTHROW
1211debfc3dSmrg {
1221debfc3dSmrg // Do this initialization once.
1231debfc3dSmrg if (__gthread_active_p ())
1241debfc3dSmrg {
1251debfc3dSmrg // When threads are active use __gthread_once.
1261debfc3dSmrg static __gthread_once_t once = __GTHREAD_ONCE_INIT;
1271debfc3dSmrg __gthread_once (&once, key_init);
1281debfc3dSmrg }
1291debfc3dSmrg else
1301debfc3dSmrg {
1311debfc3dSmrg // And when threads aren't active use a static local guard.
1321debfc3dSmrg static bool queued;
1331debfc3dSmrg if (!queued)
1341debfc3dSmrg {
1351debfc3dSmrg queued = true;
1361debfc3dSmrg std::atexit (run);
1371debfc3dSmrg }
1381debfc3dSmrg }
1391debfc3dSmrg
1401debfc3dSmrg elt *first;
1411debfc3dSmrg if (__gthread_active_p ())
1421debfc3dSmrg first = static_cast<elt*>(__gthread_getspecific (key));
1431debfc3dSmrg else
1441debfc3dSmrg first = single_thread;
1451debfc3dSmrg
1461debfc3dSmrg elt *new_elt = new (std::nothrow) elt;
1471debfc3dSmrg if (!new_elt)
1481debfc3dSmrg return -1;
1491debfc3dSmrg new_elt->destructor = dtor;
1501debfc3dSmrg new_elt->object = obj;
1511debfc3dSmrg new_elt->next = first;
1521debfc3dSmrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
1531debfc3dSmrg /* Store the DLL address for a later call to FreeLibrary in new_elt and
1541debfc3dSmrg increment DLL load count. This blocks the unloading of the DLL
1551debfc3dSmrg before the thread-local dtors have been called. This does NOT help
1561debfc3dSmrg if FreeLibrary/dlclose is called in excess. */
1571debfc3dSmrg GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
1581debfc3dSmrg (LPCWSTR) dtor, &new_elt->dll);
1591debfc3dSmrg #endif
1601debfc3dSmrg
1611debfc3dSmrg if (__gthread_active_p ())
1621debfc3dSmrg __gthread_setspecific (key, new_elt);
1631debfc3dSmrg else
1641debfc3dSmrg single_thread = new_elt;
1651debfc3dSmrg
1661debfc3dSmrg return 0;
1671debfc3dSmrg }
1681debfc3dSmrg
1691debfc3dSmrg #endif /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
170