]> git.ipfire.org Git - thirdparty/glibc.git/blame - stdlib/cxa_thread_atexit_impl.c
Use glibc_likely instead __builtin_expect.
[thirdparty/glibc.git] / stdlib / cxa_thread_atexit_impl.c
CommitLineData
ba384f6e 1/* Register destructors for C++ TLS variables declared with thread_local.
d4697bc9 2 Copyright (C) 2013-2014 Free Software Foundation, Inc.
ba384f6e
SP
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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/>. */
18
19#include <stdlib.h>
20#include <ldsodefs.h>
21
22typedef void (*dtor_func) (void *);
23
24struct dtor_list
25{
26 dtor_func func;
27 void *obj;
28 struct link_map *map;
29 struct dtor_list *next;
30};
31
32static __thread struct dtor_list *tls_dtor_list;
33static __thread void *dso_symbol_cache;
34static __thread struct link_map *lm_cache;
35
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. */
42int
43__cxa_thread_atexit_impl (dtor_func func, void *obj, void *dso_symbol)
44{
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;
51
52 /* See if we already encountered the DSO. */
53 __rtld_lock_lock_recursive (GL(dl_load_lock));
54
a1ffb40e 55 if (__glibc_unlikely (dso_symbol_cache != dso_symbol))
ba384f6e
SP
56 {
57 ElfW(Addr) caller = (ElfW(Addr)) dso_symbol;
58
59 struct link_map *l = _dl_find_dso_for_object (caller);
60
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;
64 }
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;
69
70 new->map = lm_cache;
71 new->map->l_tls_dtor_count++;
72
73 __rtld_lock_unlock_recursive (GL(dl_load_lock));
74
75 return 0;
76}
77
78/* Call the destructors. This is called either when a thread returns from the
e57b0c61 79 initial function or when the process exits via the exit function. */
ba384f6e
SP
80void
81__call_tls_dtors (void)
82{
83 while (tls_dtor_list)
84 {
85 struct dtor_list *cur = tls_dtor_list;
86 tls_dtor_list = tls_dtor_list->next;
87
88 cur->func (cur->obj);
89
90 __rtld_lock_lock_recursive (GL(dl_load_lock));
91
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;
96
97 __rtld_lock_unlock_recursive (GL(dl_load_lock));
98
99 free (cur);
100 }
101}
102libc_hidden_def (__call_tls_dtors)