about summary refs log tree commit diff
path: root/elf/dl-close.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-close.c')
-rw-r--r--elf/dl-close.c51
1 files changed, 48 insertions, 3 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 78b143f8ec..b482e89f13 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -321,8 +321,9 @@ _dl_close (void *_map)
   _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);
+  size_t tls_free_start;
+  size_t tls_free_end;
+  tls_free_start = tls_free_end = NO_TLS_OFFSET;
 #endif
 
   /* Check each element of the search list to see if all references to
@@ -371,9 +372,50 @@ _dl_close (void *_map)
 		     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 TLS_TCB_AT_TP
+		  if (tls_free_start == NO_TLS_OFFSET
+		      || (size_t) imap->l_tls_offset == tls_free_start)
+		    {
+		      /* Extend the contiguous chunk being reclaimed.  */
+		      tls_free_start
+			= imap->l_tls_offset - imap->l_tls_blocksize;
+
+		      if (tls_free_end == NO_TLS_OFFSET)
+			tls_free_end = imap->l_tls_offset;
+		    }
+		  else if (imap->l_tls_offset - imap->l_tls_blocksize
+			   == tls_free_end)
+		    /* Extend the chunk backwards.  */
+		    tls_free_end = imap->l_tls_offset;
+		  else
+		    {
+		      /* This isn't contiguous with the last chunk freed.
+			 One of them will be leaked unless we can free
+			 one block right away.  */
+		      if (tls_free_end == GL(dl_tls_static_used))
+			{
+			  GL(dl_tls_static_used) = tls_free_start;
+			  tls_free_end = imap->l_tls_offset;
+			  tls_free_start
+			    = tls_free_end - imap->l_tls_blocksize;
+			}
+		      else if ((size_t) imap->l_tls_offset
+			       == GL(dl_tls_static_used))
+			GL(dl_tls_static_used)
+			  = imap->l_tls_offset - imap->l_tls_blocksize;
+		      else if (tls_free_end < (size_t) imap->l_tls_offset)
+			{
+			  /* We pick the later block.  It has a chance to
+			     be freed.  */
+			  tls_free_end = imap->l_tls_offset;
+			  tls_free_start
+			    = tls_free_end - imap->l_tls_blocksize;
+			}
+		    }
+# elif TLS_DTV_AT_TP
 		  if ((size_t) imap->l_tls_offset == tls_free_end)
 		    /* Extend the contiguous chunk being reclaimed.  */
-		    tls_free_end += imap->l_tls_blocksize;
+		    tls_free_end -= imap->l_tls_blocksize;
 		  else if (imap->l_tls_offset + imap->l_tls_blocksize
 			   == tls_free_start)
 		    /* Extend the chunk backwards.  */
@@ -387,6 +429,9 @@ _dl_close (void *_map)
 		      tls_free_start = imap->l_tls_offset;
 		      tls_free_end = tls_free_start + imap->l_tls_blocksize;
 		    }
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
 		}
 	    }
 #endif