about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-close.c45
-rw-r--r--elf/dl-libc.c4
2 files changed, 39 insertions, 10 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 094db533dd..632f8ba9fc 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -247,6 +247,11 @@ _dl_close (void *_map)
   _r_debug.r_state = RT_DELETE;
   _dl_debug_state ();
 
+#ifdef USE_TLS
+  size_t tls_free_start, tls_free_end;
+  tls_free_start = tls_free_end = GL(dl_tls_static_used);
+#endif
+
   /* Check each element of the search list to see if all references to
      it are gone.  */
   for (i = 0; list[i] != NULL; ++i)
@@ -286,6 +291,30 @@ _dl_close (void *_map)
 				     imap->l_init_called))
 		/* All dynamically loaded modules with TLS are unloaded.  */
 		GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
+
+	      if (imap->l_tls_offset != 0)
+		{
+		  /* Collect a contiguous chunk built from the objects in
+		     this search list, going in either direction.  When the
+		     whole chunk is at the end of the used area then we can
+		     reclaim it.  */
+		  if (imap->l_tls_offset == tls_free_end)
+		    /* Extend the contiguous chunk being reclaimed.  */
+		    tls_free_end += imap->l_tls_blocksize;
+		  else if (imap->l_tls_offset + imap->l_tls_blocksize
+			   == tls_free_start)
+		    /* Extend the chunk backwards.  */
+		    tls_free_start = imap->l_tls_offset;
+		  else
+		    {
+		      /* This isn't contiguous with the last chunk freed.
+			 One of them will be leaked.  */
+		      if (tls_free_end == GL(dl_tls_static_used))
+			GL(dl_tls_static_used) = tls_free_start;
+		      tls_free_start = imap->l_tls_offset;
+		      tls_free_end = tls_free_start + imap->l_tls_blocksize;
+		    }
+		}
 	    }
 #endif
 
@@ -363,11 +392,15 @@ _dl_close (void *_map)
     }
 
 #ifdef USE_TLS
-  /* If we removed any object which uses TLS bumnp the generation
-     counter.  */
+  /* If we removed any object which uses TLS bump the generation counter.  */
   if (any_tls)
-    if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
-      __libc_fatal (_("TLS generation counter wrapped!  Please send report with the 'glibcbug' script."));
+    {
+      if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
+	__libc_fatal (_("TLS generation counter wrapped!  Please send report with the 'glibcbug' script."));
+
+      if (tls_free_end == GL(dl_tls_static_used))
+	GL(dl_tls_static_used) = tls_free_start;
+    }
 #endif
 
   /* Notify the debugger those objects are finalized and gone.  */
@@ -424,8 +457,7 @@ free_slotinfo (struct dtv_slotinfo_list *elemp)
 #endif
 
 
-static void
-free_mem (void)
+libc_freeres_fn (free_mem)
 {
   if (__builtin_expect (GL(dl_global_scope_alloc), 0) != 0
       && GL(dl_main_searchlist)->r_nlist == GL(dl_initial_searchlist).r_nlist)
@@ -453,4 +485,3 @@ free_mem (void)
     GL(dl_tls_dtv_slotinfo_list)->next = NULL;
 #endif
 }
-text_set_element (__libc_subfreeres, free_mem);
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index 938b5d707d..d69e49f359 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -123,8 +123,7 @@ __libc_dlclose (void *__map)
 }
 
 
-static void
-free_mem (void)
+libc_freeres_fn (free_mem)
 {
   struct link_map *l;
   struct r_search_path_elem *d;
@@ -154,4 +153,3 @@ free_mem (void)
 	}
     }
 }
-text_set_element (__libc_subfreeres, free_mem);