Changeset 40abf56 in mainline


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.

Location:
uspace
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/elf/elf_load.c

    r0b05082 r40abf56  
    6868        }
    6969
    70         if (info->finfo.interp == NULL) {
     70        if (info->finfo.dynamic == NULL) {
    7171                /* Statically linked program */
    7272                DPRINTF("Binary is statically linked.\n");
  • uspace/lib/c/generic/fibril.c

    r0b05082 r40abf56  
    5050#include "private/thread.h"
    5151#include "private/fibril.h"
    52 
     52#include "private/libc.h"
    5353
    5454/**
     
    8585}
    8686
    87 /** Setup fibril information into TCB structure
    88  *
    89  */
    90 fibril_t *fibril_setup(void)
    91 {
    92         tcb_t *tcb = tls_make();
     87/** Allocate a fibril structure and TCB, but don't do anything else with it. */
     88fibril_t *fibril_alloc(void)
     89{
     90        tcb_t *tcb = tls_make(__progsymbols.elfstart);
    9391        if (!tcb)
    9492                return NULL;
     
    102100        tcb->fibril_data = fibril;
    103101        fibril->tcb = tcb;
    104 
    105         /*
    106          * We are called before __tcb_set(), so we need to use
    107          * futex_down/up() instead of futex_lock/unlock() that
    108          * may attempt to access TLS.
    109          */
    110         futex_down(&fibril_futex);
    111         list_append(&fibril->all_link, &fibril_list);
    112         futex_up(&fibril_futex);
    113 
     102        fibril->is_freeable = true;
     103
     104        fibril_setup(fibril);
    114105        return fibril;
     106}
     107
     108/**
     109 * Put the fibril into fibril_list.
     110 */
     111void fibril_setup(fibril_t *f)
     112{
     113        futex_lock(&fibril_futex);
     114        list_append(&f->all_link, &fibril_list);
     115        futex_unlock(&fibril_futex);
    115116}
    116117
     
    122123        if (!locked)
    123124                futex_unlock(&fibril_futex);
    124         tls_free(fibril->tcb);
    125         free(fibril);
     125
     126        if (fibril->is_freeable) {
     127                tls_free(fibril->tcb);
     128                free(fibril);
     129        }
    126130}
    127131
     
    239243        fibril_t *fibril;
    240244
    241         fibril = fibril_setup();
     245        fibril = fibril_alloc();
    242246        if (fibril == NULL)
    243247                return 0;
     
    248252            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | AS_AREA_GUARD |
    249253            AS_AREA_LATE_RESERVE, AS_AREA_UNPAGED);
    250         if (fibril->stack == (void *) -1) {
     254        if (fibril->stack == AS_MAP_FAILED) {
    251255                fibril_teardown(fibril, false);
    252256                return 0;
     
    324328fibril_t *fibril_self(void)
    325329{
    326         return __tcb_get()->fibril_data;
     330        assert(__tcb_is_set());
     331        tcb_t *tcb = __tcb_get();
     332        assert(tcb->fibril_data);
     333        return tcb->fibril_data;
    327334}
    328335
  • uspace/lib/c/generic/io/kio.c

    r0b05082 r40abf56  
    5656errno_t kio_write(const void *buf, size_t size, size_t *nwritten)
    5757{
    58         futex_lock(&kio_buffer.futex);
     58        /* Using down/up instead of lock/unlock so we can print very early. */
     59        futex_down(&kio_buffer.futex);
    5960
    6061        const char *s = buf;
     
    8283        }
    8384
    84         futex_unlock(&kio_buffer.futex);
     85        futex_up(&kio_buffer.futex);
    8586        if (nwritten)
    8687                *nwritten = size;
  • uspace/lib/c/generic/libc.c

    r0b05082 r40abf56  
    6363progsymbols_t __progsymbols;
    6464
    65 static bool env_setup = false;
     65static bool env_setup;
     66static fibril_t main_fibril;
    6667
    6768void __libc_main(void *pcb_ptr)
    6869{
     70        assert(!__tcb_is_set());
     71
     72        __pcb = (pcb_t *) pcb_ptr;
     73
     74        if (__pcb) {
     75                main_fibril.tcb = __pcb->tcb;
     76        } else {
     77                /*
     78                 * Loaded by kernel, not the loader.
     79                 * Kernel only supports loading fully static binaries,
     80                 * so we can do basic initialization without worrying about
     81                 * dynamic libraries.
     82                 */
     83
     84                main_fibril.tcb = tls_make_initial(__progsymbols.elfstart);
     85        }
     86
     87        assert(main_fibril.tcb);
     88
     89        /* Initialize the fibril. */
     90        main_fibril.tcb->fibril_data = &main_fibril;
     91        __tcb_set(main_fibril.tcb);
     92        fibril_setup(&main_fibril);
     93
    6994        /* Initialize user task run-time environment */
    7095        __malloc_init();
    71 
    72         /* Save the PCB pointer */
    73         __pcb = (pcb_t *) pcb_ptr;
    7496
    7597#ifdef CONFIG_RTLD
     
    81103        }
    82104#endif
    83 
    84         fibril_t *fibril = fibril_setup();
    85         if (fibril == NULL)
    86                 abort();
    87 
    88         __tcb_set(fibril->tcb);
    89105
    90106        __async_server_init();
     
    151167                __stdio_done();
    152168                task_retval(status);
    153                 fibril_teardown(__tcb_get()->fibril_data, false);
    154169        }
    155170
  • uspace/lib/c/generic/private/fibril.h

    r0b05082 r40abf56  
    5555        atomic_t futex_locks;
    5656        bool is_writer : 1;
     57        /* In some places, we use fibril structs that can't be freed. */
     58        bool is_freeable : 1;
    5759};
    5860
     
    6466} fibril_switch_type_t;
    6567
    66 extern fibril_t *fibril_setup(void);
     68extern fibril_t *fibril_alloc(void);
     69extern void fibril_setup(fibril_t *);
    6770extern void fibril_teardown(fibril_t *f, bool locked);
    6871extern int fibril_switch(fibril_switch_type_t stype);
  • uspace/lib/c/generic/rtld/module.c

    r0b05082 r40abf56  
    368368         * be correct, "zero" offset (i.e. the total size) must be aligned
    369369         * to the strictest alignment present.
     370         * Note that the padding is actually in front of the TLS data,
     371         * not after it.
    370372         */
    371373        rtld->tls_size = ALIGN_UP(rtld->tls_size, rtld->tls_align);
  • uspace/lib/c/generic/thread.c

    r0b05082 r40abf56  
    5858void __thread_main(uspace_arg_t *uarg)
    5959{
    60         fibril_t *fibril = fibril_setup();
    61         if (fibril == NULL)
    62                 thread_exit(0);
     60        assert(!__tcb_is_set());
     61
     62        fibril_t *fibril = uarg->uspace_thread_arg;
     63        assert(fibril);
    6364
    6465        __tcb_set(fibril->tcb);
    6566
    66         uarg->uspace_thread_function(uarg->uspace_thread_arg);
     67        uarg->uspace_thread_function(fibril->arg);
    6768        /*
    6869         * XXX: we cannot free the userspace stack while running on it
     
    9596    thread_id_t *tid)
    9697{
    97         uspace_arg_t *uarg =
    98             (uspace_arg_t *) malloc(sizeof(uspace_arg_t));
     98        uspace_arg_t *uarg = calloc(1, sizeof(uspace_arg_t));
    9999        if (!uarg)
    100100                return ENOMEM;
     101
     102        fibril_t *fibril = fibril_alloc();
     103        if (!fibril) {
     104                free(uarg);
     105                return ENOMEM;
     106        }
    101107
    102108        size_t stack_size = stack_size_get();
     
    105111            AS_AREA_LATE_RESERVE, AS_AREA_UNPAGED);
    106112        if (stack == AS_MAP_FAILED) {
     113                fibril_teardown(fibril, false);
    107114                free(uarg);
    108115                return ENOMEM;
     
    112119        malloc_enable_multithreaded();
    113120
     121        fibril->arg = arg;
    114122        uarg->uspace_entry = (void *) FADDR(__thread_entry);
    115123        uarg->uspace_stack = stack;
    116124        uarg->uspace_stack_size = stack_size;
    117125        uarg->uspace_thread_function = function;
    118         uarg->uspace_thread_arg = arg;
     126        uarg->uspace_thread_arg = fibril;
    119127        uarg->uspace_uarg = uarg;
    120128
  • 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
  • uspace/lib/c/include/loader/pcb.h

    r0b05082 r40abf56  
    3737#define LIBC_PCB_H_
    3838
     39#include <tls.h>
    3940
    4041typedef void (*entry_point_t)(void);
     
    7677        /** Pointer to dynamic linker state structure (rtld_t). */
    7778        void *rtld_runtime;
     79
     80        /** Thread local storage for the main thread. */
     81        tcb_t *tcb;
    7882} pcb_t;
    7983
  • uspace/lib/c/include/tls.h

    r0b05082 r40abf56  
    6969#define DTV_GN(dtv) (((uintptr_t *)(dtv))[0])
    7070
    71 extern tcb_t *tls_make(void);
     71extern tcb_t *tls_make(const void *);
     72extern tcb_t *tls_make_initial(const void *);
    7273extern tcb_t *tls_alloc_arch(size_t, size_t);
    7374extern void tls_free(tcb_t *);
  • uspace/srv/loader/main.c

    r0b05082 r40abf56  
    6262#include <vfs/inbox.h>
    6363
     64#ifdef CONFIG_RTLD
     65#include <rtld/rtld.h>
     66#endif
     67
    6468#define DPRINTF(...) ((void) 0)
    6569
     
    296300        DPRINTF("Loaded.\n");
    297301
     302#ifdef CONFIG_RTLD
     303        if (prog_info.env) {
     304                pcb.tcb = rtld_tls_make(prog_info.env);
     305        } else {
     306                pcb.tcb = tls_make(prog_info.finfo.base);
     307        }
     308#else
     309        pcb.tcb = tls_make(prog_info.finfo.base);
     310#endif
     311
    298312        elf_set_pcb(&prog_info, &pcb);
    299313
     
    328342        DPRINTF("Reply OK\n");
    329343        async_answer_0(req, EOK);
     344
    330345        DPRINTF("Jump to entry point at %p\n", pcb.entry);
     346
     347        __tcb_reset();
    331348        entry_point_jmp(prog_info.finfo.entry, &pcb);
    332349
Note: See TracChangeset for help on using the changeset viewer.