1 /* Register destructors for C++ TLS variables declared with thread_local.
2 Copyright (C) 2013-2015 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/>. */
22 typedef void (*dtor_func
) (void *);
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
43 __cxa_thread_atexit_impl (dtor_func func
, void *obj
, void *dso_symbol
)
46 struct dtor_list
*new = calloc (1, sizeof (struct dtor_list
));
49 new->next
= tls_dtor_list
;
52 /* See if we already encountered the DSO. */
53 __rtld_lock_lock_recursive (GL(dl_load_lock
));
55 if (__glibc_unlikely (dso_symbol_cache
!= dso_symbol
))
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
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
;
71 new->map
->l_tls_dtor_count
++;
73 __rtld_lock_unlock_recursive (GL(dl_load_lock
));
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. */
81 __call_tls_dtors (void)
85 struct dtor_list
*cur
= tls_dtor_list
;
86 tls_dtor_list
= tls_dtor_list
->next
;
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
));
102 libc_hidden_def (__call_tls_dtors
)