Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/synch/mutex.c

    r9f2f5ee r597fa24  
    11/*
    22 * Copyright (c) 2001-2004 Jakub Jermar
    3  * Copyright (c) 2025 Jiří Zárevúcky
     3 * Copyright (c) 2023 Jiří Zárevúcky
    44 * All rights reserved.
    55 *
     
    3939#include <assert.h>
    4040#include <errno.h>
    41 #include <proc/thread.h>
    42 #include <stdatomic.h>
    4341#include <synch/mutex.h>
    4442#include <synch/semaphore.h>
     43#include <arch.h>
     44#include <stacktrace.h>
     45#include <cpu.h>
     46#include <proc/thread.h>
    4547
    4648/** Initialize mutex.
     
    5456}
    5557
    56 /** A race in mtx->owner access is unavoidable, so we have to make
    57  * access to it formally atomic. These are convenience functions to
    58  * read/write the variable without memory barriers, since we don't need
    59  * them and C11 atomics default to the strongest possible memory ordering
    60  * by default, which is utterly ridiculous.
    61  */
    62 static inline thread_t *_get_owner(mutex_t *mtx)
    63 {
    64         return atomic_load_explicit(&mtx->owner, memory_order_relaxed);
    65 }
    66 
    67 /** Counterpart to _get_owner(). */
    68 static inline void _set_owner(mutex_t *mtx, thread_t *owner)
    69 {
    70         atomic_store_explicit(&mtx->owner, owner, memory_order_relaxed);
    71 }
    72 
    7358/** Find out whether the mutex is currently locked.
    7459 *
     
    7964bool mutex_locked(mutex_t *mtx)
    8065{
    81         if (!THREAD)
    82                 return mtx->nesting > 0;
     66        errno_t rc = semaphore_trydown(&mtx->sem);
     67        if (rc == EOK) {
     68                semaphore_up(&mtx->sem);
     69        }
     70        return rc != EOK;
     71}
    8372
    84         return _get_owner(mtx) == THREAD;
     73static void mutex_lock_active(mutex_t *mtx)
     74{
     75        assert((mtx->type == MUTEX_ACTIVE) || !THREAD);
     76
     77        const unsigned deadlock_treshold = 100000000;
     78        unsigned int cnt = 0;
     79        bool deadlock_reported = false;
     80
     81        while (semaphore_trydown(&mtx->sem) != EOK) {
     82                if (cnt++ > deadlock_treshold) {
     83                        printf("cpu%u: looping on active mutex %p\n", CPU->id, mtx);
     84                        stack_trace();
     85                        cnt = 0;
     86                        deadlock_reported = true;
     87                }
     88        }
     89
     90        if (deadlock_reported)
     91                printf("cpu%u: not deadlocked\n", CPU->id);
    8592}
    8693
     
    9198void mutex_lock(mutex_t *mtx)
    9299{
    93         if (!THREAD) {
    94                 assert(mtx->type == MUTEX_RECURSIVE || mtx->nesting == 0);
     100        if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) {
     101                assert(THREAD);
    95102                mtx->nesting++;
    96103                return;
    97104        }
    98105
    99         if (_get_owner(mtx) == THREAD) {
    100                 /* This will also detect nested locks on a non-recursive mutex. */
    101                 assert(mtx->type == MUTEX_RECURSIVE);
    102                 assert(mtx->nesting > 0);
    103                 mtx->nesting++;
     106        if (mtx->type == MUTEX_ACTIVE || !THREAD) {
     107                mutex_lock_active(mtx);
    104108                return;
    105109        }
    106110
    107111        semaphore_down(&mtx->sem);
    108 
    109         _set_owner(mtx, THREAD);
    110         assert(mtx->nesting == 0);
     112        mtx->owner = THREAD;
    111113        mtx->nesting = 1;
    112114}
     
    121123errno_t mutex_lock_timeout(mutex_t *mtx, uint32_t usec)
    122124{
    123         if (!THREAD) {
    124                 assert(mtx->type == MUTEX_RECURSIVE || mtx->nesting == 0);
    125                 mtx->nesting++;
    126                 return EOK;
     125        if (usec != 0) {
     126                assert(mtx->type != MUTEX_ACTIVE);
     127                assert(THREAD);
    127128        }
    128129
    129         if (_get_owner(mtx) == THREAD) {
    130                 assert(mtx->type == MUTEX_RECURSIVE);
    131                 assert(mtx->nesting > 0);
     130        if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) {
     131                assert(THREAD);
    132132                mtx->nesting++;
    133133                return EOK;
     
    135135
    136136        errno_t rc = semaphore_down_timeout(&mtx->sem, usec);
    137         if (rc != EOK)
    138                 return rc;
    139 
    140         _set_owner(mtx, THREAD);
    141         assert(mtx->nesting == 0);
    142         mtx->nesting = 1;
    143         return EOK;
     137        if (rc == EOK) {
     138                mtx->owner = THREAD;
     139                mtx->nesting = 1;
     140        }
     141        return rc;
    144142}
    145143
     
    159157void mutex_unlock(mutex_t *mtx)
    160158{
    161         if (--mtx->nesting > 0) {
    162                 assert(mtx->type == MUTEX_RECURSIVE);
    163                 return;
     159        if (mtx->type == MUTEX_RECURSIVE) {
     160                assert(mtx->owner == THREAD);
     161                if (--mtx->nesting > 0)
     162                        return;
     163                mtx->owner = NULL;
    164164        }
    165 
    166         assert(mtx->nesting == 0);
    167 
    168         if (!THREAD)
    169                 return;
    170 
    171         assert(_get_owner(mtx) == THREAD);
    172         _set_owner(mtx, NULL);
    173 
    174165        semaphore_up(&mtx->sem);
    175166}
Note: See TracChangeset for help on using the changeset viewer.