123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- // Copyright (C) 2012-2022 Free Software Foundation, Inc.
- //
- // This file is part of GCC.
- //
- // GCC is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 3, or (at your option)
- // any later version.
- // GCC is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // Under Section 7 of GPL version 3, you are granted additional
- // permissions described in the GCC Runtime Library Exception, version
- // 3.1, as published by the Free Software Foundation.
- // You should have received a copy of the GNU General Public License and
- // a copy of the GCC Runtime Library Exception along with this program;
- // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- // <http://www.gnu.org/licenses/>.
- #include <cxxabi.h>
- #include <cstdlib>
- #include <new>
- #include "bits/gthr.h"
- #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #endif
- // Simplify it a little for this file.
- #ifndef _GLIBCXX_CDTOR_CALLABI
- # define _GLIBCXX_CDTOR_CALLABI
- #endif
- #if _GLIBCXX_HAVE___CXA_THREAD_ATEXIT
- // Libc provides __cxa_thread_atexit definition.
- #elif _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL
- extern "C" int __cxa_thread_atexit_impl (void (_GLIBCXX_CDTOR_CALLABI *func) (void *),
- void *arg, void *d);
- extern "C" int
- __cxxabiv1::__cxa_thread_atexit (void (_GLIBCXX_CDTOR_CALLABI *dtor)(void *),
- void *obj, void *dso_handle)
- _GLIBCXX_NOTHROW
- {
- return __cxa_thread_atexit_impl (dtor, obj, dso_handle);
- }
- #else /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
- namespace {
- // One element in a singly-linked stack of cleanups.
- struct elt
- {
- void (_GLIBCXX_CDTOR_CALLABI *destructor)(void *);
- void *object;
- elt *next;
- #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
- HMODULE dll;
- #endif
- };
- // Keep a per-thread list of cleanups in gthread_key storage.
- __gthread_key_t key;
- // But also support non-threaded mode.
- elt *single_thread;
- // Run the specified stack of cleanups.
- void run (void *p)
- {
- elt *e = static_cast<elt*>(p);
- while (e)
- {
- elt *old_e = e;
- e->destructor (e->object);
- #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
- /* Decrement DLL count */
- if (e->dll)
- FreeLibrary (e->dll);
- #endif
- e = e->next;
- delete (old_e);
- }
- }
- // Run the stack of cleanups for the current thread.
- void run ()
- {
- void *e;
- if (__gthread_active_p ())
- {
- e = __gthread_getspecific (key);
- __gthread_setspecific (key, NULL);
- }
- else
- {
- e = single_thread;
- single_thread = NULL;
- }
- run (e);
- }
- // Initialize the key for the cleanup stack. We use a static local for
- // key init/delete rather than atexit so that delete is run on dlclose.
- void key_init() {
- struct key_s {
- key_s() { __gthread_key_create (&key, run); }
- ~key_s() { __gthread_key_delete (key); }
- };
- static key_s ks;
- // Also make sure the destructors are run by std::exit.
- // FIXME TLS cleanups should run before static cleanups and atexit
- // cleanups.
- std::atexit (run);
- }
- }
- extern "C" int
- __cxxabiv1::__cxa_thread_atexit (void (_GLIBCXX_CDTOR_CALLABI *dtor)(void *),
- void *obj, void */*dso_handle*/)
- _GLIBCXX_NOTHROW
- {
- // Do this initialization once.
- if (__gthread_active_p ())
- {
- // When threads are active use __gthread_once.
- static __gthread_once_t once = __GTHREAD_ONCE_INIT;
- __gthread_once (&once, key_init);
- }
- else
- {
- // And when threads aren't active use a static local guard.
- static bool queued;
- if (!queued)
- {
- queued = true;
- std::atexit (run);
- }
- }
- elt *first;
- if (__gthread_active_p ())
- first = static_cast<elt*>(__gthread_getspecific (key));
- else
- first = single_thread;
- elt *new_elt = new (std::nothrow) elt;
- if (!new_elt)
- return -1;
- new_elt->destructor = dtor;
- new_elt->object = obj;
- new_elt->next = first;
- #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
- /* Store the DLL address for a later call to FreeLibrary in new_elt and
- increment DLL load count. This blocks the unloading of the DLL
- before the thread-local dtors have been called. This does NOT help
- if FreeLibrary/dlclose is called in excess. */
- GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- (LPCWSTR) dtor, &new_elt->dll);
- #endif
- if (__gthread_active_p ())
- __gthread_setspecific (key, new_elt);
- else
- single_thread = new_elt;
- return 0;
- }
- #endif /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
|