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: releng/10.3/sys/sys/sx.h 247787 2013-03-04 12:48:41Z davide $
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
89168191Sjhb/*
90168191Sjhb * Function prototipes.  Routines that start with an underscore are not part
91168191Sjhb * of the public interface and are wrappered with a macro.
92168191Sjhb */
9393672Sarrvoid	sx_sysinit(void *arg);
94168191Sjhb#define	sx_init(sx, desc)	sx_init_flags((sx), (desc), 0)
95168191Sjhbvoid	sx_init_flags(struct sx *sx, const char *description, int opts);
9673782Sjasonevoid	sx_destroy(struct sx *sx);
97227788Sattilioint	sx_try_slock_(struct sx *sx, const char *file, int line);
98227788Sattilioint	sx_try_xlock_(struct sx *sx, const char *file, int line);
99227788Sattilioint	sx_try_upgrade_(struct sx *sx, const char *file, int line);
100227788Sattiliovoid	sx_downgrade_(struct sx *sx, const char *file, int line);
101170149Sattilioint	_sx_slock(struct sx *sx, int opts, const char *file, int line);
102170149Sattilioint	_sx_xlock(struct sx *sx, int opts, const char *file, int line);
10374912Sjhbvoid	_sx_sunlock(struct sx *sx, const char *file, int line);
10474912Sjhbvoid	_sx_xunlock(struct sx *sx, const char *file, int line);
105170149Sattilioint	_sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts,
106170149Sattilio	    const char *file, int line);
107170149Sattilioint	_sx_slock_hard(struct sx *sx, int opts, const char *file, int line);
108168191Sjhbvoid	_sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int
109168191Sjhb	    line);
110168191Sjhbvoid	_sx_sunlock_hard(struct sx *sx, const char *file, int line);
111161721Sjhb#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
112227588Spjdvoid	_sx_assert(const struct sx *sx, int what, const char *file, int line);
11393688Sarr#endif
114161337Sjhb#ifdef DDB
115161337Sjhbint	sx_chain(struct thread *td, struct thread **ownerp);
116161337Sjhb#endif
11793672Sarr
11893672Sarrstruct sx_args {
11993672Sarr	struct sx 	*sa_sx;
12093672Sarr	const char	*sa_desc;
121219819Sjeff	int		sa_flags;
12293672Sarr};
12393672Sarr
124219819Sjeff#define	SX_SYSINIT_FLAGS(name, sxa, desc, flags)			\
12593672Sarr	static struct sx_args name##_args = {				\
126149739Sjhb		(sxa),							\
127219819Sjeff		(desc),							\
128219819Sjeff		(flags)							\
12993672Sarr	};								\
13093672Sarr	SYSINIT(name##_sx_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
131149739Sjhb	    sx_sysinit, &name##_args);					\
132149739Sjhb	SYSUNINIT(name##_sx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
133149739Sjhb	    sx_destroy, (sxa))
13473782Sjasone
135219819Sjeff#define	SX_SYSINIT(name, sxa, desc)	SX_SYSINIT_FLAGS(name, sxa, desc, 0)
136219819Sjeff
137168191Sjhb/*
138170149Sattilio * Full lock operations that are suitable to be inlined in non-debug kernels.
139170149Sattilio * If the lock can't be acquired or released trivially then the work is
140170149Sattilio * deferred to 'tougher' functions.
141170149Sattilio */
142170149Sattilio
143170149Sattilio/* Acquire an exclusive lock. */
144170149Sattiliostatic __inline int
145170149Sattilio__sx_xlock(struct sx *sx, struct thread *td, int opts, const char *file,
146170149Sattilio    int line)
147170149Sattilio{
148170149Sattilio	uintptr_t tid = (uintptr_t)td;
149170149Sattilio	int error = 0;
150170149Sattilio
151170149Sattilio	if (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid))
152170149Sattilio		error = _sx_xlock_hard(sx, tid, opts, file, line);
153192853Ssson	else
154192853Ssson		LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_XLOCK_ACQUIRE,
155192853Ssson		    sx, 0, 0, file, line);
156170149Sattilio
157170149Sattilio	return (error);
158170149Sattilio}
159170149Sattilio
160170149Sattilio/* Release an exclusive lock. */
161170149Sattiliostatic __inline void
162170149Sattilio__sx_xunlock(struct sx *sx, struct thread *td, const char *file, int line)
163170149Sattilio{
164170149Sattilio	uintptr_t tid = (uintptr_t)td;
165170149Sattilio
166170149Sattilio	if (!atomic_cmpset_rel_ptr(&sx->sx_lock, tid, SX_LOCK_UNLOCKED))
167170149Sattilio		_sx_xunlock_hard(sx, tid, file, line);
168170149Sattilio}
169170149Sattilio
170170149Sattilio/* Acquire a shared lock. */
171170149Sattiliostatic __inline int
172170149Sattilio__sx_slock(struct sx *sx, int opts, const char *file, int line)
173170149Sattilio{
174170149Sattilio	uintptr_t x = sx->sx_lock;
175170149Sattilio	int error = 0;
176170149Sattilio
177170149Sattilio	if (!(x & SX_LOCK_SHARED) ||
178170149Sattilio	    !atomic_cmpset_acq_ptr(&sx->sx_lock, x, x + SX_ONE_SHARER))
179170149Sattilio		error = _sx_slock_hard(sx, opts, file, line);
180174629Sjeff	else
181192853Ssson		LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_SLOCK_ACQUIRE, sx, 0,
182192853Ssson		    0, file, line);
183170149Sattilio
184170149Sattilio	return (error);
185170149Sattilio}
186170149Sattilio
187170149Sattilio/*
188170149Sattilio * Release a shared lock.  We can just drop a single shared lock so
189170149Sattilio * long as we aren't trying to drop the last shared lock when other
190170149Sattilio * threads are waiting for an exclusive lock.  This takes advantage of
191170149Sattilio * the fact that an unlocked lock is encoded as a shared lock with a
192170149Sattilio * count of 0.
193170149Sattilio */
194170149Sattiliostatic __inline void
195170149Sattilio__sx_sunlock(struct sx *sx, const char *file, int line)
196170149Sattilio{
197170149Sattilio	uintptr_t x = sx->sx_lock;
198170149Sattilio
199170149Sattilio	if (x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS) ||
200197643Sattilio	    !atomic_cmpset_rel_ptr(&sx->sx_lock, x, x - SX_ONE_SHARER))
201170149Sattilio		_sx_sunlock_hard(sx, file, line);
202170149Sattilio}
203170149Sattilio
204170149Sattilio/*
205168191Sjhb * Public interface for lock operations.
206168191Sjhb */
207168191Sjhb#ifndef LOCK_DEBUG
208168191Sjhb#error	"LOCK_DEBUG not defined, include <sys/lock.h> before <sys/sx.h>"
209168191Sjhb#endif
210168191Sjhb#if	(LOCK_DEBUG > 0) || defined(SX_NOINLINE)
211227788Sattilio#define	sx_xlock_(sx, file, line)					\
212227788Sattilio	(void)_sx_xlock((sx), 0, (file), (line))
213227788Sattilio#define	sx_xlock_sig_(sx, file, line)					\
214227788Sattilio	_sx_xlock((sx), SX_INTERRUPTIBLE, (file), (line))
215227788Sattilio#define	sx_xunlock_(sx, file, line)					\
216227788Sattilio	_sx_xunlock((sx), (file), (line))
217227788Sattilio#define	sx_slock_(sx, file, line)					\
218227788Sattilio	(void)_sx_slock((sx), 0, (file), (line))
219227788Sattilio#define	sx_slock_sig_(sx, file, line)					\
220227788Sattilio	_sx_slock((sx), SX_INTERRUPTIBLE, (file) , (line))
221227788Sattilio#define	sx_sunlock_(sx, file, line)					\
222227788Sattilio	_sx_sunlock((sx), (file), (line))
223168191Sjhb#else
224227788Sattilio#define	sx_xlock_(sx, file, line)					\
225227788Sattilio	(void)__sx_xlock((sx), curthread, 0, (file), (line))
226227788Sattilio#define	sx_xlock_sig_(sx, file, line)					\
227227788Sattilio	__sx_xlock((sx), curthread, SX_INTERRUPTIBLE, (file), (line))
228227788Sattilio#define	sx_xunlock_(sx, file, line)					\
229227788Sattilio	__sx_xunlock((sx), curthread, (file), (line))
230227788Sattilio#define	sx_slock_(sx, file, line)					\
231227788Sattilio	(void)__sx_slock((sx), 0, (file), (line))
232227788Sattilio#define	sx_slock_sig_(sx, file, line)					\
233227788Sattilio	__sx_slock((sx), SX_INTERRUPTIBLE, (file), (line))
234227788Sattilio#define	sx_sunlock_(sx, file, line)					\
235227788Sattilio	__sx_sunlock((sx), (file), (line))
236168191Sjhb#endif	/* LOCK_DEBUG > 0 || SX_NOINLINE */
237227788Sattilio#define	sx_try_slock(sx)	sx_try_slock_((sx), LOCK_FILE, LOCK_LINE)
238227788Sattilio#define	sx_try_xlock(sx)	sx_try_xlock_((sx), LOCK_FILE, LOCK_LINE)
239227788Sattilio#define	sx_try_upgrade(sx)	sx_try_upgrade_((sx), LOCK_FILE, LOCK_LINE)
240227788Sattilio#define	sx_downgrade(sx)	sx_downgrade_((sx), LOCK_FILE, LOCK_LINE)
241227788Sattilio#ifdef INVARIANTS
242227788Sattilio#define	sx_assert_(sx, what, file, line)				\
243227788Sattilio	_sx_assert((sx), (what), (file), (line))
244227788Sattilio#else
245227788Sattilio#define	sx_assert_(sx, what, file, line)	(void)0
246227788Sattilio#endif
247168191Sjhb
248227788Sattilio#define	sx_xlock(sx)		sx_xlock_((sx), LOCK_FILE, LOCK_LINE)
249227788Sattilio#define	sx_xlock_sig(sx)	sx_xlock_sig_((sx), LOCK_FILE, LOCK_LINE)
250227788Sattilio#define	sx_xunlock(sx)		sx_xunlock_((sx), LOCK_FILE, LOCK_LINE)
251227788Sattilio#define	sx_slock(sx)		sx_slock_((sx), LOCK_FILE, LOCK_LINE)
252227788Sattilio#define	sx_slock_sig(sx)	sx_slock_sig_((sx), LOCK_FILE, LOCK_LINE)
253227788Sattilio#define	sx_sunlock(sx)		sx_sunlock_((sx), LOCK_FILE, LOCK_LINE)
254227788Sattilio#define	sx_assert(sx, what)	sx_assert_((sx), (what), __FILE__, __LINE__)
255227788Sattilio
256169776Sjhb/*
257169776Sjhb * Return a pointer to the owning thread if the lock is exclusively
258169776Sjhb * locked.
259169776Sjhb */
260169776Sjhb#define	sx_xholder(sx)							\
261169776Sjhb	((sx)->sx_lock & SX_LOCK_SHARED ? NULL :			\
262169776Sjhb	(struct thread *)SX_OWNER((sx)->sx_lock))
263169776Sjhb
264168191Sjhb#define	sx_xlocked(sx)							\
265168191Sjhb	(((sx)->sx_lock & ~(SX_LOCK_FLAGMASK & ~SX_LOCK_SHARED)) ==	\
266168191Sjhb	    (uintptr_t)curthread)
267168191Sjhb
268227788Sattilio#define	sx_unlock_(sx, file, line) do {					\
269159844Sjhb	if (sx_xlocked(sx))						\
270227788Sattilio		sx_xunlock_(sx, file, line);				\
271157296Sjhb	else								\
272227788Sattilio		sx_sunlock_(sx, file, line);				\
273157296Sjhb} while (0)
274168191Sjhb
275227788Sattilio#define	sx_unlock(sx)	sx_unlock_((sx), LOCK_FILE, LOCK_LINE)
276227788Sattilio
277167387Sjhb#define	sx_sleep(chan, sx, pri, wmesg, timo)				\
278247787Sdavide	_sleep((chan), &(sx)->lock_object, (pri), (wmesg),		\
279247787Sdavide	    tick_sbt * (timo), 0,  C_HARDCLOCK)
28074912Sjhb
281168191Sjhb/*
282168191Sjhb * Options passed to sx_init_flags().
283168191Sjhb */
284168191Sjhb#define	SX_DUPOK		0x01
285168191Sjhb#define	SX_NOPROFILE		0x02
286168191Sjhb#define	SX_NOWITNESS		0x04
287168191Sjhb#define	SX_QUIET		0x08
288193011Sattilio#define	SX_NOADAPTIVE		0x10
289169769Sjhb#define	SX_RECURSE		0x20
290168191Sjhb
291170149Sattilio/*
292170149Sattilio * Options passed to sx_*lock_hard().
293170149Sattilio */
294170149Sattilio#define	SX_INTERRUPTIBLE	0x40
295170149Sattilio
29685412Sjhb#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
297169780Sjhb#define	SA_LOCKED		LA_LOCKED
298169780Sjhb#define	SA_SLOCKED		LA_SLOCKED
299169780Sjhb#define	SA_XLOCKED		LA_XLOCKED
300169780Sjhb#define	SA_UNLOCKED		LA_UNLOCKED
301169780Sjhb#define	SA_RECURSED		LA_RECURSED
302169780Sjhb#define	SA_NOTRECURSED		LA_NOTRECURSED
303169780Sjhb
304169780Sjhb/* Backwards compatability. */
30585388Sjhb#define	SX_LOCKED		LA_LOCKED
30685388Sjhb#define	SX_SLOCKED		LA_SLOCKED
30785388Sjhb#define	SX_XLOCKED		LA_XLOCKED
308125419Spjd#define	SX_UNLOCKED		LA_UNLOCKED
309168191Sjhb#define	SX_RECURSED		LA_RECURSED
310168191Sjhb#define	SX_NOTRECURSED		LA_NOTRECURSED
311125444Sbde#endif
31273863Sbmilekic
313125444Sbde#endif /* _KERNEL */
314125444Sbde
315125444Sbde#endif /* !_SYS_SX_H_ */
316