1*52ac02e4Skettenis /* $OpenBSD: mutex.h,v 1.22 2024/05/16 09:30:03 kettenis Exp $ */ 248f0b646Sjsg 34254e7abSart /* 44254e7abSart * Copyright (c) 2004 Artur Grabowski <art@openbsd.org> 54254e7abSart * 654292cf9Smpi * Permission to use, copy, modify, and distribute this software for any 754292cf9Smpi * purpose with or without fee is hereby granted, provided that the above 854292cf9Smpi * copyright notice and this permission notice appear in all copies. 94254e7abSart * 1054292cf9Smpi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1154292cf9Smpi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1254292cf9Smpi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1354292cf9Smpi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1454292cf9Smpi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1554292cf9Smpi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1654292cf9Smpi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 174254e7abSart */ 184254e7abSart 194254e7abSart #ifndef _SYS_MUTEX_H_ 204254e7abSart #define _SYS_MUTEX_H_ 214254e7abSart 224254e7abSart /* 234254e7abSart * A mutex is: 244254e7abSart * - owned by a cpu. 254254e7abSart * - non-recursive. 264254e7abSart * - spinning. 274254e7abSart * - not providing mutual exclusion between processes, only cpus. 284254e7abSart * - providing interrupt blocking when necessary. 294254e7abSart * 304254e7abSart * Different mutexes can be nested, but not interleaved. This is ok: 314254e7abSart * "mtx_enter(foo); mtx_enter(bar); mtx_leave(bar); mtx_leave(foo);" 324254e7abSart * This is _not_ ok: 334254e7abSart * "mtx_enter(foo); mtx_enter(bar); mtx_leave(foo); mtx_leave(bar);" 344254e7abSart */ 354254e7abSart 36*52ac02e4Skettenis /* 37*52ac02e4Skettenis * To prevent lock ordering problems with the kernel lock, we need to 38*52ac02e4Skettenis * make sure we block all interrupts that can grab the kernel lock. 39*52ac02e4Skettenis * The simplest way to achieve this is to make sure mutexes always 40*52ac02e4Skettenis * raise the interrupt priority level to the highest level that has 41*52ac02e4Skettenis * interrupts that grab the kernel lock. 42*52ac02e4Skettenis */ 43*52ac02e4Skettenis #ifdef MULTIPROCESSOR 44*52ac02e4Skettenis #define __MUTEX_IPL(ipl) \ 45*52ac02e4Skettenis (((ipl) < IPL_MPFLOOR) ? IPL_MPFLOOR : (ipl)) 46*52ac02e4Skettenis #else 47*52ac02e4Skettenis #define __MUTEX_IPL(ipl) (ipl) 48*52ac02e4Skettenis #endif 49*52ac02e4Skettenis 504254e7abSart #include <machine/mutex.h> 514254e7abSart 52710c2d98Smpi #ifdef __USE_MI_MUTEX 53710c2d98Smpi 54710c2d98Smpi #include <sys/_lock.h> 55710c2d98Smpi 56710c2d98Smpi struct mutex { 5755c63681Sbluhm void *volatile mtx_owner; 58710c2d98Smpi int mtx_wantipl; 59710c2d98Smpi int mtx_oldipl; 60710c2d98Smpi #ifdef WITNESS 61710c2d98Smpi struct lock_object mtx_lock_obj; 62710c2d98Smpi #endif 63710c2d98Smpi }; 64710c2d98Smpi 65710c2d98Smpi #ifdef WITNESS 66710c2d98Smpi #define MUTEX_INITIALIZER_FLAGS(ipl, name, flags) \ 67710c2d98Smpi { NULL, __MUTEX_IPL((ipl)), IPL_NONE, MTX_LO_INITIALIZER(name, flags) } 68710c2d98Smpi #else 69710c2d98Smpi #define MUTEX_INITIALIZER_FLAGS(ipl, name, flags) \ 70710c2d98Smpi { NULL, __MUTEX_IPL((ipl)), IPL_NONE } 71710c2d98Smpi #endif 72710c2d98Smpi 73710c2d98Smpi void __mtx_init(struct mutex *, int); 74710c2d98Smpi #define _mtx_init(mtx, ipl) __mtx_init((mtx), __MUTEX_IPL((ipl))) 75710c2d98Smpi 76710c2d98Smpi #ifdef DIAGNOSTIC 77710c2d98Smpi #define MUTEX_ASSERT_LOCKED(mtx) do { \ 781bb039c8Smpi if (((mtx)->mtx_owner != curcpu()) && !(panicstr || db_active)) \ 79710c2d98Smpi panic("mutex %p not held in %s", (mtx), __func__); \ 80710c2d98Smpi } while (0) 81710c2d98Smpi 82710c2d98Smpi #define MUTEX_ASSERT_UNLOCKED(mtx) do { \ 831bb039c8Smpi if (((mtx)->mtx_owner == curcpu()) && !(panicstr || db_active)) \ 84710c2d98Smpi panic("mutex %p held in %s", (mtx), __func__); \ 85710c2d98Smpi } while (0) 86710c2d98Smpi #else 87dbbcd4cdSbluhm #define MUTEX_ASSERT_LOCKED(mtx) do { (void)(mtx); } while (0) 88dbbcd4cdSbluhm #define MUTEX_ASSERT_UNLOCKED(mtx) do { (void)(mtx); } while (0) 89710c2d98Smpi #endif 90710c2d98Smpi 91710c2d98Smpi #define MUTEX_LOCK_OBJECT(mtx) (&(mtx)->mtx_lock_obj) 92710c2d98Smpi #define MUTEX_OLDIPL(mtx) (mtx)->mtx_oldipl 93710c2d98Smpi 94710c2d98Smpi #endif /* __USE_MI_MUTEX */ 95710c2d98Smpi 96710c2d98Smpi 97c4925651Svisa #define MTX_LO_FLAGS(flags) \ 98c4925651Svisa ((!((flags) & MTX_NOWITNESS) ? LO_WITNESS : 0) | \ 99c4925651Svisa ((flags) & MTX_DUPOK ? LO_DUPOK : 0) | \ 100c4925651Svisa LO_INITIALIZED | (LO_CLASS_MUTEX << LO_CLASSSHIFT)) 101c4925651Svisa 102b9599a53Svisa #define __MTX_STRING(x) #x 103b9599a53Svisa #define __MTX_S(x) __MTX_STRING(x) 104c4925651Svisa #define __MTX_NAME __FILE__ ":" __MTX_S(__LINE__) 105c4925651Svisa 106c4925651Svisa #define MTX_LO_INITIALIZER(name, flags) \ 107e0c5510eSguenther { .lo_type = &(const struct lock_type){ .lt_name = __MTX_NAME }, \ 10820189ee3Stedu .lo_name = (name), \ 109c4925651Svisa .lo_flags = MTX_LO_FLAGS(flags) } 110c4925651Svisa 111c4925651Svisa #define MTX_NOWITNESS 0x01 112c4925651Svisa #define MTX_DUPOK 0x02 113c4925651Svisa 114c4925651Svisa #define MUTEX_INITIALIZER(ipl) \ 11520189ee3Stedu MUTEX_INITIALIZER_FLAGS(ipl, __MTX_NAME, 0) 116c4925651Svisa 1174254e7abSart /* 1184254e7abSart * Some architectures need to do magic for the ipl, so they need a macro. 1194254e7abSart */ 120c4925651Svisa #ifndef _mtx_init 121c4925651Svisa void _mtx_init(struct mutex *, int); 1224254e7abSart #endif 123c4925651Svisa 1248c00de5eSvisa void mtx_enter(struct mutex *); 1258c00de5eSvisa int mtx_enter_try(struct mutex *); 1268c00de5eSvisa void mtx_leave(struct mutex *); 127c4925651Svisa 128c00cce1fSguenther #define mtx_init(m, ipl) mtx_init_flags(m, ipl, NULL, 0) 129c00cce1fSguenther 130104c0a83Smvs #define mtx_owned(mtx) \ 131104c0a83Smvs (((mtx)->mtx_owner == curcpu()) || panicstr || db_active) 132104c0a83Smvs 133c4925651Svisa #ifdef WITNESS 134c4925651Svisa 135c4925651Svisa void _mtx_init_flags(struct mutex *, int, const char *, int, 136e0c5510eSguenther const struct lock_type *); 137c4925651Svisa 138c4925651Svisa #define mtx_init_flags(m, ipl, name, flags) do { \ 139e0c5510eSguenther static const struct lock_type __lock_type = { .lt_name = #m }; \ 140c4925651Svisa _mtx_init_flags(m, ipl, name, flags, &__lock_type); \ 141c4925651Svisa } while (0) 142c4925651Svisa 143c4925651Svisa #else /* WITNESS */ 144c4925651Svisa 145c4925651Svisa #define mtx_init_flags(m, ipl, name, flags) do { \ 146c4925651Svisa (void)(name); (void)(flags); \ 14762b2a7deSdlg _mtx_init(m, ipl); \ 148c4925651Svisa } while (0) 149c4925651Svisa 150c00cce1fSguenther #define _mtx_init_flags(m,i,n,f,t) _mtx_init(m,i) 151c4925651Svisa 152c4925651Svisa #endif /* WITNESS */ 1534254e7abSart 1543fbde817Svisa #if defined(_KERNEL) && defined(DDB) 1553fbde817Svisa 1563fbde817Svisa struct db_mutex { 1573fbde817Svisa struct cpu_info *mtx_owner; 1583fbde817Svisa unsigned long mtx_intr_state; 1593fbde817Svisa }; 1603fbde817Svisa 1613fbde817Svisa #define DB_MUTEX_INITIALIZER { NULL, 0 } 1623fbde817Svisa 1633fbde817Svisa void db_mtx_enter(struct db_mutex *); 1643fbde817Svisa void db_mtx_leave(struct db_mutex *); 1653fbde817Svisa 1663fbde817Svisa #endif /* _KERNEL && DDB */ 1673fbde817Svisa 1684254e7abSart #endif 169