mirror of git://git.musl-libc.org/musl
add system for resetting TLS to initial values
this is needed for reused threads in the SIGEV_THREAD timer notification system, and could be reused elsewhere in the future if needed, though it should be refactored for such use. for static linking, __init_tls.c is simply modified to export the TLS info in a structure with external linkage, rather than using statics. this perhaps makes the code more clear, since the statics were poorly named for statics. the new __reset_tls.c is only linked if it is used. for dynamic linking, the code is in dynlink.c. sharing code with __copy_tls is not practical since __reset_tls must also re-zero thread-local bss.
This commit is contained in:
parent
7356c2554e
commit
7c6c290695
|
@ -8,29 +8,33 @@
|
|||
|
||||
#ifndef SHARED
|
||||
|
||||
static void *image;
|
||||
static size_t len, size, align;
|
||||
struct tls_image {
|
||||
void *image;
|
||||
size_t len, size, align;
|
||||
} __static_tls ATTR_LIBC_VISIBILITY;
|
||||
|
||||
#define T __static_tls
|
||||
|
||||
void *__copy_tls(unsigned char *mem)
|
||||
{
|
||||
pthread_t td;
|
||||
if (!image) return mem;
|
||||
if (!T.image) return mem;
|
||||
void **dtv = (void *)mem;
|
||||
dtv[0] = (void *)1;
|
||||
#ifdef TLS_ABOVE_TP
|
||||
mem += sizeof(void *) * 2;
|
||||
mem += -((uintptr_t)mem + sizeof(struct pthread)) & (align-1);
|
||||
mem += -((uintptr_t)mem + sizeof(struct pthread)) & (T.align-1);
|
||||
td = (pthread_t)mem;
|
||||
mem += sizeof(struct pthread);
|
||||
#else
|
||||
mem += libc.tls_size - sizeof(struct pthread);
|
||||
mem -= (uintptr_t)mem & (align-1);
|
||||
mem -= (uintptr_t)mem & (T.align-1);
|
||||
td = (pthread_t)mem;
|
||||
mem -= size;
|
||||
mem -= T.size;
|
||||
#endif
|
||||
td->dtv = dtv;
|
||||
dtv[1] = mem;
|
||||
memcpy(mem, image, len);
|
||||
memcpy(mem, T.image, T.len);
|
||||
return td;
|
||||
}
|
||||
|
||||
|
@ -73,15 +77,15 @@ void __init_tls(size_t *aux)
|
|||
}
|
||||
if (!tls_phdr) return;
|
||||
|
||||
image = (void *)(base + tls_phdr->p_vaddr);
|
||||
len = tls_phdr->p_filesz;
|
||||
size = tls_phdr->p_memsz;
|
||||
align = tls_phdr->p_align;
|
||||
T.image = (void *)(base + tls_phdr->p_vaddr);
|
||||
T.len = tls_phdr->p_filesz;
|
||||
T.size = tls_phdr->p_memsz;
|
||||
T.align = tls_phdr->p_align;
|
||||
|
||||
size += (-size - (uintptr_t)image) & (align-1);
|
||||
if (align < 4*sizeof(size_t)) align = 4*sizeof(size_t);
|
||||
T.size += (-T.size - (uintptr_t)T.image) & (T.align-1);
|
||||
if (T.align < 4*sizeof(size_t)) T.align = 4*sizeof(size_t);
|
||||
|
||||
libc.tls_size = 2*sizeof(void *)+size+align+sizeof(struct pthread);
|
||||
libc.tls_size = 2*sizeof(void *)+T.size+T.align+sizeof(struct pthread);
|
||||
|
||||
mem = __mmap(0, libc.tls_size, PROT_READ|PROT_WRITE,
|
||||
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef SHARED
|
||||
|
||||
#include <string.h>
|
||||
#include "pthread_impl.h"
|
||||
#include "libc.h"
|
||||
|
||||
extern struct tls_image {
|
||||
void *image;
|
||||
size_t len, size, align;
|
||||
} __static_tls ATTR_LIBC_VISIBILITY;
|
||||
|
||||
#define T __static_tls
|
||||
|
||||
void __reset_tls()
|
||||
{
|
||||
if (!T.size) return;
|
||||
pthread_t self = __pthread_self();
|
||||
memcpy(self->dtv[1], T.image, T.len);
|
||||
memset((char *)self->dtv[1]+T.len, 0, T.size-T.len);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -783,6 +783,19 @@ void _dl_debug_state(void)
|
|||
{
|
||||
}
|
||||
|
||||
void __reset_tls()
|
||||
{
|
||||
pthread_t self = __pthread_self();
|
||||
struct dso *p;
|
||||
for (p=head; p; p=p->next) {
|
||||
if (!p->tls_id || !self->dtv[p->tls_id]) continue;
|
||||
memcpy(self->dtv[p->tls_id], p->tls_image, p->tls_len);
|
||||
memset((char *)self->dtv[p->tls_id]+p->tls_len, 0,
|
||||
p->tls_size - p->tls_len);
|
||||
if (p->tls_id == (size_t)self->dtv[0]) break;
|
||||
}
|
||||
}
|
||||
|
||||
void *__copy_tls(unsigned char *mem)
|
||||
{
|
||||
pthread_t td;
|
||||
|
|
|
@ -19,6 +19,8 @@ static void dummy_1(pthread_t self)
|
|||
}
|
||||
weak_alias(dummy_1, __pthread_tsd_run_dtors);
|
||||
|
||||
void __reset_tls();
|
||||
|
||||
static void cleanup_fromsig(void *p)
|
||||
{
|
||||
pthread_t self = __pthread_self();
|
||||
|
@ -28,6 +30,7 @@ static void cleanup_fromsig(void *p)
|
|||
self->canceldisable = 0;
|
||||
self->cancelasync = 0;
|
||||
self->unblock_cancel = 0;
|
||||
__reset_tls();
|
||||
longjmp(p, 1);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue