Changeset 0b47781 in mainline


Ignore:
Timestamp:
2025-04-10T17:23:30Z (4 days ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
master
Children:
c626117
Parents:
a78b0a0
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2025-04-10 16:29:50)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2025-04-10 17:23:30)
Message:

Extend kernel condvar_t to work with spinlocks

MUTEX_ACTIVE is a poor copy of the spinlock, made solely to allow
using condvars with it. Solve that issue the other way around,
by making condvar_wait() generic, so that we can get rid of that
hack.

Location:
kernel/generic
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/synch/condvar.h

    ra78b0a0 r0b47781  
    11/*
    22 * Copyright (c) 2001-2004 Jakub Jermar
     3 * Copyright (c) 2025 Jiří Zárevúcky
    34 * All rights reserved.
    45 *
     
    5354        condvar_t name = CONDVAR_INITIALIZER(name)
    5455
    55 #ifdef CONFIG_SMP
    56 #define _condvar_wait_timeout_spinlock(cv, lock, usec, flags) \
    57         _condvar_wait_timeout_spinlock_impl((cv), (lock), (usec), (flags))
    58 #else
    59 #define _condvar_wait_timeout_spinlock(cv, lock, usec, flags) \
    60         _condvar_wait_timeout_spinlock_impl((cv), NULL, (usec), (flags))
    61 #endif
    62 
    6356extern void condvar_initialize(condvar_t *cv);
    6457extern void condvar_signal(condvar_t *cv);
    6558extern void condvar_broadcast(condvar_t *cv);
    6659
    67 extern errno_t condvar_wait(condvar_t *cv, mutex_t *mtx);
    68 extern errno_t condvar_wait_timeout(condvar_t *cv, mutex_t *mtx, uint32_t usec);
     60extern errno_t __condvar_wait_mutex(condvar_t *cv, mutex_t *mtx);
     61extern errno_t __condvar_wait_spinlock(condvar_t *cv, spinlock_t *mtx);
     62extern errno_t __condvar_wait_irq_spinlock(condvar_t *cv, irq_spinlock_t *mtx);
     63extern errno_t __condvar_wait_timeout_mutex(condvar_t *cv, mutex_t *mtx, uint32_t usec);
     64extern errno_t __condvar_wait_timeout_spinlock(condvar_t *cv, spinlock_t *mtx, uint32_t usec);
     65extern errno_t __condvar_wait_timeout_irq_spinlock(condvar_t *cv, irq_spinlock_t *mtx, uint32_t usec);
    6966
    70 extern errno_t _condvar_wait_timeout_spinlock_impl(condvar_t *cv, spinlock_t *lock,
    71     uint32_t usec, int flags);
    72 extern errno_t _condvar_wait_timeout_irq_spinlock(condvar_t *cv,
    73     irq_spinlock_t *irq_lock, uint32_t usec, int flags);
     67#define condvar_wait(cv, mtx) (_Generic((mtx), \
     68        mutex_t *: __condvar_wait_mutex, \
     69        spinlock_t *: __condvar_wait_spinlock, \
     70        irq_spinlock_t *: __condvar_wait_irq_spinlock \
     71)(cv, mtx))
     72
     73#define condvar_wait_timeout(cv, mtx, usec) (_Generic((mtx), \
     74        mutex_t *: __condvar_wait_timeout_mutex, \
     75        spinlock_t *: __condvar_wait_timeout_spinlock, \
     76        irq_spinlock_t *: __condvar_wait_timeout_irq_spinlock \
     77)(cv, mtx))
    7478
    7579#endif
  • kernel/generic/src/synch/condvar.c

    ra78b0a0 r0b47781  
    7979 * @return              See comment for waitq_sleep_timeout().
    8080 */
    81 errno_t condvar_wait_timeout(condvar_t *cv, mutex_t *mtx, uint32_t usec)
     81errno_t __condvar_wait_timeout_mutex(condvar_t *cv, mutex_t *mtx, uint32_t usec)
    8282{
    8383        wait_guard_t guard = waitq_sleep_prepare(&cv->wq);
     
    9292}
    9393
    94 errno_t condvar_wait(condvar_t *cv, mutex_t *mtx)
     94errno_t __condvar_wait_mutex(condvar_t *cv, mutex_t *mtx)
    9595{
    9696        wait_guard_t guard = waitq_sleep_prepare(&cv->wq);
     
    105105}
    106106
    107 /** Wait for the condition to become true with a locked spinlock.
    108  *
    109  * The function is not aware of irq_spinlock. Therefore do not even
    110  * try passing irq_spinlock_t to it. Use _condvar_wait_timeout_irq_spinlock()
    111  * instead.
    112  *
    113  * @param cv            Condition variable.
    114  * @param lock          Locked spinlock.
    115  * @param usec          Timeout value in microseconds.
    116  * @param flags         Select mode of operation.
    117  *
    118  * For exact description of meaning of possible combinations of usec and flags,
    119  * see comment for waitq_sleep_timeout().  Note that when
    120  * SYNCH_FLAGS_NON_BLOCKING is specified here, EAGAIN is always
    121  * returned.
    122  *
    123  * @return See comment for waitq_sleep_timeout().
    124  */
    125 errno_t _condvar_wait_timeout_spinlock_impl(condvar_t *cv, spinlock_t *lock,
    126     uint32_t usec, int flags)
     107/** Same as __condvar_wait_timeout_mutex(), except for spinlock_t. */
     108errno_t __condvar_wait_timeout_spinlock(condvar_t *cv, spinlock_t *lock,
     109    uint32_t usec)
    127110{
    128111        wait_guard_t guard = waitq_sleep_prepare(&cv->wq);
     
    131114        spinlock_unlock(lock);
    132115
    133         errno_t rc = waitq_sleep_timeout_unsafe(&cv->wq, usec, flags, guard);
     116        errno_t rc = waitq_sleep_timeout_unsafe(&cv->wq, usec,
     117            SYNCH_FLAGS_NON_BLOCKING, guard);
    134118
    135119        spinlock_lock(lock);
     
    137121}
    138122
    139 /** Wait for the condition to become true with a locked irq spinlock.
    140  *
    141  * @param cv            Condition variable.
    142  * @param lock          Locked irq spinlock.
    143  * @param usec          Timeout value in microseconds.
    144  * @param flags         Select mode of operation.
    145  *
    146  * For exact description of meaning of possible combinations of usec and flags,
    147  * see comment for waitq_sleep_timeout().  Note that when
    148  * SYNCH_FLAGS_NON_BLOCKING is specified here, EAGAIN is always
    149  * returned.
    150  *
    151  * @return See comment for waitq_sleep_timeout().
    152  */
    153 errno_t _condvar_wait_timeout_irq_spinlock(condvar_t *cv, irq_spinlock_t *irq_lock,
    154     uint32_t usec, int flags)
     123errno_t __condvar_wait_spinlock(condvar_t *cv, spinlock_t *mtx)
     124{
     125        wait_guard_t guard = waitq_sleep_prepare(&cv->wq);
     126
     127        /* Unlock only after the waitq is locked so we don't miss a wakeup. */
     128        spinlock_unlock(mtx);
     129
     130        errno_t rc = waitq_sleep_unsafe(&cv->wq, guard);
     131
     132        spinlock_lock(mtx);
     133        return rc;
     134}
     135
     136/** Same as __condvar_wait_timeout_mutex(), except for irq_spinlock_t. */
     137errno_t __condvar_wait_timeout_irq_spinlock(condvar_t *cv,
     138    irq_spinlock_t *irq_lock, uint32_t usec)
    155139{
    156140        errno_t rc;
     
    171155         * running) and there is no danger of a deadlock.
    172156         */
    173         rc = _condvar_wait_timeout_spinlock(cv, &irq_lock->lock, usec, flags);
     157        rc = __condvar_wait_timeout_spinlock(cv, &irq_lock->lock, usec);
     158
     159        irq_lock->guard = guard;
     160        irq_lock->ipl = ipl;
     161
     162        return rc;
     163}
     164
     165/** Same as __condvar_wait_mutex(), except for irq_spinlock_t. */
     166errno_t __condvar_wait_irq_spinlock(condvar_t *cv, irq_spinlock_t *irq_lock)
     167{
     168        errno_t rc;
     169        /* Save spinlock's state so we can restore it correctly later on. */
     170        ipl_t ipl = irq_lock->ipl;
     171        bool guard = irq_lock->guard;
     172
     173        irq_lock->guard = false;
     174
     175        rc = __condvar_wait_spinlock(cv, &irq_lock->lock);
    174176
    175177        irq_lock->guard = guard;
Note: See TracChangeset for help on using the changeset viewer.