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 327413 2017-12-31 05:06:35Z 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);
104327413Smjgint	sx_try_slock_int(struct sx *sx LOCK_FILE_LINE_ARG_DEF);
105227788Sattilioint	sx_try_slock_(struct sx *sx, const char *file, int line);
106327413Smjgint	sx_try_xlock_int(struct sx *sx LOCK_FILE_LINE_ARG_DEF);
107227788Sattilioint	sx_try_xlock_(struct sx *sx, const char *file, int line);
108327413Smjgint	sx_try_upgrade_int(struct sx *sx LOCK_FILE_LINE_ARG_DEF);
109227788Sattilioint	sx_try_upgrade_(struct sx *sx, const char *file, int line);
110327413Smjgvoid	sx_downgrade_int(struct sx *sx LOCK_FILE_LINE_ARG_DEF);
111227788Sattiliovoid	sx_downgrade_(struct sx *sx, const char *file, int line);
112327413Smjgint	_sx_slock_int(struct sx *sx, int opts LOCK_FILE_LINE_ARG_DEF);
113170149Sattilioint	_sx_slock(struct sx *sx, int opts, const char *file, int line);
114170149Sattilioint	_sx_xlock(struct sx *sx, int opts, const char *file, int line);
115327413Smjgvoid	_sx_sunlock_int(struct sx *sx LOCK_FILE_LINE_ARG_DEF);
11674912Sjhbvoid	_sx_sunlock(struct sx *sx, const char *file, int line);
11774912Sjhbvoid	_sx_xunlock(struct sx *sx, const char *file, int line);
118327413Smjgint	_sx_xlock_hard(struct sx *sx, uintptr_t x, int opts LOCK_FILE_LINE_ARG_DEF);
119327413Smjgvoid	_sx_xunlock_hard(struct sx *sx, uintptr_t x LOCK_FILE_LINE_ARG_DEF);
120161721Sjhb#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
121227588Spjdvoid	_sx_assert(const struct sx *sx, int what, const char *file, int line);
12293688Sarr#endif
123161337Sjhb#ifdef DDB
124161337Sjhbint	sx_chain(struct thread *td, struct thread **ownerp);
125161337Sjhb#endif
12693672Sarr
12793672Sarrstruct sx_args {
12893672Sarr	struct sx 	*sa_sx;
12993672Sarr	const char	*sa_desc;
130219819Sjeff	int		sa_flags;
13193672Sarr};
13293672Sarr
133219819Sjeff#define	SX_SYSINIT_FLAGS(name, sxa, desc, flags)			\
13493672Sarr	static struct sx_args name##_args = {				\
135149739Sjhb		(sxa),							\
136219819Sjeff		(desc),							\
137219819Sjeff		(flags)							\
13893672Sarr	};								\
13993672Sarr	SYSINIT(name##_sx_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
140149739Sjhb	    sx_sysinit, &name##_args);					\
141149739Sjhb	SYSUNINIT(name##_sx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
142149739Sjhb	    sx_destroy, (sxa))
14373782Sjasone
144219819Sjeff#define	SX_SYSINIT(name, sxa, desc)	SX_SYSINIT_FLAGS(name, sxa, desc, 0)
145219819Sjeff
146168191Sjhb/*
147170149Sattilio * Full lock operations that are suitable to be inlined in non-debug kernels.
148170149Sattilio * If the lock can't be acquired or released trivially then the work is
149170149Sattilio * deferred to 'tougher' functions.
150170149Sattilio */
151170149Sattilio
152315394Smjg#if	(LOCK_DEBUG == 0)
153170149Sattilio/* Acquire an exclusive lock. */
154170149Sattiliostatic __inline int
155170149Sattilio__sx_xlock(struct sx *sx, struct thread *td, int opts, const char *file,
156170149Sattilio    int line)
157170149Sattilio{
158170149Sattilio	uintptr_t tid = (uintptr_t)td;
159315378Smjg	uintptr_t v = SX_LOCK_UNLOCKED;
160170149Sattilio	int error = 0;
161170149Sattilio
162315378Smjg	if (__predict_false(LOCKSTAT_PROFILE_ENABLED(sx__acquire) ||
163315378Smjg	    !atomic_fcmpset_acq_ptr(&sx->sx_lock, &v, tid)))
164327413Smjg		error = _sx_xlock_hard(sx, v, opts);
165170149Sattilio
166170149Sattilio	return (error);
167170149Sattilio}
168170149Sattilio
169170149Sattilio/* Release an exclusive lock. */
170170149Sattiliostatic __inline void
171170149Sattilio__sx_xunlock(struct sx *sx, struct thread *td, const char *file, int line)
172170149Sattilio{
173327413Smjg	uintptr_t x = (uintptr_t)td;
174170149Sattilio
175315378Smjg	if (__predict_false(LOCKSTAT_PROFILE_ENABLED(sx__release) ||
176327413Smjg	    !atomic_fcmpset_rel_ptr(&sx->sx_lock, &x, SX_LOCK_UNLOCKED)))
177327413Smjg		_sx_xunlock_hard(sx, x);
178170149Sattilio}
179315378Smjg#endif
180170149Sattilio
181170149Sattilio/*
182168191Sjhb * Public interface for lock operations.
183168191Sjhb */
184168191Sjhb#ifndef LOCK_DEBUG
185168191Sjhb#error	"LOCK_DEBUG not defined, include <sys/lock.h> before <sys/sx.h>"
186168191Sjhb#endif
187168191Sjhb#if	(LOCK_DEBUG > 0) || defined(SX_NOINLINE)
188227788Sattilio#define	sx_xlock_(sx, file, line)					\
189227788Sattilio	(void)_sx_xlock((sx), 0, (file), (line))
190227788Sattilio#define	sx_xlock_sig_(sx, file, line)					\
191227788Sattilio	_sx_xlock((sx), SX_INTERRUPTIBLE, (file), (line))
192227788Sattilio#define	sx_xunlock_(sx, file, line)					\
193227788Sattilio	_sx_xunlock((sx), (file), (line))
194168191Sjhb#else
195227788Sattilio#define	sx_xlock_(sx, file, line)					\
196227788Sattilio	(void)__sx_xlock((sx), curthread, 0, (file), (line))
197227788Sattilio#define	sx_xlock_sig_(sx, file, line)					\
198227788Sattilio	__sx_xlock((sx), curthread, SX_INTERRUPTIBLE, (file), (line))
199227788Sattilio#define	sx_xunlock_(sx, file, line)					\
200227788Sattilio	__sx_xunlock((sx), curthread, (file), (line))
201315377Smjg#endif	/* LOCK_DEBUG > 0 || SX_NOINLINE */
202327413Smjg#if	(LOCK_DEBUG > 0)
203227788Sattilio#define	sx_slock_(sx, file, line)					\
204315377Smjg	(void)_sx_slock((sx), 0, (file), (line))
205227788Sattilio#define	sx_slock_sig_(sx, file, line)					\
206315377Smjg	_sx_slock((sx), SX_INTERRUPTIBLE, (file) , (line))
207227788Sattilio#define	sx_sunlock_(sx, file, line)					\
208315377Smjg	_sx_sunlock((sx), (file), (line))
209227788Sattilio#define	sx_try_slock(sx)	sx_try_slock_((sx), LOCK_FILE, LOCK_LINE)
210227788Sattilio#define	sx_try_xlock(sx)	sx_try_xlock_((sx), LOCK_FILE, LOCK_LINE)
211227788Sattilio#define	sx_try_upgrade(sx)	sx_try_upgrade_((sx), LOCK_FILE, LOCK_LINE)
212227788Sattilio#define	sx_downgrade(sx)	sx_downgrade_((sx), LOCK_FILE, LOCK_LINE)
213327413Smjg#else
214327413Smjg#define	sx_slock_(sx, file, line)					\
215327413Smjg	(void)_sx_slock_int((sx), 0)
216327413Smjg#define	sx_slock_sig_(sx, file, line)					\
217327413Smjg	_sx_slock_int((sx), SX_INTERRUPTIBLE)
218327413Smjg#define	sx_sunlock_(sx, file, line)					\
219327413Smjg	_sx_sunlock_int((sx))
220327413Smjg#define	sx_try_slock(sx)	sx_try_slock_int((sx))
221327413Smjg#define	sx_try_xlock(sx)	sx_try_xlock_int((sx))
222327413Smjg#define	sx_try_upgrade(sx)	sx_try_upgrade_int((sx))
223327413Smjg#define	sx_downgrade(sx)	sx_downgrade_int((sx))
224327413Smjg#endif
225227788Sattilio#ifdef INVARIANTS
226227788Sattilio#define	sx_assert_(sx, what, file, line)				\
227227788Sattilio	_sx_assert((sx), (what), (file), (line))
228227788Sattilio#else
229227788Sattilio#define	sx_assert_(sx, what, file, line)	(void)0
230227788Sattilio#endif
231168191Sjhb
232227788Sattilio#define	sx_xlock(sx)		sx_xlock_((sx), LOCK_FILE, LOCK_LINE)
233227788Sattilio#define	sx_xlock_sig(sx)	sx_xlock_sig_((sx), LOCK_FILE, LOCK_LINE)
234227788Sattilio#define	sx_xunlock(sx)		sx_xunlock_((sx), LOCK_FILE, LOCK_LINE)
235227788Sattilio#define	sx_slock(sx)		sx_slock_((sx), LOCK_FILE, LOCK_LINE)
236227788Sattilio#define	sx_slock_sig(sx)	sx_slock_sig_((sx), LOCK_FILE, LOCK_LINE)
237227788Sattilio#define	sx_sunlock(sx)		sx_sunlock_((sx), LOCK_FILE, LOCK_LINE)
238227788Sattilio#define	sx_assert(sx, what)	sx_assert_((sx), (what), __FILE__, __LINE__)
239227788Sattilio
240169776Sjhb/*
241169776Sjhb * Return a pointer to the owning thread if the lock is exclusively
242169776Sjhb * locked.
243169776Sjhb */
244169776Sjhb#define	sx_xholder(sx)							\
245169776Sjhb	((sx)->sx_lock & SX_LOCK_SHARED ? NULL :			\
246169776Sjhb	(struct thread *)SX_OWNER((sx)->sx_lock))
247169776Sjhb
248168191Sjhb#define	sx_xlocked(sx)							\
249168191Sjhb	(((sx)->sx_lock & ~(SX_LOCK_FLAGMASK & ~SX_LOCK_SHARED)) ==	\
250168191Sjhb	    (uintptr_t)curthread)
251168191Sjhb
252227788Sattilio#define	sx_unlock_(sx, file, line) do {					\
253159844Sjhb	if (sx_xlocked(sx))						\
254227788Sattilio		sx_xunlock_(sx, file, line);				\
255157296Sjhb	else								\
256227788Sattilio		sx_sunlock_(sx, file, line);				\
257157296Sjhb} while (0)
258168191Sjhb
259227788Sattilio#define	sx_unlock(sx)	sx_unlock_((sx), LOCK_FILE, LOCK_LINE)
260227788Sattilio
261167387Sjhb#define	sx_sleep(chan, sx, pri, wmesg, timo)				\
262247787Sdavide	_sleep((chan), &(sx)->lock_object, (pri), (wmesg),		\
263247787Sdavide	    tick_sbt * (timo), 0,  C_HARDCLOCK)
26474912Sjhb
265168191Sjhb/*
266168191Sjhb * Options passed to sx_init_flags().
267168191Sjhb */
268168191Sjhb#define	SX_DUPOK		0x01
269168191Sjhb#define	SX_NOPROFILE		0x02
270168191Sjhb#define	SX_NOWITNESS		0x04
271168191Sjhb#define	SX_QUIET		0x08
272193011Sattilio#define	SX_NOADAPTIVE		0x10
273169769Sjhb#define	SX_RECURSE		0x20
274275751Sdchagin#define	SX_NEW			0x40
275168191Sjhb
276170149Sattilio/*
277170149Sattilio * Options passed to sx_*lock_hard().
278170149Sattilio */
279170149Sattilio#define	SX_INTERRUPTIBLE	0x40
280170149Sattilio
28185412Sjhb#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
282169780Sjhb#define	SA_LOCKED		LA_LOCKED
283169780Sjhb#define	SA_SLOCKED		LA_SLOCKED
284169780Sjhb#define	SA_XLOCKED		LA_XLOCKED
285169780Sjhb#define	SA_UNLOCKED		LA_UNLOCKED
286169780Sjhb#define	SA_RECURSED		LA_RECURSED
287169780Sjhb#define	SA_NOTRECURSED		LA_NOTRECURSED
288169780Sjhb
289298981Spfg/* Backwards compatibility. */
29085388Sjhb#define	SX_LOCKED		LA_LOCKED
29185388Sjhb#define	SX_SLOCKED		LA_SLOCKED
29285388Sjhb#define	SX_XLOCKED		LA_XLOCKED
293125419Spjd#define	SX_UNLOCKED		LA_UNLOCKED
294168191Sjhb#define	SX_RECURSED		LA_RECURSED
295168191Sjhb#define	SX_NOTRECURSED		LA_NOTRECURSED
296125444Sbde#endif
29773863Sbmilekic
298125444Sbde#endif /* _KERNEL */
299125444Sbde
300125444Sbde#endif /* !_SYS_SX_H_ */
301