Changes in / [797ab95:88cbc66] in mainline


Ignore:
Location:
uspace/lib
Files:
2 added
10 edited

Legend:

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

    r797ab95 r88cbc66  
    8181                main_fibril.tcb = tls_make_initial(__progsymbols.elfstart);
    8282        }
     83        main_fibril.is_freeable = false;
    8384
    8485        assert(main_fibril.tcb);
     
    172173void __libc_exit(int status)
    173174{
     175        fibril_run_exit_hooks(&main_fibril);
     176
    174177        /*
    175178         * GCC extension __attribute__((destructor)),
  • uspace/lib/c/generic/private/fibril.h

    r797ab95 r88cbc66  
    7070        fibril_owner_info_t *waits_for;
    7171        fibril_event_t *sleep_event;
     72
     73        list_t exit_hooks;
    7274};
     75
     76typedef struct {
     77        link_t link;
     78        void (*func)(void);
     79} fibril_hook_t;
    7380
    7481extern fibril_t *fibril_alloc(void);
     
    8693extern errno_t fibril_ipc_wait(ipc_call_t *, const struct timespec *);
    8794extern void fibril_ipc_poke(void);
     95
     96extern void fibril_run_exit_hooks(fibril_t *);
    8897
    8998/**
  • uspace/lib/c/generic/rtld/symbol.c

    r797ab95 r88cbc66  
    6565static elf_symbol_t *def_find_in_module(const char *name, module_t *m)
    6666{
     67        if (m->dyn.hash == NULL) {
     68                /* No hash table */
     69                return NULL;
     70        }
     71
    6772        elf_symbol_t *sym_table;
    6873        elf_symbol_t *s, *sym;
  • uspace/lib/c/generic/thread/fibril.c

    r797ab95 r88cbc66  
    185185void fibril_setup(fibril_t *f)
    186186{
     187        list_initialize(&f->exit_hooks);
    187188        futex_lock(&fibril_futex);
    188189        list_append(&f->all_link, &fibril_list);
     
    845846}
    846847
     848void fibril_run_exit_hooks(fibril_t *f)
     849{
     850        list_foreach_safe(f->exit_hooks, cur, _next) {
     851                fibril_hook_t *hook = list_get_instance(cur, fibril_hook_t, link);
     852                list_remove(cur);
     853                hook->func();
     854                free(hook);
     855        }
     856}
     857
    847858/**
    848859 * Exit a fibril. Never returns.
     
    854865        // TODO: implement fibril_join() and remember retval
    855866        (void) retval;
     867
     868        fibril_run_exit_hooks(fibril_self());
    856869
    857870        fibril_t *f = _ready_list_pop_nonblocking(false);
     
    918931}
    919932
     933errno_t fibril_add_exit_hook(void (*hook)(void))
     934{
     935        fibril_hook_t *h = malloc(sizeof(fibril_hook_t));
     936        if (!h)
     937                return ENOMEM;
     938
     939        DPRINTF("adding exit hook: function %p (fibril_hook_t structure at %p)\n", hook, h);
     940
     941        h->func = hook;
     942        list_append(&h->link, &fibril_self()->exit_hooks);
     943        return EOK;
     944}
     945
    920946errno_t fibril_ipc_wait(ipc_call_t *call, const struct timespec *expires)
    921947{
  • uspace/lib/c/include/fibril.h

    r797ab95 r88cbc66  
    7474extern __noreturn void fibril_exit(long);
    7575
     76/** Add a function to be called after fibril exits, just before it is destroyed */
     77extern errno_t fibril_add_exit_hook(void (*)(void));
     78
    7679__HELENOS_DECLS_END;
    7780
  • uspace/lib/c/meson.build

    r797ab95 r88cbc66  
    177177        'test/double_to_str.c',
    178178        'test/fibril/timer.c',
     179        'test/fibril/exit_hook.c',
    179180        'test/getopt.c',
    180181        'test/gsort.c',
  • uspace/lib/c/test/main.c

    r797ab95 r88cbc66  
    3838PCUT_IMPORT(double_to_str);
    3939PCUT_IMPORT(fibril_timer);
     40PCUT_IMPORT(fibril_exit_hook);
    4041PCUT_IMPORT(getopt);
    4142PCUT_IMPORT(gsort);
  • uspace/lib/posix/meson.build

    r797ab95 r88cbc66  
    6161        'test/stdlib.c',
    6262        'test/unistd.c',
     63        'test/pthread/keys.c',
    6364)
    6465
  • uspace/lib/posix/src/pthread/keys.c

    r797ab95 r88cbc66  
    3636#include <pthread.h>
    3737#include <errno.h>
     38#include <fibril.h>
     39#include <stdatomic.h>
    3840#include "../internal/common.h"
     41
     42#define DPRINTF(format, ...) ((void) 0)
     43
     44static fibril_local bool fibril_initialized = false;
     45static atomic_ushort next_key = 1; // skip the key 'zero'
     46
     47/*
     48 * For now, we just support maximum of 100 keys. This can be improved
     49 * in the future by implementing a dynamically growing array with
     50 * reallocations, but that will require more synchronization.
     51 */
     52#define PTHREAD_KEYS_MAX 100
     53static void (*destructors[PTHREAD_KEYS_MAX])(void *);
     54
     55static fibril_local void *key_data[PTHREAD_KEYS_MAX];
    3956
    4057void *pthread_getspecific(pthread_key_t key)
    4158{
    42         not_implemented();
    43         return NULL;
     59        // initialization is done in setspecific -> if not initialized, nothing was set yet
     60        if (!fibril_initialized)
     61                return NULL;
     62
     63        assert(key < PTHREAD_KEYS_MAX);
     64        assert(key < next_key);
     65        assert(key > 0);
     66
     67        return key_data[key];
     68}
     69
     70static void pthread_key_on_fibril_exit(void)
     71{
     72        if (!fibril_initialized)
     73                return;
     74
     75        for (unsigned i = 0; i < PTHREAD_KEYS_MAX; i++) {
     76                /*
     77                 * Note that this doesn't cause a race with pthread_key_create:
     78                 * if key `i` has not been assigned yet (it could be just being
     79                 * created), key_data[i] has never been assigned, therefore it
     80                 * is NULL, and the destructor is not checked at all.
     81                 */
     82                if (key_data[i] != NULL && destructors[i] != NULL)
     83                        destructors[i](key_data[i]);
     84        }
    4485}
    4586
    4687int pthread_setspecific(pthread_key_t key, const void *data)
    4788{
    48         not_implemented();
    49         return ENOTSUP;
     89        if (!fibril_initialized) {
     90                DPRINTF("initializing pthread keys\n");
     91                errno_t res = fibril_add_exit_hook(pthread_key_on_fibril_exit);
     92                if (res != EOK)
     93                        return res;
     94
     95                for (unsigned i = 0; i < PTHREAD_KEYS_MAX; i++) {
     96                        key_data[i] = NULL;
     97                }
     98                fibril_initialized = true;
     99        }
     100        assert(key < PTHREAD_KEYS_MAX);
     101        assert(key < next_key);
     102        assert(key > 0);
     103
     104        key_data[key] = (void *) data;
     105        return EOK;
    50106}
    51107
    52108int pthread_key_delete(pthread_key_t key)
    53109{
    54         not_implemented();
    55         return ENOTSUP;
     110        /*
     111         * FIXME: this can cause a data race if another fibrill concurrently
     112         * runs on_fibril_exit. The obvious solution is to add a rwlock on
     113         * the destructors array, which will be needed anyway if we want to
     114         * support unlimited number of keys.
     115         */
     116        destructors[key] = NULL;
     117        key_data[key] = NULL;
     118
     119        // TODO: the key could also be reused
     120        return EOK;
    56121}
    57122
    58123int pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
    59124{
    60         not_implemented();
    61         return ENOTSUP;
     125        unsigned short k = atomic_fetch_add(&next_key, 1);
     126        if (k >= PTHREAD_KEYS_MAX) {
     127                atomic_store(&next_key, PTHREAD_KEYS_MAX + 1);
     128                return ELIMIT;
     129        }
     130
     131        destructors[k] = destructor;
     132        *key = k;
     133        return EOK;
    62134}
    63135
  • uspace/lib/posix/test/main.c

    r797ab95 r88cbc66  
    3434PCUT_IMPORT(stdlib);
    3535PCUT_IMPORT(unistd);
     36PCUT_IMPORT(pthread_keys);
    3637
    3738PCUT_MAIN();
Note: See TracChangeset for help on using the changeset viewer.