mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-28 23:34:53 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			103 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Register destructors for C++ TLS variables declared with thread_local.
 | |
|    Copyright (C) 2013-2014 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
| 
 | |
|    The GNU C Library is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU Lesser General Public
 | |
|    License as published by the Free Software Foundation; either
 | |
|    version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|    The GNU C Library is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Lesser General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Lesser General Public
 | |
|    License along with the GNU C Library; if not, see
 | |
|    <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <ldsodefs.h>
 | |
| 
 | |
| typedef void (*dtor_func) (void *);
 | |
| 
 | |
| struct dtor_list
 | |
| {
 | |
|   dtor_func func;
 | |
|   void *obj;
 | |
|   struct link_map *map;
 | |
|   struct dtor_list *next;
 | |
| };
 | |
| 
 | |
| static __thread struct dtor_list *tls_dtor_list;
 | |
| static __thread void *dso_symbol_cache;
 | |
| static __thread struct link_map *lm_cache;
 | |
| 
 | |
| /* Register a destructor for TLS variables declared with the 'thread_local'
 | |
|    keyword.  This function is only called from code generated by the C++
 | |
|    compiler.  FUNC is the destructor function and OBJ is the object to be
 | |
|    passed to the destructor.  DSO_SYMBOL is the __dso_handle symbol that each
 | |
|    DSO has at a unique address in its map, added from crtbegin.o during the
 | |
|    linking phase.  */
 | |
| int
 | |
| __cxa_thread_atexit_impl (dtor_func func, void *obj, void *dso_symbol)
 | |
| {
 | |
|   /* Prepend.  */
 | |
|   struct dtor_list *new = calloc (1, sizeof (struct dtor_list));
 | |
|   new->func = func;
 | |
|   new->obj = obj;
 | |
|   new->next = tls_dtor_list;
 | |
|   tls_dtor_list = new;
 | |
| 
 | |
|   /* See if we already encountered the DSO.  */
 | |
|   __rtld_lock_lock_recursive (GL(dl_load_lock));
 | |
| 
 | |
|   if (__glibc_unlikely (dso_symbol_cache != dso_symbol))
 | |
|     {
 | |
|       ElfW(Addr) caller = (ElfW(Addr)) dso_symbol;
 | |
| 
 | |
|       struct link_map *l = _dl_find_dso_for_object (caller);
 | |
| 
 | |
|       /* If the address is not recognized the call comes from the main
 | |
|          program (we hope).  */
 | |
|       lm_cache = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
 | |
|     }
 | |
|   /* A destructor could result in a thread_local construction and the former
 | |
|      could have cleared the flag.  */
 | |
|   if (lm_cache->l_type == lt_loaded && lm_cache->l_tls_dtor_count == 0)
 | |
|     lm_cache->l_flags_1 |= DF_1_NODELETE;
 | |
| 
 | |
|   new->map = lm_cache;
 | |
|   new->map->l_tls_dtor_count++;
 | |
| 
 | |
|   __rtld_lock_unlock_recursive (GL(dl_load_lock));
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Call the destructors.  This is called either when a thread returns from the
 | |
|    initial function or when the process exits via the exit function.  */
 | |
| void
 | |
| __call_tls_dtors (void)
 | |
| {
 | |
|   while (tls_dtor_list)
 | |
|     {
 | |
|       struct dtor_list *cur = tls_dtor_list;
 | |
|       tls_dtor_list = tls_dtor_list->next;
 | |
| 
 | |
|       cur->func (cur->obj);
 | |
| 
 | |
|       __rtld_lock_lock_recursive (GL(dl_load_lock));
 | |
| 
 | |
|       /* Allow DSO unload if count drops to zero.  */
 | |
|       cur->map->l_tls_dtor_count--;
 | |
|       if (cur->map->l_tls_dtor_count == 0 && cur->map->l_type == lt_loaded)
 | |
|         cur->map->l_flags_1 &= ~DF_1_NODELETE;
 | |
| 
 | |
|       __rtld_lock_unlock_recursive (GL(dl_load_lock));
 | |
| 
 | |
|       free (cur);
 | |
|     }
 | |
| }
 | |
| libc_hidden_def (__call_tls_dtors)
 |