diff options
Diffstat (limited to 'elf/dl-close.c')
-rw-r--r-- | elf/dl-close.c | 51 |
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 |