Update copyright notices with scripts/update-copyrights
[glibc.git] / stdlib / cxa_thread_atexit_impl.c
blobd2f88d3ed83b13929c9ef03659be9a16c349a535
1 /* Register destructors for C++ TLS variables declared with thread_local.
2 Copyright (C) 2013-2014 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <stdlib.h>
20 #include <ldsodefs.h>
22 typedef void (*dtor_func) (void *);
24 struct dtor_list
26 dtor_func func;
27 void *obj;
28 struct link_map *map;
29 struct dtor_list *next;
32 static __thread struct dtor_list *tls_dtor_list;
33 static __thread void *dso_symbol_cache;
34 static __thread struct link_map *lm_cache;
36 /* Register a destructor for TLS variables declared with the 'thread_local'
37 keyword. This function is only called from code generated by the C++
38 compiler. FUNC is the destructor function and OBJ is the object to be
39 passed to the destructor. DSO_SYMBOL is the __dso_handle symbol that each
40 DSO has at a unique address in its map, added from crtbegin.o during the
41 linking phase. */
42 int
43 __cxa_thread_atexit_impl (dtor_func func, void *obj, void *dso_symbol)
45 /* Prepend. */
46 struct dtor_list *new = calloc (1, sizeof (struct dtor_list));
47 new->func = func;
48 new->obj = obj;
49 new->next = tls_dtor_list;
50 tls_dtor_list = new;
52 /* See if we already encountered the DSO. */
53 __rtld_lock_lock_recursive (GL(dl_load_lock));
55 if (__builtin_expect (dso_symbol_cache != dso_symbol, 0))
57 ElfW(Addr) caller = (ElfW(Addr)) dso_symbol;
59 struct link_map *l = _dl_find_dso_for_object (caller);
61 /* If the address is not recognized the call comes from the main
62 program (we hope). */
63 lm_cache = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
65 /* A destructor could result in a thread_local construction and the former
66 could have cleared the flag. */
67 if (lm_cache->l_type == lt_loaded && lm_cache->l_tls_dtor_count == 0)
68 lm_cache->l_flags_1 |= DF_1_NODELETE;
70 new->map = lm_cache;
71 new->map->l_tls_dtor_count++;
73 __rtld_lock_unlock_recursive (GL(dl_load_lock));
75 return 0;
78 /* Call the destructors. This is called either when a thread returns from the
79 initial function or when the process exits via the exit function. */
80 void
81 __call_tls_dtors (void)
83 while (tls_dtor_list)
85 struct dtor_list *cur = tls_dtor_list;
86 tls_dtor_list = tls_dtor_list->next;
88 cur->func (cur->obj);
90 __rtld_lock_lock_recursive (GL(dl_load_lock));
92 /* Allow DSO unload if count drops to zero. */
93 cur->map->l_tls_dtor_count--;
94 if (cur->map->l_tls_dtor_count == 0 && cur->map->l_type == lt_loaded)
95 cur->map->l_flags_1 &= ~DF_1_NODELETE;
97 __rtld_lock_unlock_recursive (GL(dl_load_lock));
99 free (cur);
102 libc_hidden_def (__call_tls_dtors)