Support C++11 thread_local destructors.
[official-gcc.git] / libstdc++-v3 / libsupc++ / atexit_thread.cc
blob5e47708d93472884eed9246d4bef11ef1dc25999
1 // Copyright (C) 2012 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.
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.
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.
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/>.
24 #include <cxxabi.h>
25 #include <cstdlib>
26 #include <new>
27 #include "bits/gthr.h"
29 namespace {
30 // Data structure for the list of destructors: Singly-linked list
31 // of arrays.
32 class list
34 struct elt
36 void *object;
37 void (*destructor)(void *);
40 static const int max_nelts = 32;
42 list *next;
43 int nelts;
44 elt array[max_nelts];
46 elt *allocate_elt();
47 public:
48 void run();
49 static void run(void *p);
50 int add_elt(void (*)(void *), void *);
53 // Return the address of an open slot.
54 list::elt *
55 list::allocate_elt()
57 if (nelts < max_nelts)
58 return &array[nelts++];
59 if (!next)
60 next = new (std::nothrow) list();
61 if (!next)
62 return 0;
63 return next->allocate_elt();
66 // Run all the cleanups in the list.
67 void
68 list::run()
70 for (int i = nelts - 1; i >= 0; --i)
71 array[i].destructor (array[i].object);
72 if (next)
73 next->run();
76 // Static version to use as a callback to __gthread_key_create.
77 void
78 list::run(void *p)
80 static_cast<list *>(p)->run();
83 // The list of cleanups is per-thread.
84 thread_local list first;
86 // The pthread data structures for actually running the destructors at
87 // thread exit are shared. The constructor of the thread-local sentinel
88 // object in add_elt performs the initialization.
89 __gthread_key_t key;
90 __gthread_once_t once = __GTHREAD_ONCE_INIT;
91 void run_current () { first.run(); }
92 void key_init() {
93 __gthread_key_create (&key, list::run);
94 // Also make sure the destructors are run by std::exit.
95 // FIXME TLS cleanups should run before static cleanups and atexit
96 // cleanups.
97 std::atexit (run_current);
99 struct sentinel
101 sentinel()
103 if (__gthread_active_p ())
105 __gthread_once (&once, key_init);
106 __gthread_setspecific (key, &first);
108 else
109 std::atexit (run_current);
113 // Actually insert an element.
115 list::add_elt(void (*dtor)(void *), void *obj)
117 thread_local sentinel s;
118 elt *e = allocate_elt ();
119 if (!e)
120 return -1;
121 e->object = obj;
122 e->destructor = dtor;
123 return 0;
127 namespace __cxxabiv1
129 extern "C" int
130 __cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/)
131 _GLIBCXX_NOTHROW
133 return first.add_elt (dtor, obj);