Changeset f6372be9 in mainline


Ignore:
Timestamp:
2018-06-26T17:34:23Z (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:
b59318e
Parents:
38e3427
git-author:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-06-25 20:50:53)
git-committer:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-06-26 17:34:23)
Message:

Improve the debugging options for futexes.

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • HelenOS.config

    r38e3427 rf6372be9  
    385385! CONFIG_UBSAN_KERNEL (n/y)
    386386
     387% Track owner for futexes in userspace.
     388! CONFIG_DEBUG_FUTEX (y/n)
     389
    387390% Deadlock detection support for spinlocks
    388391! [CONFIG_DEBUG=y&CONFIG_SMP=y] CONFIG_DEBUG_SPINLOCK (y/n)
  • uspace/lib/c/generic/fibril.c

    r38e3427 rf6372be9  
    150150        case FIBRIL_FROM_DEAD:
    151151                /* Make sure the async_futex is held. */
    152                 assert((atomic_signed_t) async_futex.val.count <= 0);
     152                futex_assert_is_locked(&async_futex);
    153153
    154154                /* If we are going to manager and none exists, create it */
     
    162162                    fibril_t, link);
    163163
     164                /* Bookkeeping. */
     165                futex_give_to(&async_futex, dstf);
     166
    164167                if (stype == FIBRIL_FROM_DEAD)
    165168                        dstf->clean_after_me = srcf;
     
    167170        case FIBRIL_PREEMPT:
    168171        case FIBRIL_FROM_MANAGER:
     172                futex_assert_is_not_locked(&async_futex);
     173
    169174                if (list_empty(&ready_list)) {
    170175                        futex_unlock(&fibril_futex);
     
    196201                break;
    197202        }
     203
     204        /* Bookkeeping. */
     205        futex_give_to(&fibril_futex, dstf);
    198206
    199207        /* Swap to the next fibril. */
  • uspace/lib/c/generic/futex.c

    r38e3427 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
     59
     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}
     69
     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}
     79
     80void __futex_lock(futex_t *futex, const char *name)
     81{
     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         */
     86
     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);
     123        }
     124
     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);
     138}
     139
     140#endif
     141
    49142/** @}
    50143 */
  • uspace/lib/c/include/futex.h

    r38e3427 rf6372be9  
    3939#include <errno.h>
    4040#include <libc.h>
     41#include <time.h>
    4142
    4243typedef struct futex {
    4344        atomic_t val;
     45#ifdef CONFIG_DEBUG_FUTEX
     46        _Atomic void *owner;
     47#endif
    4448} futex_t;
    4549
    4650extern void futex_initialize(futex_t *futex, int value);
     51
     52#ifdef CONFIG_DEBUG_FUTEX
     53
     54#define FUTEX_INITIALIZE(val) {{ (val) }, NULL }
     55#define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
     56
     57void __futex_assert_is_locked(futex_t *, const char *);
     58void __futex_assert_is_not_locked(futex_t *, const char *);
     59void __futex_lock(futex_t *, const char *);
     60void __futex_unlock(futex_t *, const char *);
     61bool __futex_trylock(futex_t *, const char *);
     62void __futex_give_to(futex_t *, void *, const char *);
     63
     64#define futex_lock(futex) __futex_lock((futex), #futex)
     65#define futex_unlock(futex) __futex_unlock((futex), #futex)
     66#define futex_trylock(futex) __futex_trylock((futex), #futex)
     67
     68#define futex_give_to(futex, new_owner) __futex_give_to((futex), (new_owner), #futex)
     69#define futex_assert_is_locked(futex) __futex_assert_is_locked((futex), #futex)
     70#define futex_assert_is_not_locked(futex) __futex_assert_is_not_locked((futex), #futex)
     71
     72#else
    4773
    4874#define FUTEX_INITIALIZE(val) {{ (val) }}
     
    5278#define futex_trylock(fut)  futex_trydown((fut))
    5379#define futex_unlock(fut)   (void) futex_up((fut))
     80
     81#define futex_give_to(fut, owner) ((void)0)
     82#define futex_assert_is_locked(fut) assert((atomic_signed_t) (fut)->val.count <= 0)
     83#define futex_assert_is_not_locked(fut) ((void)0)
     84
     85#endif
    5486
    5587/** Try to down the futex.
Note: See TracChangeset for help on using the changeset viewer.