Changeset 40abf56 in mainline for uspace/lib/c/generic/tls.c


Ignore:
Timestamp:
2018-07-18T19:42:28Z (6 years ago)
Author:
Jiří Zárevúcky <jiri.zarevucky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9bde0d5
Parents:
0b05082
git-author:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-07-18 19:05:08)
git-committer:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-07-18 19:42:28)
Message:

Make sure that a thread with uninitialized TLS does not need to call malloc()
to initialize it.

For threads and tasks created by loader, we create TLS beforehand and pass
it to the child. For tasks spawned directly by the kernel, we require it is
a static executable and allocate the initial TLS using as_area_create() instead
of the libc allocator.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/tls.c

    r0b05082 r40abf56  
    4444#include <macros.h>
    4545#include <elf/elf.h>
     46#include <as.h>
     47
     48#include <libarch/config.h>
     49
     50#ifdef CONFIG_RTLD
     51#include <rtld/rtld.h>
     52#endif
    4653
    4754#include "private/libc.h"
    48 
    49 #ifdef CONFIG_RTLD
    50 #include <rtld/rtld.h>
    51 #endif
    5255
    5356#if !defined(CONFIG_TLS_VARIANT_1) && !defined(CONFIG_TLS_VARIANT_2)
     
    5558#endif
    5659
     60static ptrdiff_t _tcb_data_offset(void)
     61{
     62        const elf_segment_header_t *tls =
     63            elf_get_phdr(__progsymbols.elfstart, PT_TLS);
     64
     65        size_t tls_align = tls ? tls->p_align : 1;
     66
     67#ifdef CONFIG_TLS_VARIANT_1
     68        return ALIGN_UP((ptrdiff_t) sizeof(tcb_t), tls_align);
     69#else
     70        size_t tls_size = tls ? tls->p_memsz : 0;
     71        return -ALIGN_UP((ptrdiff_t) tls_size, max(tls_align, _Alignof(tcb_t)));
     72#endif
     73}
     74
    5775/** Get address of static TLS block */
    5876void *tls_get(void)
     
    6179        assert(runtime_env == NULL);
    6280#endif
    63 
    64         const elf_segment_header_t *tls =
    65             elf_get_phdr(__progsymbols.elfstart, PT_TLS);
    66 
    67         if (tls == NULL)
    68                 return NULL;
    69 
    70 #ifdef CONFIG_TLS_VARIANT_1
    71         return (uint8_t *)__tcb_get() + ALIGN_UP(sizeof(tcb_t), tls->p_align);
    72 #else /* CONFIG_TLS_VARIANT_2 */
    73         return (uint8_t *)__tcb_get() - ALIGN_UP(tls->p_memsz, tls->p_align);
    74 #endif
     81        return (uint8_t *)__tcb_get() + _tcb_data_offset();
     82}
     83
     84static tcb_t *tls_make_generic(const void *elf, void *(*alloc)(size_t, size_t))
     85{
     86        assert(!elf_get_phdr(elf, PT_DYNAMIC));
     87#ifdef CONFIG_RTLD
     88        assert(runtime_env == NULL);
     89#endif
     90
     91        const elf_segment_header_t *tls = elf_get_phdr(elf, PT_TLS);
     92        size_t tls_size = tls ? tls->p_memsz : 0;
     93        size_t tls_align = tls ? tls->p_align : 1;
     94
     95        /*
     96         * We don't currently support alignment this big,
     97         * and neither should we need to.
     98         */
     99        assert(tls_align <= PAGE_SIZE);
     100
     101#ifdef CONFIG_TLS_VARIANT_1
     102        size_t alloc_size =
     103            ALIGN_UP(sizeof(tcb_t), tls_align) + tls_size;
     104#else
     105        size_t alloc_size =
     106            ALIGN_UP(tls_size, max(tls_align, _Alignof(tcb_t))) + sizeof(tcb_t);
     107#endif
     108
     109        void *area = alloc(max(tls_align, _Alignof(tcb_t)), alloc_size);
     110        if (!area)
     111                return NULL;
     112
     113#ifdef CONFIG_TLS_VARIANT_1
     114        tcb_t *tcb = area;
     115        uint8_t *data = (uint8_t *)tcb + _tcb_data_offset();
     116        memset(tcb, 0, sizeof(*tcb));
     117#else
     118        uint8_t *data = area;
     119        tcb_t *tcb = (tcb_t *) (data - _tcb_data_offset());
     120        memset(tcb, 0, sizeof(tcb_t));
     121        tcb->self = tcb;
     122#endif
     123
     124        if (!tls)
     125                return tcb;
     126
     127        uintptr_t bias = elf_get_bias(elf);
     128
     129        /* Copy thread local data from the initialization image. */
     130        memcpy(data, (void *)(tls->p_vaddr + bias), tls->p_filesz);
     131        /* Zero out the thread local uninitialized data. */
     132        memset(data + tls->p_filesz, 0, tls->p_memsz - tls->p_filesz);
     133
     134        return tcb;
     135}
     136
     137static void *early_alloc(size_t align, size_t alloc_size)
     138{
     139        assert(align <= PAGE_SIZE);
     140        alloc_size = ALIGN_UP(alloc_size, PAGE_SIZE);
     141
     142        void *area = as_area_create(AS_AREA_ANY, alloc_size,
     143            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
     144        if (area == AS_MAP_FAILED)
     145                return NULL;
     146        return area;
     147}
     148
     149/** Same as tls_make(), but uses as_area_create() instead of memalign().
     150 *  Only used in __libc_main() if the program was created by the kernel.
     151 */
     152tcb_t *tls_make_initial(const void *elf)
     153{
     154        return tls_make_generic(elf, early_alloc);
    75155}
    76156
     
    79159 * @return Pointer to TCB.
    80160 */
    81 tcb_t *tls_make(void)
    82 {
    83         void *data;
    84         tcb_t *tcb;
     161tcb_t *tls_make(const void *elf)
     162{
     163        // TODO: Always use rtld.
    85164
    86165#ifdef CONFIG_RTLD
     
    89168#endif
    90169
    91         const elf_segment_header_t *tls =
    92             elf_get_phdr(__progsymbols.elfstart, PT_TLS);
    93         if (tls == NULL)
    94                 return NULL;
    95 
    96         uintptr_t bias = elf_get_bias(__progsymbols.elfstart);
    97         size_t align = max(tls->p_align, _Alignof(tcb_t));
    98 
    99 #ifdef CONFIG_TLS_VARIANT_1
    100         tcb = tls_alloc_arch(
    101             ALIGN_UP(sizeof(tcb_t), align) + tls->p_memsz, align);
    102         data = (void *) tcb + ALIGN_UP(sizeof(tcb_t), align);
    103 #else
    104         tcb = tls_alloc_arch(
    105             ALIGN_UP(tls->p_memsz, align) + sizeof(tcb_t), align);
    106         data = (void *) tcb - ALIGN_UP(tls->p_memsz, tls->p_align);
    107 #endif
    108 
    109         /*
    110          * Copy thread local data from the initialization image.
    111          */
    112         memcpy(data, (void *)(tls->p_vaddr + bias), tls->p_filesz);
    113         /*
    114          * Zero out the thread local uninitialized data.
    115          */
    116         memset(data + tls->p_filesz, 0, tls->p_memsz - tls->p_filesz);
    117 
    118         return tcb;
     170        return tls_make_generic(elf, memalign);
    119171}
    120172
Note: See TracChangeset for help on using the changeset viewer.