master
  1/*	$NetBSD: mutex.h,v 1.26 2022/10/26 23:21:20 riastradh Exp $	*/
  2
  3/*-
  4 * Copyright (c) 2002, 2006, 2007, 2008, 2009, 2019 The NetBSD Foundation, Inc.
  5 * All rights reserved.
  6 *
  7 * This code is derived from software contributed to The NetBSD Foundation
  8 * by Jason R. Thorpe and Andrew Doran.
  9 *
 10 * Redistribution and use in source and binary forms, with or without
 11 * modification, are permitted provided that the following conditions
 12 * are met:
 13 * 1. Redistributions of source code must retain the above copyright
 14 *    notice, this list of conditions and the following disclaimer.
 15 * 2. Redistributions in binary form must reproduce the above copyright
 16 *    notice, this list of conditions and the following disclaimer in the
 17 *    documentation and/or other materials provided with the distribution.
 18 *
 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 29 * POSSIBILITY OF SUCH DAMAGE.
 30 */
 31
 32#ifndef _SYS_MUTEX_H_
 33#define	_SYS_MUTEX_H_
 34
 35/*
 36 * There are 2 types of mutexes:
 37 *
 38 *	* Adaptive -- If the lock is already held, the thread attempting
 39 *	  to acquire the lock determines if the thread that holds it is
 40 *	  currently running.  If so, it spins, else it sleeps.
 41 *
 42 *	* Spin -- If the lock is already held, the thread attempting to
 43 *	  acquire the lock spins.  The IPL will be raised on entry.
 44 *
 45 * Machine dependent code must provide the following:
 46 *
 47 *	struct mutex
 48 *		The actual mutex structure.  This structure is mostly
 49 *		opaque to machine-independent code; most access are done
 50 *		through macros.  However, machine-independent code must
 51 *		be able to access the following members:
 52 *
 53 *		uintptr_t		mtx_owner
 54 *		ipl_cookie_t		mtx_ipl
 55 *		__cpu_simple_lock_t	mtx_lock
 56 *
 57 * If an architecture can be considered 'simple' (no interlock required in
 58 * the MP case, or no MP) it need only define __HAVE_SIMPLE_MUTEXES and
 59 * provide the following:
 60 *
 61 *	struct mutex
 62 *
 63 *		[additionally:]
 64 *		volatile integer	mtx_id
 65 *
 66 * 	MUTEX_CAS(ptr, old, new)
 67 *		Perform an atomic "compare and swap" operation and
 68 *		evaluate to true or false according to the success
 69 *
 70 * Otherwise, the following must be defined:
 71 *
 72 *	MUTEX_INITIALIZE_SPIN(mtx, dodebug, minipl)
 73 *		Initialize a spin mutex.
 74 *
 75 *	MUTEX_INITIALIZE_ADAPTIVE(mtx, dodebug)
 76 *		Initialize an adaptive mutex.
 77 *
 78 *	MUTEX_DESTROY(mtx)
 79 *		Tear down a mutex.
 80 *
 81 *	MUTEX_ADAPTIVE_P(mtx)
 82 *		Evaluates to true if the mutex is an adaptive mutex.
 83 *
 84 *	MUTEX_SPIN_P(mtx)
 85 *		Evaluates to true if the mutex is a spin mutex.
 86 *
 87 *	MUTEX_OWNER(owner)
 88 *		Returns the owner of the adaptive mutex (LWP address).
 89 *
 90 *	MUTEX_OWNED(owner)
 91 *		Returns non-zero if an adaptive mutex is currently
 92 *		held by an LWP.
 93 *
 94 *	MUTEX_HAS_WAITERS(mtx)
 95 *		Returns true if the mutex has waiters.
 96 *
 97 *	MUTEX_SET_WAITERS(mtx)
 98 *		Mark the mutex has having waiters.
 99 *
100 *	MUTEX_ACQUIRE(mtx, owner)
101 *		Try to acquire an adaptive mutex such that:
102 *			if (lock held OR waiters)
103 *				return 0;
104 *			else
105 *				return 1;
106 *		Must be MP/interrupt atomic.
107 *
108 *	MUTEX_RELEASE(mtx)
109 *		Release the lock and clear the "has waiters" indication.
110 *		Must be interrupt atomic, need not be MP safe.
111 *
112 *	MUTEX_DEBUG_P(mtx)
113 *		Evaluates to true if the mutex is initialized with
114 *		dodebug==true.  Only used in the LOCKDEBUG case.
115 *
116 * Machine dependent code may optionally provide stubs for the following
117 * functions to implement the easy (unlocked / no waiters) cases.  If
118 * these stubs are provided, __HAVE_MUTEX_STUBS should be defined.
119 *
120 *	mutex_enter()
121 *	mutex_exit()
122 *
123 * Two additional stubs may be implemented that handle only the spinlock
124 * case, primarily for the scheduler.  __HAVE_SPIN_MUTEX_STUBS should be
125 * defined if these are provided:
126 *
127 *	mutex_spin_enter()
128 *	mutex_spin_exit()
129 */
130
131#if defined(_KERNEL_OPT)
132#include "opt_lockdebug.h"
133#endif
134
135#if !defined(_KERNEL)
136#include <sys/types.h>
137#include <sys/inttypes.h>
138#endif
139
140typedef enum kmutex_type_t {
141	MUTEX_SPIN = 0,		/* To get a spin mutex at IPL_NONE */
142	MUTEX_ADAPTIVE = 1,	/* For porting code written for Solaris */
143	MUTEX_DEFAULT = 2,	/* The only native, endorsed type */
144	MUTEX_DRIVER = 3,	/* For porting code written for Solaris */
145	MUTEX_NODEBUG = 4	/* Disables LOCKDEBUG; use with care */
146} kmutex_type_t;
147
148typedef struct kmutex kmutex_t;
149
150#if defined(__MUTEX_PRIVATE)
151
152#define	MUTEX_THREAD			((uintptr_t)-16L)
153
154#define	MUTEX_BIT_SPIN			0x01
155#define	MUTEX_BIT_WAITERS		0x02
156
157#if defined(LOCKDEBUG)
158#define	MUTEX_BIT_NODEBUG		0x04	/* LOCKDEBUG disabled */
159#else
160#define	MUTEX_BIT_NODEBUG		0x00	/* do nothing */
161#endif	/* LOCKDEBUG */
162
163#define	MUTEX_SPIN_IPL(mtx)		((mtx)->mtx_ipl)
164#define	MUTEX_SPIN_OLDSPL(ci)		((ci)->ci_mtx_oldspl)
165
166void	mutex_vector_enter(kmutex_t *);
167void	mutex_vector_exit(kmutex_t *);
168void	mutex_spin_retry(kmutex_t *);
169void	mutex_wakeup(kmutex_t *);
170
171#endif	/* __MUTEX_PRIVATE */
172
173#ifdef _KERNEL
174#include <sys/intr.h>
175#endif
176
177#include <machine/mutex.h>
178
179/*
180 * Return true if no spin mutexes are held by the current CPU.
181 */
182#ifndef MUTEX_NO_SPIN_ACTIVE_P
183#define	MUTEX_NO_SPIN_ACTIVE_P(ci)	((ci)->ci_mtx_count == 0)
184#endif
185
186#ifdef _KERNEL
187
188void	_mutex_init(kmutex_t *, kmutex_type_t, int, uintptr_t);
189void	mutex_init(kmutex_t *, kmutex_type_t, int);
190void	mutex_destroy(kmutex_t *);
191
192void	mutex_enter(kmutex_t *);
193void	mutex_exit(kmutex_t *);
194
195void	mutex_spin_enter(kmutex_t *);
196void	mutex_spin_exit(kmutex_t *);
197
198int	mutex_tryenter(kmutex_t *);
199
200int	mutex_owned(const kmutex_t *);
201int	mutex_ownable(const kmutex_t *);
202lwp_t	*mutex_owner(const kmutex_t *);
203bool	mutex_owner_running(const kmutex_t *);
204
205void	mutex_obj_init(void);
206kmutex_t *mutex_obj_alloc(kmutex_type_t, int);
207void	mutex_obj_hold(kmutex_t *);
208bool	mutex_obj_free(kmutex_t *);
209u_int	mutex_obj_refcnt(kmutex_t *);
210kmutex_t *mutex_obj_tryalloc(kmutex_type_t, int);
211
212#endif /* _KERNEL */
213
214#endif /* _SYS_MUTEX_H_ */