1*b1e83836Smrg // Copyright (C) 2012-2022 Free Software Foundation, Inc.
248fb7bfaSmrg //
348fb7bfaSmrg // This file is part of GCC.
448fb7bfaSmrg //
548fb7bfaSmrg // GCC is free software; you can redistribute it and/or modify
648fb7bfaSmrg // it under the terms of the GNU General Public License as published by
748fb7bfaSmrg // the Free Software Foundation; either version 3, or (at your option)
848fb7bfaSmrg // any later version.
948fb7bfaSmrg
1048fb7bfaSmrg // GCC is distributed in the hope that it will be useful,
1148fb7bfaSmrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
1248fb7bfaSmrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1348fb7bfaSmrg // GNU General Public License for more details.
1448fb7bfaSmrg
1548fb7bfaSmrg // Under Section 7 of GPL version 3, you are granted additional
1648fb7bfaSmrg // permissions described in the GCC Runtime Library Exception, version
1748fb7bfaSmrg // 3.1, as published by the Free Software Foundation.
1848fb7bfaSmrg
1948fb7bfaSmrg // You should have received a copy of the GNU General Public License and
2048fb7bfaSmrg // a copy of the GCC Runtime Library Exception along with this program;
2148fb7bfaSmrg // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2248fb7bfaSmrg // <http://www.gnu.org/licenses/>.
2348fb7bfaSmrg
2448fb7bfaSmrg #include <cxxabi.h>
2548fb7bfaSmrg #include <cstdlib>
2648fb7bfaSmrg #include <new>
2748fb7bfaSmrg #include "bits/gthr.h"
284d5abbe8Smrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
294d5abbe8Smrg #define WIN32_LEAN_AND_MEAN
304d5abbe8Smrg #include <windows.h>
314d5abbe8Smrg #endif
3248fb7bfaSmrg
33*b1e83836Smrg // Simplify it a little for this file.
34*b1e83836Smrg #ifndef _GLIBCXX_CDTOR_CALLABI
35*b1e83836Smrg # define _GLIBCXX_CDTOR_CALLABI
36*b1e83836Smrg #endif
37*b1e83836Smrg
38b17d1066Smrg #if _GLIBCXX_HAVE___CXA_THREAD_ATEXIT
39b17d1066Smrg
40b17d1066Smrg // Libc provides __cxa_thread_atexit definition.
41b17d1066Smrg
42b17d1066Smrg #elif _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL
4348fb7bfaSmrg
44*b1e83836Smrg extern "C" int __cxa_thread_atexit_impl (void (_GLIBCXX_CDTOR_CALLABI *func) (void *),
4548fb7bfaSmrg void *arg, void *d);
4648fb7bfaSmrg extern "C" int
__cxa_thread_atexit(void (_GLIBCXX_CDTOR_CALLABI * dtor)(void *),void * obj,void * dso_handle)47*b1e83836Smrg __cxxabiv1::__cxa_thread_atexit (void (_GLIBCXX_CDTOR_CALLABI *dtor)(void *),
4848fb7bfaSmrg void *obj, void *dso_handle)
4948fb7bfaSmrg _GLIBCXX_NOTHROW
5048fb7bfaSmrg {
5148fb7bfaSmrg return __cxa_thread_atexit_impl (dtor, obj, dso_handle);
5248fb7bfaSmrg }
5348fb7bfaSmrg
54cd5ea10dSmrg #else /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
5548fb7bfaSmrg
5648fb7bfaSmrg namespace {
5748fb7bfaSmrg // One element in a singly-linked stack of cleanups.
5848fb7bfaSmrg struct elt
5948fb7bfaSmrg {
60*b1e83836Smrg void (_GLIBCXX_CDTOR_CALLABI *destructor)(void *);
6148fb7bfaSmrg void *object;
6248fb7bfaSmrg elt *next;
634d5abbe8Smrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
644d5abbe8Smrg HMODULE dll;
654d5abbe8Smrg #endif
6648fb7bfaSmrg };
6748fb7bfaSmrg
6848fb7bfaSmrg // Keep a per-thread list of cleanups in gthread_key storage.
6948fb7bfaSmrg __gthread_key_t key;
7048fb7bfaSmrg // But also support non-threaded mode.
7148fb7bfaSmrg elt *single_thread;
7248fb7bfaSmrg
7348fb7bfaSmrg // Run the specified stack of cleanups.
run(void * p)7448fb7bfaSmrg void run (void *p)
7548fb7bfaSmrg {
7648fb7bfaSmrg elt *e = static_cast<elt*>(p);
7748fb7bfaSmrg while (e)
7848fb7bfaSmrg {
7948fb7bfaSmrg elt *old_e = e;
8048fb7bfaSmrg e->destructor (e->object);
814d5abbe8Smrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
824d5abbe8Smrg /* Decrement DLL count */
834d5abbe8Smrg if (e->dll)
844d5abbe8Smrg FreeLibrary (e->dll);
854d5abbe8Smrg #endif
8648fb7bfaSmrg e = e->next;
8748fb7bfaSmrg delete (old_e);
8848fb7bfaSmrg }
8948fb7bfaSmrg }
9048fb7bfaSmrg
9148fb7bfaSmrg // Run the stack of cleanups for the current thread.
run()9248fb7bfaSmrg void run ()
9348fb7bfaSmrg {
9448fb7bfaSmrg void *e;
9548fb7bfaSmrg if (__gthread_active_p ())
9648fb7bfaSmrg {
9748fb7bfaSmrg e = __gthread_getspecific (key);
9848fb7bfaSmrg __gthread_setspecific (key, NULL);
9948fb7bfaSmrg }
10048fb7bfaSmrg else
10148fb7bfaSmrg {
10248fb7bfaSmrg e = single_thread;
10348fb7bfaSmrg single_thread = NULL;
10448fb7bfaSmrg }
10548fb7bfaSmrg run (e);
10648fb7bfaSmrg }
10748fb7bfaSmrg
10848fb7bfaSmrg // Initialize the key for the cleanup stack. We use a static local for
10948fb7bfaSmrg // key init/delete rather than atexit so that delete is run on dlclose.
key_init()11048fb7bfaSmrg void key_init() {
11148fb7bfaSmrg struct key_s {
11248fb7bfaSmrg key_s() { __gthread_key_create (&key, run); }
11348fb7bfaSmrg ~key_s() { __gthread_key_delete (key); }
11448fb7bfaSmrg };
11548fb7bfaSmrg static key_s ks;
11648fb7bfaSmrg // Also make sure the destructors are run by std::exit.
11748fb7bfaSmrg // FIXME TLS cleanups should run before static cleanups and atexit
11848fb7bfaSmrg // cleanups.
11948fb7bfaSmrg std::atexit (run);
12048fb7bfaSmrg }
12148fb7bfaSmrg }
12248fb7bfaSmrg
12348fb7bfaSmrg extern "C" int
__cxa_thread_atexit(void (_GLIBCXX_CDTOR_CALLABI * dtor)(void *),void * obj,void *)124*b1e83836Smrg __cxxabiv1::__cxa_thread_atexit (void (_GLIBCXX_CDTOR_CALLABI *dtor)(void *),
125*b1e83836Smrg void *obj, void */*dso_handle*/)
12648fb7bfaSmrg _GLIBCXX_NOTHROW
12748fb7bfaSmrg {
12848fb7bfaSmrg // Do this initialization once.
12948fb7bfaSmrg if (__gthread_active_p ())
13048fb7bfaSmrg {
13148fb7bfaSmrg // When threads are active use __gthread_once.
13248fb7bfaSmrg static __gthread_once_t once = __GTHREAD_ONCE_INIT;
13348fb7bfaSmrg __gthread_once (&once, key_init);
13448fb7bfaSmrg }
13548fb7bfaSmrg else
13648fb7bfaSmrg {
13748fb7bfaSmrg // And when threads aren't active use a static local guard.
13848fb7bfaSmrg static bool queued;
13948fb7bfaSmrg if (!queued)
14048fb7bfaSmrg {
14148fb7bfaSmrg queued = true;
14248fb7bfaSmrg std::atexit (run);
14348fb7bfaSmrg }
14448fb7bfaSmrg }
14548fb7bfaSmrg
14648fb7bfaSmrg elt *first;
14748fb7bfaSmrg if (__gthread_active_p ())
14848fb7bfaSmrg first = static_cast<elt*>(__gthread_getspecific (key));
14948fb7bfaSmrg else
15048fb7bfaSmrg first = single_thread;
15148fb7bfaSmrg
15248fb7bfaSmrg elt *new_elt = new (std::nothrow) elt;
15348fb7bfaSmrg if (!new_elt)
15448fb7bfaSmrg return -1;
15548fb7bfaSmrg new_elt->destructor = dtor;
15648fb7bfaSmrg new_elt->object = obj;
15748fb7bfaSmrg new_elt->next = first;
1584d5abbe8Smrg #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
1594d5abbe8Smrg /* Store the DLL address for a later call to FreeLibrary in new_elt and
1604d5abbe8Smrg increment DLL load count. This blocks the unloading of the DLL
1614d5abbe8Smrg before the thread-local dtors have been called. This does NOT help
1624d5abbe8Smrg if FreeLibrary/dlclose is called in excess. */
1634d5abbe8Smrg GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
1644d5abbe8Smrg (LPCWSTR) dtor, &new_elt->dll);
1654d5abbe8Smrg #endif
16648fb7bfaSmrg
16748fb7bfaSmrg if (__gthread_active_p ())
16848fb7bfaSmrg __gthread_setspecific (key, new_elt);
16948fb7bfaSmrg else
17048fb7bfaSmrg single_thread = new_elt;
17148fb7bfaSmrg
17248fb7bfaSmrg return 0;
17348fb7bfaSmrg }
17448fb7bfaSmrg
175cd5ea10dSmrg #endif /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
176