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
35extern "C" int __cxa_thread_atexit_impl (void (*func) (void *),
36					 void *arg, void *d);
37extern "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
47namespace {
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
114extern "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