Ignore:
File:
1 edited

Legend:

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

    ra35b458 rf6372be9  
    3434
    3535#include <futex.h>
     36
     37#include <assert.h>
    3638#include <atomic.h>
     39#include <fibril.h>
     40#include <io/kio.h>
     41
     42#include "private/fibril.h"
     43
     44//#define DPRINTF(...) kio_printf(__VA_ARGS__)
     45#define DPRINTF(...) ((void)0)
    3746
    3847/** Initialize futex counter.
     
    4756}
    4857
     58#ifdef CONFIG_DEBUG_FUTEX
    4959
    50 #ifdef FUTEX_UPGRADABLE
     60void __futex_assert_is_locked(futex_t *futex, const char *name)
     61{
     62        void *owner = __atomic_load_n(&futex->owner, __ATOMIC_RELAXED);
     63        fibril_t *self = (fibril_t *) fibril_get_id();
     64        if (owner != self) {
     65                DPRINTF("Assertion failed: %s (%p) is not locked by fibril %p (instead locked by fibril %p).\n", name, futex, self, owner);
     66        }
     67        assert(owner == self);
     68}
    5169
    52 int _upgrade_futexes = 0;
    53 static futex_t upg_and_wait_futex = FUTEX_INITIALIZER;
     70void __futex_assert_is_not_locked(futex_t *futex, const char *name)
     71{
     72        void *owner = __atomic_load_n(&futex->owner, __ATOMIC_RELAXED);
     73        fibril_t *self = (fibril_t *) fibril_get_id();
     74        if (owner == self) {
     75                DPRINTF("Assertion failed: %s (%p) is already locked by fibril %p.\n", name, futex, self);
     76        }
     77        assert(owner != self);
     78}
    5479
    55 void futex_upgrade_all_and_wait(void)
     80void __futex_lock(futex_t *futex, const char *name)
    5681{
    57         futex_down(&upg_and_wait_futex);
     82        /* We use relaxed atomics to avoid violating C11 memory model.
     83         * They should compile to regular load/stores, but simple assignments
     84         * would be UB by definition.
     85         */
    5886
    59         if (!_upgrade_futexes) {
    60                 rcu_assign(_upgrade_futexes, 1);
    61                 _rcu_synchronize(BM_BLOCK_THREAD);
     87        fibril_t *self = (fibril_t *) fibril_get_id();
     88        DPRINTF("Locking futex %s (%p) by fibril %p.\n", name, futex, self);
     89        __futex_assert_is_not_locked(futex, name);
     90        futex_down(futex);
     91
     92        void *prev_owner = __atomic_exchange_n(&futex->owner, self, __ATOMIC_RELAXED);
     93        assert(prev_owner == NULL);
     94
     95        atomic_inc(&self->futex_locks);
     96}
     97
     98void __futex_unlock(futex_t *futex, const char *name)
     99{
     100        fibril_t *self = (fibril_t *) fibril_get_id();
     101        DPRINTF("Unlocking futex %s (%p) by fibril %p.\n", name, futex, self);
     102        __futex_assert_is_locked(futex, name);
     103        __atomic_store_n(&futex->owner, NULL, __ATOMIC_RELAXED);
     104        atomic_dec(&self->futex_locks);
     105        futex_up(futex);
     106}
     107
     108bool __futex_trylock(futex_t *futex, const char *name)
     109{
     110        fibril_t *self = (fibril_t *) fibril_get_id();
     111        bool success = futex_trydown(futex);
     112        if (success) {
     113                void *owner = __atomic_load_n(&futex->owner, __ATOMIC_RELAXED);
     114                assert(owner == NULL);
     115
     116                __atomic_store_n(&futex->owner, self, __ATOMIC_RELAXED);
     117
     118                atomic_inc(&self->futex_locks);
     119
     120                DPRINTF("Trylock on futex %s (%p) by fibril %p succeeded.\n", name, futex, self);
     121        } else {
     122                DPRINTF("Trylock on futex %s (%p) by fibril %p failed.\n", name, futex, self);
    62123        }
    63124
    64         futex_up(&upg_and_wait_futex);
     125        return success;
     126}
     127
     128void __futex_give_to(futex_t *futex, void *new_owner, const char *name)
     129{
     130        fibril_t *self = fibril_self();
     131        fibril_t *no = new_owner;
     132        DPRINTF("Passing futex %s (%p) from fibril %p to fibril %p.\n", name, futex, self, no);
     133
     134        __futex_assert_is_locked(futex, name);
     135        atomic_dec(&self->futex_locks);
     136        atomic_inc(&no->futex_locks);
     137        __atomic_store_n(&futex->owner, new_owner, __ATOMIC_RELAXED);
    65138}
    66139
Note: See TracChangeset for help on using the changeset viewer.