1/* $OpenBSD: mutex.h,v 1.22 2024/05/16 09:30:03 kettenis Exp $ */ 2 3/* 4 * Copyright (c) 2004 Artur Grabowski <art@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#ifndef _SYS_MUTEX_H_ 20#define _SYS_MUTEX_H_ 21 22/* 23 * A mutex is: 24 * - owned by a cpu. 25 * - non-recursive. 26 * - spinning. 27 * - not providing mutual exclusion between processes, only cpus. 28 * - providing interrupt blocking when necessary. 29 * 30 * Different mutexes can be nested, but not interleaved. This is ok: 31 * "mtx_enter(foo); mtx_enter(bar); mtx_leave(bar); mtx_leave(foo);" 32 * This is _not_ ok: 33 * "mtx_enter(foo); mtx_enter(bar); mtx_leave(foo); mtx_leave(bar);" 34 */ 35 36/* 37 * To prevent lock ordering problems with the kernel lock, we need to 38 * make sure we block all interrupts that can grab the kernel lock. 39 * The simplest way to achieve this is to make sure mutexes always 40 * raise the interrupt priority level to the highest level that has 41 * interrupts that grab the kernel lock. 42 */ 43#ifdef MULTIPROCESSOR 44#define __MUTEX_IPL(ipl) \ 45 (((ipl) < IPL_MPFLOOR) ? IPL_MPFLOOR : (ipl)) 46#else 47#define __MUTEX_IPL(ipl) (ipl) 48#endif 49 50#include <machine/mutex.h> 51 52#ifdef __USE_MI_MUTEX 53 54#include <sys/_lock.h> 55 56struct mutex { 57 void *volatile mtx_owner; 58 int mtx_wantipl; 59 int mtx_oldipl; 60#ifdef WITNESS 61 struct lock_object mtx_lock_obj; 62#endif 63}; 64 65#ifdef WITNESS 66#define MUTEX_INITIALIZER_FLAGS(ipl, name, flags) \ 67 { NULL, __MUTEX_IPL((ipl)), IPL_NONE, MTX_LO_INITIALIZER(name, flags) } 68#else 69#define MUTEX_INITIALIZER_FLAGS(ipl, name, flags) \ 70 { NULL, __MUTEX_IPL((ipl)), IPL_NONE } 71#endif 72 73void __mtx_init(struct mutex *, int); 74#define _mtx_init(mtx, ipl) __mtx_init((mtx), __MUTEX_IPL((ipl))) 75 76#ifdef DIAGNOSTIC 77#define MUTEX_ASSERT_LOCKED(mtx) do { \ 78 if (((mtx)->mtx_owner != curcpu()) && !(panicstr || db_active)) \ 79 panic("mutex %p not held in %s", (mtx), __func__); \ 80} while (0) 81 82#define MUTEX_ASSERT_UNLOCKED(mtx) do { \ 83 if (((mtx)->mtx_owner == curcpu()) && !(panicstr || db_active)) \ 84 panic("mutex %p held in %s", (mtx), __func__); \ 85} while (0) 86#else 87#define MUTEX_ASSERT_LOCKED(mtx) do { (void)(mtx); } while (0) 88#define MUTEX_ASSERT_UNLOCKED(mtx) do { (void)(mtx); } while (0) 89#endif 90 91#define MUTEX_LOCK_OBJECT(mtx) (&(mtx)->mtx_lock_obj) 92#define MUTEX_OLDIPL(mtx) (mtx)->mtx_oldipl 93 94#endif /* __USE_MI_MUTEX */ 95 96 97#define MTX_LO_FLAGS(flags) \ 98 ((!((flags) & MTX_NOWITNESS) ? LO_WITNESS : 0) | \ 99 ((flags) & MTX_DUPOK ? LO_DUPOK : 0) | \ 100 LO_INITIALIZED | (LO_CLASS_MUTEX << LO_CLASSSHIFT)) 101 102#define __MTX_STRING(x) #x 103#define __MTX_S(x) __MTX_STRING(x) 104#define __MTX_NAME __FILE__ ":" __MTX_S(__LINE__) 105 106#define MTX_LO_INITIALIZER(name, flags) \ 107 { .lo_type = &(const struct lock_type){ .lt_name = __MTX_NAME }, \ 108 .lo_name = (name), \ 109 .lo_flags = MTX_LO_FLAGS(flags) } 110 111#define MTX_NOWITNESS 0x01 112#define MTX_DUPOK 0x02 113 114#define MUTEX_INITIALIZER(ipl) \ 115 MUTEX_INITIALIZER_FLAGS(ipl, __MTX_NAME, 0) 116 117/* 118 * Some architectures need to do magic for the ipl, so they need a macro. 119 */ 120#ifndef _mtx_init 121void _mtx_init(struct mutex *, int); 122#endif 123 124void mtx_enter(struct mutex *); 125int mtx_enter_try(struct mutex *); 126void mtx_leave(struct mutex *); 127 128#define mtx_init(m, ipl) mtx_init_flags(m, ipl, NULL, 0) 129 130#define mtx_owned(mtx) \ 131 (((mtx)->mtx_owner == curcpu()) || panicstr || db_active) 132 133#ifdef WITNESS 134 135void _mtx_init_flags(struct mutex *, int, const char *, int, 136 const struct lock_type *); 137 138#define mtx_init_flags(m, ipl, name, flags) do { \ 139 static const struct lock_type __lock_type = { .lt_name = #m }; \ 140 _mtx_init_flags(m, ipl, name, flags, &__lock_type); \ 141} while (0) 142 143#else /* WITNESS */ 144 145#define mtx_init_flags(m, ipl, name, flags) do { \ 146 (void)(name); (void)(flags); \ 147 _mtx_init(m, ipl); \ 148} while (0) 149 150#define _mtx_init_flags(m,i,n,f,t) _mtx_init(m,i) 151 152#endif /* WITNESS */ 153 154#if defined(_KERNEL) && defined(DDB) 155 156struct db_mutex { 157 struct cpu_info *mtx_owner; 158 unsigned long mtx_intr_state; 159}; 160 161#define DB_MUTEX_INITIALIZER { NULL, 0 } 162 163void db_mtx_enter(struct db_mutex *); 164void db_mtx_leave(struct db_mutex *); 165 166#endif /* _KERNEL && DDB */ 167 168#endif 169