mirror of
https://git.musl-libc.org/git/musl
synced 2025-02-15 17:54:23 +03:00
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
32
src/env/__init_tls.c
vendored
32
src/env/__init_tls.c
vendored
@ -8,29 +8,33 @@
|
|||||||
|
|
||||||
#ifndef SHARED
|
#ifndef SHARED
|
||||||
|
|
||||||
static void *image;
|
struct tls_image {
|
||||||
static size_t len, size, align;
|
void *image;
|
||||||
|
size_t len, size, align;
|
||||||
|
} __static_tls ATTR_LIBC_VISIBILITY;
|
||||||
|
|
||||||
|
#define T __static_tls
|
||||||
|
|
||||||
void *__copy_tls(unsigned char *mem)
|
void *__copy_tls(unsigned char *mem)
|
||||||
{
|
{
|
||||||
pthread_t td;
|
pthread_t td;
|
||||||
if (!image) return mem;
|
if (!T.image) return mem;
|
||||||
void **dtv = (void *)mem;
|
void **dtv = (void *)mem;
|
||||||
dtv[0] = (void *)1;
|
dtv[0] = (void *)1;
|
||||||
#ifdef TLS_ABOVE_TP
|
#ifdef TLS_ABOVE_TP
|
||||||
mem += sizeof(void *) * 2;
|
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;
|
td = (pthread_t)mem;
|
||||||
mem += sizeof(struct pthread);
|
mem += sizeof(struct pthread);
|
||||||
#else
|
#else
|
||||||
mem += libc.tls_size - sizeof(struct pthread);
|
mem += libc.tls_size - sizeof(struct pthread);
|
||||||
mem -= (uintptr_t)mem & (align-1);
|
mem -= (uintptr_t)mem & (T.align-1);
|
||||||
td = (pthread_t)mem;
|
td = (pthread_t)mem;
|
||||||
mem -= size;
|
mem -= T.size;
|
||||||
#endif
|
#endif
|
||||||
td->dtv = dtv;
|
td->dtv = dtv;
|
||||||
dtv[1] = mem;
|
dtv[1] = mem;
|
||||||
memcpy(mem, image, len);
|
memcpy(mem, T.image, T.len);
|
||||||
return td;
|
return td;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,15 +77,15 @@ void __init_tls(size_t *aux)
|
|||||||
}
|
}
|
||||||
if (!tls_phdr) return;
|
if (!tls_phdr) return;
|
||||||
|
|
||||||
image = (void *)(base + tls_phdr->p_vaddr);
|
T.image = (void *)(base + tls_phdr->p_vaddr);
|
||||||
len = tls_phdr->p_filesz;
|
T.len = tls_phdr->p_filesz;
|
||||||
size = tls_phdr->p_memsz;
|
T.size = tls_phdr->p_memsz;
|
||||||
align = tls_phdr->p_align;
|
T.align = tls_phdr->p_align;
|
||||||
|
|
||||||
size += (-size - (uintptr_t)image) & (align-1);
|
T.size += (-T.size - (uintptr_t)T.image) & (T.align-1);
|
||||||
if (align < 4*sizeof(size_t)) align = 4*sizeof(size_t);
|
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,
|
mem = __mmap(0, libc.tls_size, PROT_READ|PROT_WRITE,
|
||||||
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||||
|
22
src/env/__reset_tls.c
vendored
Normal file
22
src/env/__reset_tls.c
vendored
Normal file
@ -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)
|
void *__copy_tls(unsigned char *mem)
|
||||||
{
|
{
|
||||||
pthread_t td;
|
pthread_t td;
|
||||||
|
@ -19,6 +19,8 @@ static void dummy_1(pthread_t self)
|
|||||||
}
|
}
|
||||||
weak_alias(dummy_1, __pthread_tsd_run_dtors);
|
weak_alias(dummy_1, __pthread_tsd_run_dtors);
|
||||||
|
|
||||||
|
void __reset_tls();
|
||||||
|
|
||||||
static void cleanup_fromsig(void *p)
|
static void cleanup_fromsig(void *p)
|
||||||
{
|
{
|
||||||
pthread_t self = __pthread_self();
|
pthread_t self = __pthread_self();
|
||||||
@ -28,6 +30,7 @@ static void cleanup_fromsig(void *p)
|
|||||||
self->canceldisable = 0;
|
self->canceldisable = 0;
|
||||||
self->cancelasync = 0;
|
self->cancelasync = 0;
|
||||||
self->unblock_cancel = 0;
|
self->unblock_cancel = 0;
|
||||||
|
__reset_tls();
|
||||||
longjmp(p, 1);
|
longjmp(p, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user