sx.h revision 315394
1139825Simp/*-
2168191Sjhb * Copyright (c) 2007 Attilio Rao <attilio@freebsd.org>
3168191Sjhb * Copyright (c) 2001 Jason Evans <jasone@freebsd.org>
4168191Sjhb * All rights reserved.
573782Sjasone *
673782Sjasone * Redistribution and use in source and binary forms, with or without
773782Sjasone * modification, are permitted provided that the following conditions
873782Sjasone * are met:
973782Sjasone * 1. Redistributions of source code must retain the above copyright
1073782Sjasone *    notice(s), this list of conditions and the following disclaimer as
1173782Sjasone *    the first lines of this file unmodified other than the possible
1273782Sjasone *    addition of one or more copyright notices.
1373782Sjasone * 2. Redistributions in binary form must reproduce the above copyright
1473782Sjasone *    notice(s), this list of conditions and the following disclaimer in the
1573782Sjasone *    documentation and/or other materials provided with the distribution.
1673782Sjasone *
1773782Sjasone * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
1873782Sjasone * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1973782Sjasone * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2073782Sjasone * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
2173782Sjasone * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2273782Sjasone * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2373782Sjasone * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2473782Sjasone * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2573782Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2673782Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2773782Sjasone * DAMAGE.
2873782Sjasone *
2973782Sjasone * $FreeBSD: stable/11/sys/sys/sx.h 315394 2017-03-16 08:29:09Z mjg $
3073782Sjasone */
3173782Sjasone
3273782Sjasone#ifndef	_SYS_SX_H_
3373782Sjasone#define	_SYS_SX_H_
3473782Sjasone
3583103Sjhb#include <sys/_lock.h>
36168191Sjhb#include <sys/_sx.h>
3773782Sjasone
38168191Sjhb#ifdef	_KERNEL
39181682Sed#include <sys/pcpu.h>
40181682Sed#include <sys/lock_profile.h>
41192853Ssson#include <sys/lockstat.h>
42168191Sjhb#include <machine/atomic.h>
43168191Sjhb#endif
4473782Sjasone
45168191Sjhb/*
46168191Sjhb * In general, the sx locks and rwlocks use very similar algorithms.
47168191Sjhb * The main difference in the implementations is how threads are
48168191Sjhb * blocked when a lock is unavailable.  For this, sx locks use sleep
49168191Sjhb * queues which do not support priority propagation, and rwlocks use
50168191Sjhb * turnstiles which do.
51168191Sjhb *
52168191Sjhb * The sx_lock field consists of several fields.  The low bit
53168191Sjhb * indicates if the lock is locked with a shared or exclusive lock.  A
54168191Sjhb * value of 0 indicates an exclusive lock, and a value of 1 indicates
55168191Sjhb * a shared lock.  Bit 1 is a boolean indicating if there are any
56168191Sjhb * threads waiting for a shared lock.  Bit 2 is a boolean indicating
57168191Sjhb * if there are any threads waiting for an exclusive lock.  Bit 3 is a
58168191Sjhb * boolean indicating if an exclusive lock is recursively held.  The
59168191Sjhb * rest of the variable's definition is dependent on the value of the
60168191Sjhb * first bit.  For an exclusive lock, it is a pointer to the thread
61168191Sjhb * holding the lock, similar to the mtx_lock field of mutexes.  For
62168191Sjhb * shared locks, it is a count of read locks that are held.
63168191Sjhb *
64168191Sjhb * When the lock is not locked by any thread, it is encoded as a
65168191Sjhb * shared lock with zero waiters.
66168191Sjhb */
67168191Sjhb
68168191Sjhb#define	SX_LOCK_SHARED			0x01
69168191Sjhb#define	SX_LOCK_SHARED_WAITERS		0x02
70168191Sjhb#define	SX_LOCK_EXCLUSIVE_WAITERS	0x04
71168191Sjhb#define	SX_LOCK_RECURSED		0x08
72168191Sjhb#define	SX_LOCK_FLAGMASK						\
73168191Sjhb	(SX_LOCK_SHARED | SX_LOCK_SHARED_WAITERS |			\
74168191Sjhb	SX_LOCK_EXCLUSIVE_WAITERS | SX_LOCK_RECURSED)
75168191Sjhb
76168191Sjhb#define	SX_OWNER(x)			((x) & ~SX_LOCK_FLAGMASK)
77168191Sjhb#define	SX_SHARERS_SHIFT		4
78168191Sjhb#define	SX_SHARERS(x)			(SX_OWNER(x) >> SX_SHARERS_SHIFT)
79168191Sjhb#define	SX_SHARERS_LOCK(x)						\
80168191Sjhb	((x) << SX_SHARERS_SHIFT | SX_LOCK_SHARED)
81168191Sjhb#define	SX_ONE_SHARER			(1 << SX_SHARERS_SHIFT)
82168191Sjhb
83168191Sjhb#define	SX_LOCK_UNLOCKED		SX_SHARERS_LOCK(0)
84169394Sjhb#define	SX_LOCK_DESTROYED						\
85169394Sjhb	(SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)
86168191Sjhb
8773782Sjasone#ifdef _KERNEL
88168191Sjhb
89258541Sattilio#define	sx_recurse	lock_object.lo_data
90258541Sattilio
91315341Smjg#define	SX_READ_VALUE(sx)	((sx)->sx_lock)
92315341Smjg
93315341Smjg#define	lv_sx_owner(v) \
94315341Smjg	((v & SX_LOCK_SHARED) ? NULL : (struct thread *)SX_OWNER(v))
95315341Smjg
96168191Sjhb/*
97168191Sjhb * Function prototipes.  Routines that start with an underscore are not part
98168191Sjhb * of the public interface and are wrappered with a macro.
99168191Sjhb */
10093672Sarrvoid	sx_sysinit(void *arg);
101168191Sjhb#define	sx_init(sx, desc)	sx_init_flags((sx), (desc), 0)
102168191Sjhbvoid	sx_init_flags(struct sx *sx, const char *description, int opts);
10373782Sjasonevoid	sx_destroy(struct sx *sx);
104227788Sattilioint	sx_try_slock_(struct sx *sx, const char *file, int line);
105227788Sattilioint	sx_try_xlock_(struct sx *sx, const char *file, int line);
106227788Sattilioint	sx_try_upgrade_(struct sx *sx, const char *file, int line);
107227788Sattiliovoid	sx_downgrade_(struct sx *sx, const char *file, int line);
108170149Sattilioint	_sx_slock(struct sx *sx, int opts, const char *file, int line);
109170149Sattilioint	_sx_xlock(struct sx *sx, int opts, const char *file, int line);
11074912Sjhbvoid	_sx_sunlock(struct sx *sx, const char *file, int line);
11174912Sjhbvoid	_sx_xunlock(struct sx *sx, const char *file, int line);
112315377Smjgint	_sx_xlock_hard(struct sx *sx, uintptr_t v, uintptr_t tid, int opts,
113170149Sattilio	    const char *file, int line);
114168191Sjhbvoid	_sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int
115168191Sjhb	    line);
116161721Sjhb#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
117227588Spjdvoid	_sx_assert(const struct sx *sx, int what, const char *file, int line);
11893688Sarr#endif
119161337Sjhb#ifdef DDB
120161337Sjhbint	sx_chain(struct thread *td, struct thread **ownerp);
121161337Sjhb#endif
12293672Sarr
12393672Sarrstruct sx_args {
12493672Sarr	struct sx 	*sa_sx;
12593672Sarr	const char	*sa_desc;
126219819Sjeff	int		sa_flags;
12793672Sarr};
12893672Sarr
129219819Sjeff#define	SX_SYSINIT_FLAGS(name, sxa, desc, flags)			\
13093672Sarr	static struct sx_args name##_args = {				\
131149739Sjhb		(sxa),							\
132219819Sjeff		(desc),							\
133219819Sjeff		(flags)							\
13493672Sarr	};								\
13593672Sarr	SYSINIT(name##_sx_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
136149739Sjhb	    sx_sysinit, &name##_args);					\
137149739Sjhb	SYSUNINIT(name##_sx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
138149739Sjhb	    sx_destroy, (sxa))
13973782Sjasone
140219819Sjeff#define	SX_SYSINIT(name, sxa, desc)	SX_SYSINIT_FLAGS(name, sxa, desc, 0)
141219819Sjeff
142168191Sjhb/*
143170149Sattilio * Full lock operations that are suitable to be inlined in non-debug kernels.
144170149Sattilio * If the lock can't be acquired or released trivially then the work is
145170149Sattilio * deferred to 'tougher' functions.
146170149Sattilio */
147170149Sattilio
148315394Smjg#if	(LOCK_DEBUG == 0)
149170149Sattilio/* Acquire an exclusive lock. */
150170149Sattiliostatic __inline int
151170149Sattilio__sx_xlock(struct sx *sx, struct thread *td, int opts, const char *file,
152170149Sattilio    int line)
153170149Sattilio{
154170149Sattilio	uintptr_t tid = (uintptr_t)td;
155315378Smjg	uintptr_t v = SX_LOCK_UNLOCKED;
156170149Sattilio	int error = 0;
157170149Sattilio
158315378Smjg	if (__predict_false(LOCKSTAT_PROFILE_ENABLED(sx__acquire) ||
159315378Smjg	    !atomic_fcmpset_acq_ptr(&sx->sx_lock, &v, tid)))
160315377Smjg		error = _sx_xlock_hard(sx, v, tid, opts, file, line);
161170149Sattilio
162170149Sattilio	return (error);
163170149Sattilio}
164170149Sattilio
165170149Sattilio/* Release an exclusive lock. */
166170149Sattiliostatic __inline void
167170149Sattilio__sx_xunlock(struct sx *sx, struct thread *td, const char *file, int line)
168170149Sattilio{
169170149Sattilio	uintptr_t tid = (uintptr_t)td;
170170149Sattilio
171315378Smjg	if (__predict_false(LOCKSTAT_PROFILE_ENABLED(sx__release) ||
172315378Smjg	    !atomic_cmpset_rel_ptr(&sx->sx_lock, tid, SX_LOCK_UNLOCKED)))
173170149Sattilio		_sx_xunlock_hard(sx, tid, file, line);
174170149Sattilio}
175315378Smjg#endif
176170149Sattilio
177170149Sattilio/*
178168191Sjhb * Public interface for lock operations.
179168191Sjhb */
180168191Sjhb#ifndef LOCK_DEBUG
181168191Sjhb#error	"LOCK_DEBUG not defined, include <sys/lock.h> before <sys/sx.h>"
182168191Sjhb#endif
183168191Sjhb#if	(LOCK_DEBUG > 0) || defined(SX_NOINLINE)
184227788Sattilio#define	sx_xlock_(sx, file, line)					\
185227788Sattilio	(void)_sx_xlock((sx), 0, (file), (line))
186227788Sattilio#define	sx_xlock_sig_(sx, file, line)					\
187227788Sattilio	_sx_xlock((sx), SX_INTERRUPTIBLE, (file), (line))
188227788Sattilio#define	sx_xunlock_(sx, file, line)					\
189227788Sattilio	_sx_xunlock((sx), (file), (line))
190168191Sjhb#else
191227788Sattilio#define	sx_xlock_(sx, file, line)					\
192227788Sattilio	(void)__sx_xlock((sx), curthread, 0, (file), (line))
193227788Sattilio#define	sx_xlock_sig_(sx, file, line)					\
194227788Sattilio	__sx_xlock((sx), curthread, SX_INTERRUPTIBLE, (file), (line))
195227788Sattilio#define	sx_xunlock_(sx, file, line)					\
196227788Sattilio	__sx_xunlock((sx), curthread, (file), (line))
197315377Smjg#endif	/* LOCK_DEBUG > 0 || SX_NOINLINE */
198227788Sattilio#define	sx_slock_(sx, file, line)					\
199315377Smjg	(void)_sx_slock((sx), 0, (file), (line))
200227788Sattilio#define	sx_slock_sig_(sx, file, line)					\
201315377Smjg	_sx_slock((sx), SX_INTERRUPTIBLE, (file) , (line))
202227788Sattilio#define	sx_sunlock_(sx, file, line)					\
203315377Smjg	_sx_sunlock((sx), (file), (line))
204227788Sattilio#define	sx_try_slock(sx)	sx_try_slock_((sx), LOCK_FILE, LOCK_LINE)
205227788Sattilio#define	sx_try_xlock(sx)	sx_try_xlock_((sx), LOCK_FILE, LOCK_LINE)
206227788Sattilio#define	sx_try_upgrade(sx)	sx_try_upgrade_((sx), LOCK_FILE, LOCK_LINE)
207227788Sattilio#define	sx_downgrade(sx)	sx_downgrade_((sx), LOCK_FILE, LOCK_LINE)
208227788Sattilio#ifdef INVARIANTS
209227788Sattilio#define	sx_assert_(sx, what, file, line)				\
210227788Sattilio	_sx_assert((sx), (what), (file), (line))
211227788Sattilio#else
212227788Sattilio#define	sx_assert_(sx, what, file, line)	(void)0
213227788Sattilio#endif
214168191Sjhb
215227788Sattilio#define	sx_xlock(sx)		sx_xlock_((sx), LOCK_FILE, LOCK_LINE)
216227788Sattilio#define	sx_xlock_sig(sx)	sx_xlock_sig_((sx), LOCK_FILE, LOCK_LINE)
217227788Sattilio#define	sx_xunlock(sx)		sx_xunlock_((sx), LOCK_FILE, LOCK_LINE)
218227788Sattilio#define	sx_slock(sx)		sx_slock_((sx), LOCK_FILE, LOCK_LINE)
219227788Sattilio#define	sx_slock_sig(sx)	sx_slock_sig_((sx), LOCK_FILE, LOCK_LINE)
220227788Sattilio#define	sx_sunlock(sx)		sx_sunlock_((sx), LOCK_FILE, LOCK_LINE)
221227788Sattilio#define	sx_assert(sx, what)	sx_assert_((sx), (what), __FILE__, __LINE__)
222227788Sattilio
223169776Sjhb/*
224169776Sjhb * Return a pointer to the owning thread if the lock is exclusively
225169776Sjhb * locked.
226169776Sjhb */
227169776Sjhb#define	sx_xholder(sx)							\
228169776Sjhb	((sx)->sx_lock & SX_LOCK_SHARED ? NULL :			\
229169776Sjhb	(struct thread *)SX_OWNER((sx)->sx_lock))
230169776Sjhb
231168191Sjhb#define	sx_xlocked(sx)							\
232168191Sjhb	(((sx)->sx_lock & ~(SX_LOCK_FLAGMASK & ~SX_LOCK_SHARED)) ==	\
233168191Sjhb	    (uintptr_t)curthread)
234168191Sjhb
235227788Sattilio#define	sx_unlock_(sx, file, line) do {					\
236159844Sjhb	if (sx_xlocked(sx))						\
237227788Sattilio		sx_xunlock_(sx, file, line);				\
238157296Sjhb	else								\
239227788Sattilio		sx_sunlock_(sx, file, line);				\
240157296Sjhb} while (0)
241168191Sjhb
242227788Sattilio#define	sx_unlock(sx)	sx_unlock_((sx), LOCK_FILE, LOCK_LINE)
243227788Sattilio
244167387Sjhb#define	sx_sleep(chan, sx, pri, wmesg, timo)				\
245247787Sdavide	_sleep((chan), &(sx)->lock_object, (pri), (wmesg),		\
246247787Sdavide	    tick_sbt * (timo), 0,  C_HARDCLOCK)
24774912Sjhb
248168191Sjhb/*
249168191Sjhb * Options passed to sx_init_flags().
250168191Sjhb */
251168191Sjhb#define	SX_DUPOK		0x01
252168191Sjhb#define	SX_NOPROFILE		0x02
253168191Sjhb#define	SX_NOWITNESS		0x04
254168191Sjhb#define	SX_QUIET		0x08
255193011Sattilio#define	SX_NOADAPTIVE		0x10
256169769Sjhb#define	SX_RECURSE		0x20
257275751Sdchagin#define	SX_NEW			0x40
258168191Sjhb
259170149Sattilio/*
260170149Sattilio * Options passed to sx_*lock_hard().
261170149Sattilio */
262170149Sattilio#define	SX_INTERRUPTIBLE	0x40
263170149Sattilio
26485412Sjhb#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
265169780Sjhb#define	SA_LOCKED		LA_LOCKED
266169780Sjhb#define	SA_SLOCKED		LA_SLOCKED
267169780Sjhb#define	SA_XLOCKED		LA_XLOCKED
268169780Sjhb#define	SA_UNLOCKED		LA_UNLOCKED
269169780Sjhb#define	SA_RECURSED		LA_RECURSED
270169780Sjhb#define	SA_NOTRECURSED		LA_NOTRECURSED
271169780Sjhb
272298981Spfg/* Backwards compatibility. */
27385388Sjhb#define	SX_LOCKED		LA_LOCKED
27485388Sjhb#define	SX_SLOCKED		LA_SLOCKED
27585388Sjhb#define	SX_XLOCKED		LA_XLOCKED
276125419Spjd#define	SX_UNLOCKED		LA_UNLOCKED
277168191Sjhb#define	SX_RECURSED		LA_RECURSED
278168191Sjhb#define	SX_NOTRECURSED		LA_NOTRECURSED
279125444Sbde#endif
28073863Sbmilekic
281125444Sbde#endif /* _KERNEL */
282125444Sbde
283125444Sbde#endif /* !_SYS_SX_H_ */
284