Changeset 88cbc66 in mainline for uspace/lib/posix/src/pthread/keys.c


Ignore:
Timestamp:
2025-03-08T16:41:12Z (29 hours ago)
Author:
GitHub <noreply@…>
Parents:
797ab95 (diff), af28af6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Matěj Volf <mat.volfik@…> (2025-03-08 16:41:12)
git-committer:
GitHub <noreply@…> (2025-03-08 16:41:12)
Message:

Merge af28af66b2f75b653b814d95c7e3b93389a559e6 into 797ab957fc37b27462c54f0c3a7520af8a33e233

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.