Ignore:
File:
1 edited

Legend:

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

    r9f2f5ee r76e17d7c  
    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.
     
    5153void mutex_initialize(mutex_t *mtx, mutex_type_t type)
    5254{
    53         *mtx = MUTEX_INITIALIZER(*mtx, type);
    54 }
    55 
    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);
     55        mtx->type = type;
     56        mtx->owner = NULL;
     57        mtx->nesting = 0;
     58        semaphore_initialize(&mtx->sem, 1);
    7159}
    7260
     
    7967bool mutex_locked(mutex_t *mtx)
    8068{
    81         if (!THREAD)
    82                 return mtx->nesting > 0;
     69        errno_t rc = semaphore_trydown(&mtx->sem);
     70        if (rc == EOK) {
     71                semaphore_up(&mtx->sem);
     72        }
     73        return rc != EOK;
     74}
    8375
    84         return _get_owner(mtx) == THREAD;
     76static void mutex_lock_active(mutex_t *mtx)
     77{
     78        assert((mtx->type == MUTEX_ACTIVE) || !THREAD);
     79
     80        const unsigned deadlock_treshold = 100000000;
     81        unsigned int cnt = 0;
     82        bool deadlock_reported = false;
     83
     84        while (semaphore_trydown(&mtx->sem) != EOK) {
     85                if (cnt++ > deadlock_treshold) {
     86                        printf("cpu%u: looping on active mutex %p\n", CPU->id, mtx);
     87                        stack_trace();
     88                        cnt = 0;
     89                        deadlock_reported = true;
     90                }
     91        }
     92
     93        if (deadlock_reported)
     94                printf("cpu%u: not deadlocked\n", CPU->id);
    8595}
    8696
     
    91101void mutex_lock(mutex_t *mtx)
    92102{
    93         if (!THREAD) {
    94                 assert(mtx->type == MUTEX_RECURSIVE || mtx->nesting == 0);
     103        if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) {
     104                assert(THREAD);
    95105                mtx->nesting++;
    96106                return;
    97107        }
    98108
    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++;
     109        if (mtx->type == MUTEX_ACTIVE || !THREAD) {
     110                mutex_lock_active(mtx);
    104111                return;
    105112        }
    106113
    107114        semaphore_down(&mtx->sem);
    108 
    109         _set_owner(mtx, THREAD);
    110         assert(mtx->nesting == 0);
     115        mtx->owner = THREAD;
    111116        mtx->nesting = 1;
    112117}
     
    121126errno_t mutex_lock_timeout(mutex_t *mtx, uint32_t usec)
    122127{
    123         if (!THREAD) {
    124                 assert(mtx->type == MUTEX_RECURSIVE || mtx->nesting == 0);
    125                 mtx->nesting++;
    126                 return EOK;
     128        if (usec != 0) {
     129                assert(mtx->type != MUTEX_ACTIVE);
     130                assert(THREAD);
    127131        }
    128132
    129         if (_get_owner(mtx) == THREAD) {
    130                 assert(mtx->type == MUTEX_RECURSIVE);
    131                 assert(mtx->nesting > 0);
     133        if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) {
     134                assert(THREAD);
    132135                mtx->nesting++;
    133136                return EOK;
     
    135138
    136139        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;
     140        if (rc == EOK) {
     141                mtx->owner = THREAD;
     142                mtx->nesting = 1;
     143        }
     144        return rc;
    144145}
    145146
     
    159160void mutex_unlock(mutex_t *mtx)
    160161{
    161         if (--mtx->nesting > 0) {
    162                 assert(mtx->type == MUTEX_RECURSIVE);
    163                 return;
     162        if (mtx->type == MUTEX_RECURSIVE) {
     163                assert(mtx->owner == THREAD);
     164                if (--mtx->nesting > 0)
     165                        return;
     166                mtx->owner = NULL;
    164167        }
    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 
    174168        semaphore_up(&mtx->sem);
    175169}
Note: See TracChangeset for help on using the changeset viewer.