1*51f49692SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause 2*51f49692SMarouene Boubakri /* 3*51f49692SMarouene Boubakri * Copyright (c) 2015-2017, Linaro Limited 4*51f49692SMarouene Boubakri */ 5*51f49692SMarouene Boubakri 6*51f49692SMarouene Boubakri #include <kernel/mutex.h> 7*51f49692SMarouene Boubakri #include <kernel/panic.h> 8*51f49692SMarouene Boubakri #include <kernel/refcount.h> 9*51f49692SMarouene Boubakri #include <kernel/spinlock.h> 10*51f49692SMarouene Boubakri #include <kernel/thread.h> 11*51f49692SMarouene Boubakri #include <trace.h> 12*51f49692SMarouene Boubakri 13*51f49692SMarouene Boubakri #include "mutex_lockdep.h" 14*51f49692SMarouene Boubakri 15*51f49692SMarouene Boubakri void mutex_init(struct mutex *m) 16*51f49692SMarouene Boubakri { 17*51f49692SMarouene Boubakri *m = (struct mutex)MUTEX_INITIALIZER; 18*51f49692SMarouene Boubakri } 19*51f49692SMarouene Boubakri 20*51f49692SMarouene Boubakri void mutex_init_recursive(struct recursive_mutex *m) 21*51f49692SMarouene Boubakri { 22*51f49692SMarouene Boubakri *m = (struct recursive_mutex)RECURSIVE_MUTEX_INITIALIZER; 23*51f49692SMarouene Boubakri } 24*51f49692SMarouene Boubakri 25*51f49692SMarouene Boubakri static void __mutex_lock(struct mutex *m, const char *fname, int lineno) 26*51f49692SMarouene Boubakri { 27*51f49692SMarouene Boubakri assert_have_no_spinlock(); 28*51f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 29*51f49692SMarouene Boubakri assert(thread_is_in_normal_mode()); 30*51f49692SMarouene Boubakri 31*51f49692SMarouene Boubakri mutex_lock_check(m); 32*51f49692SMarouene Boubakri 33*51f49692SMarouene Boubakri while (true) { 34*51f49692SMarouene Boubakri uint32_t old_itr_status; 35*51f49692SMarouene Boubakri bool can_lock; 36*51f49692SMarouene Boubakri struct wait_queue_elem wqe; 37*51f49692SMarouene Boubakri 38*51f49692SMarouene Boubakri /* 39*51f49692SMarouene Boubakri * If the mutex is locked we need to initialize the wqe 40*51f49692SMarouene Boubakri * before releasing the spinlock to guarantee that we don't 41*51f49692SMarouene Boubakri * miss the wakeup from mutex_unlock(). 42*51f49692SMarouene Boubakri * 43*51f49692SMarouene Boubakri * If the mutex is unlocked we don't need to use the wqe at 44*51f49692SMarouene Boubakri * all. 45*51f49692SMarouene Boubakri */ 46*51f49692SMarouene Boubakri 47*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock); 48*51f49692SMarouene Boubakri 49*51f49692SMarouene Boubakri can_lock = !m->state; 50*51f49692SMarouene Boubakri if (!can_lock) { 51*51f49692SMarouene Boubakri wq_wait_init(&m->wq, &wqe, false /* wait_read */); 52*51f49692SMarouene Boubakri } else { 53*51f49692SMarouene Boubakri m->state = -1; /* write locked */ 54*51f49692SMarouene Boubakri } 55*51f49692SMarouene Boubakri 56*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status); 57*51f49692SMarouene Boubakri 58*51f49692SMarouene Boubakri if (!can_lock) { 59*51f49692SMarouene Boubakri /* 60*51f49692SMarouene Boubakri * Someone else is holding the lock, wait in normal 61*51f49692SMarouene Boubakri * world for the lock to become available. 62*51f49692SMarouene Boubakri */ 63*51f49692SMarouene Boubakri wq_wait_final(&m->wq, &wqe, m, fname, lineno); 64*51f49692SMarouene Boubakri } else 65*51f49692SMarouene Boubakri return; 66*51f49692SMarouene Boubakri } 67*51f49692SMarouene Boubakri } 68*51f49692SMarouene Boubakri 69*51f49692SMarouene Boubakri static void __mutex_lock_recursive(struct recursive_mutex *m, const char *fname, 70*51f49692SMarouene Boubakri int lineno) 71*51f49692SMarouene Boubakri { 72*51f49692SMarouene Boubakri short int ct = thread_get_id(); 73*51f49692SMarouene Boubakri 74*51f49692SMarouene Boubakri assert_have_no_spinlock(); 75*51f49692SMarouene Boubakri assert(thread_is_in_normal_mode()); 76*51f49692SMarouene Boubakri 77*51f49692SMarouene Boubakri if (atomic_load_short(&m->owner) == ct) { 78*51f49692SMarouene Boubakri if (!refcount_inc(&m->lock_depth)) 79*51f49692SMarouene Boubakri panic(); 80*51f49692SMarouene Boubakri return; 81*51f49692SMarouene Boubakri } 82*51f49692SMarouene Boubakri 83*51f49692SMarouene Boubakri __mutex_lock(&m->m, fname, lineno); 84*51f49692SMarouene Boubakri 85*51f49692SMarouene Boubakri assert(m->owner == THREAD_ID_INVALID); 86*51f49692SMarouene Boubakri atomic_store_short(&m->owner, ct); 87*51f49692SMarouene Boubakri refcount_set(&m->lock_depth, 1); 88*51f49692SMarouene Boubakri } 89*51f49692SMarouene Boubakri 90*51f49692SMarouene Boubakri static void __mutex_unlock(struct mutex *m, const char *fname, int lineno) 91*51f49692SMarouene Boubakri { 92*51f49692SMarouene Boubakri uint32_t old_itr_status; 93*51f49692SMarouene Boubakri 94*51f49692SMarouene Boubakri assert_have_no_spinlock(); 95*51f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 96*51f49692SMarouene Boubakri 97*51f49692SMarouene Boubakri mutex_unlock_check(m); 98*51f49692SMarouene Boubakri 99*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock); 100*51f49692SMarouene Boubakri 101*51f49692SMarouene Boubakri if (!m->state) 102*51f49692SMarouene Boubakri panic(); 103*51f49692SMarouene Boubakri 104*51f49692SMarouene Boubakri m->state = 0; 105*51f49692SMarouene Boubakri 106*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status); 107*51f49692SMarouene Boubakri 108*51f49692SMarouene Boubakri wq_wake_next(&m->wq, m, fname, lineno); 109*51f49692SMarouene Boubakri } 110*51f49692SMarouene Boubakri 111*51f49692SMarouene Boubakri static void __mutex_unlock_recursive(struct recursive_mutex *m, 112*51f49692SMarouene Boubakri const char *fname, int lineno) 113*51f49692SMarouene Boubakri { 114*51f49692SMarouene Boubakri assert_have_no_spinlock(); 115*51f49692SMarouene Boubakri assert(m->owner == thread_get_id()); 116*51f49692SMarouene Boubakri 117*51f49692SMarouene Boubakri if (refcount_dec(&m->lock_depth)) { 118*51f49692SMarouene Boubakri /* 119*51f49692SMarouene Boubakri * Do an atomic store to match the atomic load in 120*51f49692SMarouene Boubakri * __mutex_lock_recursive() 121*51f49692SMarouene Boubakri */ 122*51f49692SMarouene Boubakri atomic_store_short(&m->owner, THREAD_ID_INVALID); 123*51f49692SMarouene Boubakri __mutex_unlock(&m->m, fname, lineno); 124*51f49692SMarouene Boubakri } 125*51f49692SMarouene Boubakri } 126*51f49692SMarouene Boubakri 127*51f49692SMarouene Boubakri static bool __mutex_trylock(struct mutex *m, const char *fname __unused, 128*51f49692SMarouene Boubakri int lineno __unused) 129*51f49692SMarouene Boubakri { 130*51f49692SMarouene Boubakri uint32_t old_itr_status; 131*51f49692SMarouene Boubakri bool can_lock_write; 132*51f49692SMarouene Boubakri 133*51f49692SMarouene Boubakri assert_have_no_spinlock(); 134*51f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 135*51f49692SMarouene Boubakri 136*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock); 137*51f49692SMarouene Boubakri 138*51f49692SMarouene Boubakri can_lock_write = !m->state; 139*51f49692SMarouene Boubakri if (can_lock_write) 140*51f49692SMarouene Boubakri m->state = -1; 141*51f49692SMarouene Boubakri 142*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status); 143*51f49692SMarouene Boubakri 144*51f49692SMarouene Boubakri if (can_lock_write) 145*51f49692SMarouene Boubakri mutex_trylock_check(m); 146*51f49692SMarouene Boubakri 147*51f49692SMarouene Boubakri return can_lock_write; 148*51f49692SMarouene Boubakri } 149*51f49692SMarouene Boubakri 150*51f49692SMarouene Boubakri static void __mutex_read_unlock(struct mutex *m, const char *fname, int lineno) 151*51f49692SMarouene Boubakri { 152*51f49692SMarouene Boubakri uint32_t old_itr_status; 153*51f49692SMarouene Boubakri short new_state; 154*51f49692SMarouene Boubakri 155*51f49692SMarouene Boubakri assert_have_no_spinlock(); 156*51f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 157*51f49692SMarouene Boubakri 158*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock); 159*51f49692SMarouene Boubakri 160*51f49692SMarouene Boubakri if (m->state <= 0) 161*51f49692SMarouene Boubakri panic(); 162*51f49692SMarouene Boubakri m->state--; 163*51f49692SMarouene Boubakri new_state = m->state; 164*51f49692SMarouene Boubakri 165*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status); 166*51f49692SMarouene Boubakri 167*51f49692SMarouene Boubakri /* Wake eventual waiters if the mutex was unlocked */ 168*51f49692SMarouene Boubakri if (!new_state) 169*51f49692SMarouene Boubakri wq_wake_next(&m->wq, m, fname, lineno); 170*51f49692SMarouene Boubakri } 171*51f49692SMarouene Boubakri 172*51f49692SMarouene Boubakri static void __mutex_read_lock(struct mutex *m, const char *fname, int lineno) 173*51f49692SMarouene Boubakri { 174*51f49692SMarouene Boubakri assert_have_no_spinlock(); 175*51f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 176*51f49692SMarouene Boubakri assert(thread_is_in_normal_mode()); 177*51f49692SMarouene Boubakri 178*51f49692SMarouene Boubakri while (true) { 179*51f49692SMarouene Boubakri uint32_t old_itr_status; 180*51f49692SMarouene Boubakri bool can_lock; 181*51f49692SMarouene Boubakri struct wait_queue_elem wqe; 182*51f49692SMarouene Boubakri 183*51f49692SMarouene Boubakri /* 184*51f49692SMarouene Boubakri * If the mutex is locked we need to initialize the wqe 185*51f49692SMarouene Boubakri * before releasing the spinlock to guarantee that we don't 186*51f49692SMarouene Boubakri * miss the wakeup from mutex_unlock(). 187*51f49692SMarouene Boubakri * 188*51f49692SMarouene Boubakri * If the mutex is unlocked we don't need to use the wqe at 189*51f49692SMarouene Boubakri * all. 190*51f49692SMarouene Boubakri */ 191*51f49692SMarouene Boubakri 192*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock); 193*51f49692SMarouene Boubakri 194*51f49692SMarouene Boubakri can_lock = m->state != -1; 195*51f49692SMarouene Boubakri if (!can_lock) { 196*51f49692SMarouene Boubakri wq_wait_init(&m->wq, &wqe, true /* wait_read */); 197*51f49692SMarouene Boubakri } else { 198*51f49692SMarouene Boubakri m->state++; /* read_locked */ 199*51f49692SMarouene Boubakri } 200*51f49692SMarouene Boubakri 201*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status); 202*51f49692SMarouene Boubakri 203*51f49692SMarouene Boubakri if (!can_lock) { 204*51f49692SMarouene Boubakri /* 205*51f49692SMarouene Boubakri * Someone else is holding the lock, wait in normal 206*51f49692SMarouene Boubakri * world for the lock to become available. 207*51f49692SMarouene Boubakri */ 208*51f49692SMarouene Boubakri wq_wait_final(&m->wq, &wqe, m, fname, lineno); 209*51f49692SMarouene Boubakri } else 210*51f49692SMarouene Boubakri return; 211*51f49692SMarouene Boubakri } 212*51f49692SMarouene Boubakri } 213*51f49692SMarouene Boubakri 214*51f49692SMarouene Boubakri static bool __mutex_read_trylock(struct mutex *m, const char *fname __unused, 215*51f49692SMarouene Boubakri int lineno __unused) 216*51f49692SMarouene Boubakri { 217*51f49692SMarouene Boubakri uint32_t old_itr_status; 218*51f49692SMarouene Boubakri bool can_lock; 219*51f49692SMarouene Boubakri 220*51f49692SMarouene Boubakri assert_have_no_spinlock(); 221*51f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 222*51f49692SMarouene Boubakri assert(thread_is_in_normal_mode()); 223*51f49692SMarouene Boubakri 224*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock); 225*51f49692SMarouene Boubakri 226*51f49692SMarouene Boubakri can_lock = m->state != -1; 227*51f49692SMarouene Boubakri if (can_lock) 228*51f49692SMarouene Boubakri m->state++; 229*51f49692SMarouene Boubakri 230*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status); 231*51f49692SMarouene Boubakri 232*51f49692SMarouene Boubakri return can_lock; 233*51f49692SMarouene Boubakri } 234*51f49692SMarouene Boubakri 235*51f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG 236*51f49692SMarouene Boubakri void mutex_unlock_debug(struct mutex *m, const char *fname, int lineno) 237*51f49692SMarouene Boubakri { 238*51f49692SMarouene Boubakri __mutex_unlock(m, fname, lineno); 239*51f49692SMarouene Boubakri } 240*51f49692SMarouene Boubakri 241*51f49692SMarouene Boubakri void mutex_lock_debug(struct mutex *m, const char *fname, int lineno) 242*51f49692SMarouene Boubakri { 243*51f49692SMarouene Boubakri __mutex_lock(m, fname, lineno); 244*51f49692SMarouene Boubakri } 245*51f49692SMarouene Boubakri 246*51f49692SMarouene Boubakri bool mutex_trylock_debug(struct mutex *m, const char *fname, int lineno) 247*51f49692SMarouene Boubakri { 248*51f49692SMarouene Boubakri return __mutex_trylock(m, fname, lineno); 249*51f49692SMarouene Boubakri } 250*51f49692SMarouene Boubakri 251*51f49692SMarouene Boubakri void mutex_read_unlock_debug(struct mutex *m, const char *fname, int lineno) 252*51f49692SMarouene Boubakri { 253*51f49692SMarouene Boubakri __mutex_read_unlock(m, fname, lineno); 254*51f49692SMarouene Boubakri } 255*51f49692SMarouene Boubakri 256*51f49692SMarouene Boubakri void mutex_read_lock_debug(struct mutex *m, const char *fname, int lineno) 257*51f49692SMarouene Boubakri { 258*51f49692SMarouene Boubakri __mutex_read_lock(m, fname, lineno); 259*51f49692SMarouene Boubakri } 260*51f49692SMarouene Boubakri 261*51f49692SMarouene Boubakri bool mutex_read_trylock_debug(struct mutex *m, const char *fname, int lineno) 262*51f49692SMarouene Boubakri { 263*51f49692SMarouene Boubakri return __mutex_read_trylock(m, fname, lineno); 264*51f49692SMarouene Boubakri } 265*51f49692SMarouene Boubakri 266*51f49692SMarouene Boubakri void mutex_unlock_recursive_debug(struct recursive_mutex *m, const char *fname, 267*51f49692SMarouene Boubakri int lineno) 268*51f49692SMarouene Boubakri { 269*51f49692SMarouene Boubakri __mutex_unlock_recursive(m, fname, lineno); 270*51f49692SMarouene Boubakri } 271*51f49692SMarouene Boubakri 272*51f49692SMarouene Boubakri void mutex_lock_recursive_debug(struct recursive_mutex *m, const char *fname, 273*51f49692SMarouene Boubakri int lineno) 274*51f49692SMarouene Boubakri { 275*51f49692SMarouene Boubakri __mutex_lock_recursive(m, fname, lineno); 276*51f49692SMarouene Boubakri } 277*51f49692SMarouene Boubakri #else 278*51f49692SMarouene Boubakri void mutex_unlock(struct mutex *m) 279*51f49692SMarouene Boubakri { 280*51f49692SMarouene Boubakri __mutex_unlock(m, NULL, -1); 281*51f49692SMarouene Boubakri } 282*51f49692SMarouene Boubakri 283*51f49692SMarouene Boubakri void mutex_unlock_recursive(struct recursive_mutex *m) 284*51f49692SMarouene Boubakri { 285*51f49692SMarouene Boubakri __mutex_unlock_recursive(m, NULL, -1); 286*51f49692SMarouene Boubakri } 287*51f49692SMarouene Boubakri 288*51f49692SMarouene Boubakri void mutex_lock(struct mutex *m) 289*51f49692SMarouene Boubakri { 290*51f49692SMarouene Boubakri __mutex_lock(m, NULL, -1); 291*51f49692SMarouene Boubakri } 292*51f49692SMarouene Boubakri 293*51f49692SMarouene Boubakri void mutex_lock_recursive(struct recursive_mutex *m) 294*51f49692SMarouene Boubakri { 295*51f49692SMarouene Boubakri __mutex_lock_recursive(m, NULL, -1); 296*51f49692SMarouene Boubakri } 297*51f49692SMarouene Boubakri 298*51f49692SMarouene Boubakri bool mutex_trylock(struct mutex *m) 299*51f49692SMarouene Boubakri { 300*51f49692SMarouene Boubakri return __mutex_trylock(m, NULL, -1); 301*51f49692SMarouene Boubakri } 302*51f49692SMarouene Boubakri 303*51f49692SMarouene Boubakri void mutex_read_unlock(struct mutex *m) 304*51f49692SMarouene Boubakri { 305*51f49692SMarouene Boubakri __mutex_read_unlock(m, NULL, -1); 306*51f49692SMarouene Boubakri } 307*51f49692SMarouene Boubakri 308*51f49692SMarouene Boubakri void mutex_read_lock(struct mutex *m) 309*51f49692SMarouene Boubakri { 310*51f49692SMarouene Boubakri __mutex_read_lock(m, NULL, -1); 311*51f49692SMarouene Boubakri } 312*51f49692SMarouene Boubakri 313*51f49692SMarouene Boubakri bool mutex_read_trylock(struct mutex *m) 314*51f49692SMarouene Boubakri { 315*51f49692SMarouene Boubakri return __mutex_read_trylock(m, NULL, -1); 316*51f49692SMarouene Boubakri } 317*51f49692SMarouene Boubakri #endif 318*51f49692SMarouene Boubakri 319*51f49692SMarouene Boubakri void mutex_destroy(struct mutex *m) 320*51f49692SMarouene Boubakri { 321*51f49692SMarouene Boubakri /* 322*51f49692SMarouene Boubakri * Caller guarantees that no one will try to take the mutex so 323*51f49692SMarouene Boubakri * there's no need to take the spinlock before accessing it. 324*51f49692SMarouene Boubakri */ 325*51f49692SMarouene Boubakri if (m->state) 326*51f49692SMarouene Boubakri panic(); 327*51f49692SMarouene Boubakri if (!wq_is_empty(&m->wq)) 328*51f49692SMarouene Boubakri panic("waitqueue not empty"); 329*51f49692SMarouene Boubakri mutex_destroy_check(m); 330*51f49692SMarouene Boubakri } 331*51f49692SMarouene Boubakri 332*51f49692SMarouene Boubakri void mutex_destroy_recursive(struct recursive_mutex *m) 333*51f49692SMarouene Boubakri { 334*51f49692SMarouene Boubakri mutex_destroy(&m->m); 335*51f49692SMarouene Boubakri } 336*51f49692SMarouene Boubakri 337*51f49692SMarouene Boubakri unsigned int mutex_get_recursive_lock_depth(struct recursive_mutex *m) 338*51f49692SMarouene Boubakri { 339*51f49692SMarouene Boubakri assert_have_no_spinlock(); 340*51f49692SMarouene Boubakri assert(m->owner == thread_get_id()); 341*51f49692SMarouene Boubakri 342*51f49692SMarouene Boubakri return refcount_val(&m->lock_depth); 343*51f49692SMarouene Boubakri } 344*51f49692SMarouene Boubakri 345*51f49692SMarouene Boubakri void condvar_init(struct condvar *cv) 346*51f49692SMarouene Boubakri { 347*51f49692SMarouene Boubakri *cv = (struct condvar)CONDVAR_INITIALIZER; 348*51f49692SMarouene Boubakri } 349*51f49692SMarouene Boubakri 350*51f49692SMarouene Boubakri void condvar_destroy(struct condvar *cv) 351*51f49692SMarouene Boubakri { 352*51f49692SMarouene Boubakri if (cv->m && wq_have_condvar(&cv->m->wq, cv)) 353*51f49692SMarouene Boubakri panic(); 354*51f49692SMarouene Boubakri 355*51f49692SMarouene Boubakri condvar_init(cv); 356*51f49692SMarouene Boubakri } 357*51f49692SMarouene Boubakri 358*51f49692SMarouene Boubakri static void cv_signal(struct condvar *cv, bool only_one, const char *fname, 359*51f49692SMarouene Boubakri int lineno) 360*51f49692SMarouene Boubakri { 361*51f49692SMarouene Boubakri uint32_t old_itr_status; 362*51f49692SMarouene Boubakri struct mutex *m; 363*51f49692SMarouene Boubakri 364*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&cv->spin_lock); 365*51f49692SMarouene Boubakri m = cv->m; 366*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&cv->spin_lock, old_itr_status); 367*51f49692SMarouene Boubakri 368*51f49692SMarouene Boubakri if (m) 369*51f49692SMarouene Boubakri wq_promote_condvar(&m->wq, cv, only_one, m, fname, lineno); 370*51f49692SMarouene Boubakri 371*51f49692SMarouene Boubakri } 372*51f49692SMarouene Boubakri 373*51f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG 374*51f49692SMarouene Boubakri void condvar_signal_debug(struct condvar *cv, const char *fname, int lineno) 375*51f49692SMarouene Boubakri { 376*51f49692SMarouene Boubakri cv_signal(cv, true /* only one */, fname, lineno); 377*51f49692SMarouene Boubakri } 378*51f49692SMarouene Boubakri 379*51f49692SMarouene Boubakri void condvar_broadcast_debug(struct condvar *cv, const char *fname, int lineno) 380*51f49692SMarouene Boubakri { 381*51f49692SMarouene Boubakri cv_signal(cv, false /* all */, fname, lineno); 382*51f49692SMarouene Boubakri } 383*51f49692SMarouene Boubakri 384*51f49692SMarouene Boubakri #else 385*51f49692SMarouene Boubakri void condvar_signal(struct condvar *cv) 386*51f49692SMarouene Boubakri { 387*51f49692SMarouene Boubakri cv_signal(cv, true /* only one */, NULL, -1); 388*51f49692SMarouene Boubakri } 389*51f49692SMarouene Boubakri 390*51f49692SMarouene Boubakri void condvar_broadcast(struct condvar *cv) 391*51f49692SMarouene Boubakri { 392*51f49692SMarouene Boubakri cv_signal(cv, false /* all */, NULL, -1); 393*51f49692SMarouene Boubakri } 394*51f49692SMarouene Boubakri #endif /*CFG_MUTEX_DEBUG*/ 395*51f49692SMarouene Boubakri 396*51f49692SMarouene Boubakri static void __condvar_wait(struct condvar *cv, struct mutex *m, 397*51f49692SMarouene Boubakri const char *fname, int lineno) 398*51f49692SMarouene Boubakri { 399*51f49692SMarouene Boubakri uint32_t old_itr_status; 400*51f49692SMarouene Boubakri struct wait_queue_elem wqe; 401*51f49692SMarouene Boubakri short old_state; 402*51f49692SMarouene Boubakri short new_state; 403*51f49692SMarouene Boubakri 404*51f49692SMarouene Boubakri mutex_unlock_check(m); 405*51f49692SMarouene Boubakri 406*51f49692SMarouene Boubakri /* Link this condvar to this mutex until reinitialized */ 407*51f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&cv->spin_lock); 408*51f49692SMarouene Boubakri if (cv->m && cv->m != m) 409*51f49692SMarouene Boubakri panic("invalid mutex"); 410*51f49692SMarouene Boubakri 411*51f49692SMarouene Boubakri cv->m = m; 412*51f49692SMarouene Boubakri cpu_spin_unlock(&cv->spin_lock); 413*51f49692SMarouene Boubakri 414*51f49692SMarouene Boubakri cpu_spin_lock(&m->spin_lock); 415*51f49692SMarouene Boubakri 416*51f49692SMarouene Boubakri if (!m->state) 417*51f49692SMarouene Boubakri panic(); 418*51f49692SMarouene Boubakri old_state = m->state; 419*51f49692SMarouene Boubakri /* Add to mutex wait queue as a condvar waiter */ 420*51f49692SMarouene Boubakri wq_wait_init_condvar(&m->wq, &wqe, cv, m->state > 0); 421*51f49692SMarouene Boubakri 422*51f49692SMarouene Boubakri if (m->state > 1) { 423*51f49692SMarouene Boubakri /* Multiple read locks, remove one */ 424*51f49692SMarouene Boubakri m->state--; 425*51f49692SMarouene Boubakri } else { 426*51f49692SMarouene Boubakri /* Only one lock (read or write), unlock the mutex */ 427*51f49692SMarouene Boubakri m->state = 0; 428*51f49692SMarouene Boubakri } 429*51f49692SMarouene Boubakri new_state = m->state; 430*51f49692SMarouene Boubakri 431*51f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status); 432*51f49692SMarouene Boubakri 433*51f49692SMarouene Boubakri /* Wake eventual waiters if the mutex was unlocked */ 434*51f49692SMarouene Boubakri if (!new_state) 435*51f49692SMarouene Boubakri wq_wake_next(&m->wq, m, fname, lineno); 436*51f49692SMarouene Boubakri 437*51f49692SMarouene Boubakri wq_wait_final(&m->wq, &wqe, m, fname, lineno); 438*51f49692SMarouene Boubakri 439*51f49692SMarouene Boubakri if (old_state > 0) 440*51f49692SMarouene Boubakri mutex_read_lock(m); 441*51f49692SMarouene Boubakri else 442*51f49692SMarouene Boubakri mutex_lock(m); 443*51f49692SMarouene Boubakri } 444*51f49692SMarouene Boubakri 445*51f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG 446*51f49692SMarouene Boubakri void condvar_wait_debug(struct condvar *cv, struct mutex *m, 447*51f49692SMarouene Boubakri const char *fname, int lineno) 448*51f49692SMarouene Boubakri { 449*51f49692SMarouene Boubakri __condvar_wait(cv, m, fname, lineno); 450*51f49692SMarouene Boubakri } 451*51f49692SMarouene Boubakri #else 452*51f49692SMarouene Boubakri void condvar_wait(struct condvar *cv, struct mutex *m) 453*51f49692SMarouene Boubakri { 454*51f49692SMarouene Boubakri __condvar_wait(cv, m, NULL, -1); 455*51f49692SMarouene Boubakri } 456*51f49692SMarouene Boubakri #endif 457