Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. // Copyright (C) 2012-2015 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_IMPL
  34.  
  35. extern "C" int __cxa_thread_atexit_impl (void (*func) (void *),
  36.                                          void *arg, void *d);
  37. extern "C" int
  38. __cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *),
  39.                                  void *obj, void *dso_handle)
  40.   _GLIBCXX_NOTHROW
  41. {
  42.   return __cxa_thread_atexit_impl (dtor, obj, dso_handle);
  43. }
  44.  
  45. #else /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
  46.  
  47. namespace {
  48.   // One element in a singly-linked stack of cleanups.
  49.   struct elt
  50.   {
  51.     void (*destructor)(void *);
  52.     void *object;
  53.     elt *next;
  54. #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
  55.     HMODULE dll;
  56. #endif
  57.   };
  58.  
  59.   // Keep a per-thread list of cleanups in gthread_key storage.
  60.   __gthread_key_t key;
  61.   // But also support non-threaded mode.
  62.   elt *single_thread;
  63.  
  64.   // Run the specified stack of cleanups.
  65.   void run (void *p)
  66.   {
  67.     elt *e = static_cast<elt*>(p);
  68.     while (e)
  69.       {
  70.         elt *old_e = e;
  71.         e->destructor (e->object);
  72. #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
  73.         /* Decrement DLL count */
  74.         if (e->dll)
  75.           FreeLibrary (e->dll);
  76. #endif
  77.         e = e->next;
  78.         delete (old_e);
  79.       }
  80.   }
  81.  
  82.   // Run the stack of cleanups for the current thread.
  83.   void run ()
  84.   {
  85.     void *e;
  86.     if (__gthread_active_p ())
  87.       {
  88.         e = __gthread_getspecific (key);
  89.         __gthread_setspecific (key, NULL);
  90.       }
  91.     else
  92.       {
  93.         e = single_thread;
  94.         single_thread = NULL;
  95.       }
  96.     run (e);
  97.   }
  98.  
  99.   // Initialize the key for the cleanup stack.  We use a static local for
  100.   // key init/delete rather than atexit so that delete is run on dlclose.
  101.   void key_init() {
  102.     struct key_s {
  103.       key_s() { __gthread_key_create (&key, run); }
  104.       ~key_s() { __gthread_key_delete (key); }
  105.     };
  106.     static key_s ks;
  107.     // Also make sure the destructors are run by std::exit.
  108.     // FIXME TLS cleanups should run before static cleanups and atexit
  109.     // cleanups.
  110.     std::atexit (run);
  111.   }
  112. }
  113.  
  114. extern "C" int
  115. __cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/)
  116.   _GLIBCXX_NOTHROW
  117. {
  118.   // Do this initialization once.
  119.   if (__gthread_active_p ())
  120.     {
  121.       // When threads are active use __gthread_once.
  122.       static __gthread_once_t once = __GTHREAD_ONCE_INIT;
  123.       __gthread_once (&once, key_init);
  124.     }
  125.   else
  126.     {
  127.       // And when threads aren't active use a static local guard.
  128.       static bool queued;
  129.       if (!queued)
  130.         {
  131.           queued = true;
  132.           std::atexit (run);
  133.         }
  134.     }
  135.  
  136.   elt *first;
  137.   if (__gthread_active_p ())
  138.     first = static_cast<elt*>(__gthread_getspecific (key));
  139.   else
  140.     first = single_thread;
  141.  
  142.   elt *new_elt = new (std::nothrow) elt;
  143.   if (!new_elt)
  144.     return -1;
  145.   new_elt->destructor = dtor;
  146.   new_elt->object = obj;
  147.   new_elt->next = first;
  148. #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
  149.   /* Store the DLL address for a later call to FreeLibrary in new_elt and
  150.      increment DLL load count.  This blocks the unloading of the DLL
  151.      before the thread-local dtors have been called.  This does NOT help
  152.      if FreeLibrary/dlclose is called in excess. */
  153.   GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
  154.                       (LPCWSTR) dtor, &new_elt->dll);
  155. #endif
  156.  
  157.   if (__gthread_active_p ())
  158.     __gthread_setspecific (key, new_elt);
  159.   else
  160.     single_thread = new_elt;
  161.  
  162.   return 0;
  163. }
  164.  
  165. #endif /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
  166.