xref: /openbsd-src/sys/sys/mutex.h (revision 52ac02e4d7f3dc6035fb429a557276c9f267439a)
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