kern_sx.c revision 171277
1/*-
2 * Copyright (c) 2007 Attilio Rao <attilio@freebsd.org>
3 * Copyright (c) 2001 Jason Evans <jasone@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice(s), this list of conditions and the following disclaimer as
11 *    the first lines of this file unmodified other than the possible
12 *    addition of one or more copyright notices.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice(s), this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 * DAMAGE.
28 */
29
30/*
31 * Shared/exclusive locks.  This implementation attempts to ensure
32 * deterministic lock granting behavior, so that slocks and xlocks are
33 * interleaved.
34 *
35 * Priority propagation will not generally raise the priority of lock holders,
36 * so should not be relied upon in combination with sx locks.
37 */
38
39#include "opt_adaptive_sx.h"
40#include "opt_ddb.h"
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/sys/kern/kern_sx.c 171277 2007-07-06 13:20:44Z attilio $");
44
45#include <sys/param.h>
46#include <sys/ktr.h>
47#include <sys/lock.h>
48#include <sys/mutex.h>
49#include <sys/proc.h>
50#include <sys/sleepqueue.h>
51#include <sys/sx.h>
52#include <sys/systm.h>
53
54#ifdef ADAPTIVE_SX
55#include <machine/cpu.h>
56#endif
57
58#ifdef DDB
59#include <ddb/ddb.h>
60#endif
61
62#if !defined(SMP) && defined(ADAPTIVE_SX)
63#error "You must have SMP to enable the ADAPTIVE_SX option"
64#endif
65
66CTASSERT(((SX_ADAPTIVESPIN | SX_RECURSE) & LO_CLASSFLAGS) ==
67    (SX_ADAPTIVESPIN | SX_RECURSE));
68
69/* Handy macros for sleep queues. */
70#define	SQ_EXCLUSIVE_QUEUE	0
71#define	SQ_SHARED_QUEUE		1
72
73/*
74 * Variations on DROP_GIANT()/PICKUP_GIANT() for use in this file.  We
75 * drop Giant anytime we have to sleep or if we adaptively spin.
76 */
77#define	GIANT_DECLARE							\
78	int _giantcnt = 0;						\
79	WITNESS_SAVE_DECL(Giant)					\
80
81#define	GIANT_SAVE() do {						\
82	if (mtx_owned(&Giant)) {					\
83		WITNESS_SAVE(&Giant.lock_object, Giant);		\
84		while (mtx_owned(&Giant)) {				\
85			_giantcnt++;					\
86			mtx_unlock(&Giant);				\
87		}							\
88	}								\
89} while (0)
90
91#define GIANT_RESTORE() do {						\
92	if (_giantcnt > 0) {						\
93		mtx_assert(&Giant, MA_NOTOWNED);			\
94		while (_giantcnt--)					\
95			mtx_lock(&Giant);				\
96		WITNESS_RESTORE(&Giant.lock_object, Giant);		\
97	}								\
98} while (0)
99
100/*
101 * Returns true if an exclusive lock is recursed.  It assumes
102 * curthread currently has an exclusive lock.
103 */
104#define	sx_recursed(sx)		((sx)->sx_recurse != 0)
105
106#ifdef DDB
107static void	db_show_sx(struct lock_object *lock);
108#endif
109static void	lock_sx(struct lock_object *lock, int how);
110static int	unlock_sx(struct lock_object *lock);
111
112struct lock_class lock_class_sx = {
113	.lc_name = "sx",
114	.lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
115#ifdef DDB
116	.lc_ddb_show = db_show_sx,
117#endif
118	.lc_lock = lock_sx,
119	.lc_unlock = unlock_sx,
120};
121
122#ifndef INVARIANTS
123#define	_sx_assert(sx, what, file, line)
124#endif
125
126void
127lock_sx(struct lock_object *lock, int how)
128{
129	struct sx *sx;
130
131	sx = (struct sx *)lock;
132	if (how)
133		sx_xlock(sx);
134	else
135		sx_slock(sx);
136}
137
138int
139unlock_sx(struct lock_object *lock)
140{
141	struct sx *sx;
142
143	sx = (struct sx *)lock;
144	sx_assert(sx, SA_LOCKED | SA_NOTRECURSED);
145	if (sx_xlocked(sx)) {
146		sx_xunlock(sx);
147		return (1);
148	} else {
149		sx_sunlock(sx);
150		return (0);
151	}
152}
153
154void
155sx_sysinit(void *arg)
156{
157	struct sx_args *sargs = arg;
158
159	sx_init(sargs->sa_sx, sargs->sa_desc);
160}
161
162void
163sx_init_flags(struct sx *sx, const char *description, int opts)
164{
165	int flags;
166
167	MPASS((opts & ~(SX_QUIET | SX_RECURSE | SX_NOWITNESS | SX_DUPOK |
168	    SX_NOPROFILE | SX_ADAPTIVESPIN)) == 0);
169
170	flags = LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE;
171	if (opts & SX_DUPOK)
172		flags |= LO_DUPOK;
173	if (opts & SX_NOPROFILE)
174		flags |= LO_NOPROFILE;
175	if (!(opts & SX_NOWITNESS))
176		flags |= LO_WITNESS;
177	if (opts & SX_QUIET)
178		flags |= LO_QUIET;
179
180	flags |= opts & (SX_ADAPTIVESPIN | SX_RECURSE);
181	sx->sx_lock = SX_LOCK_UNLOCKED;
182	sx->sx_recurse = 0;
183	lock_init(&sx->lock_object, &lock_class_sx, description, NULL, flags);
184}
185
186void
187sx_destroy(struct sx *sx)
188{
189
190	KASSERT(sx->sx_lock == SX_LOCK_UNLOCKED, ("sx lock still held"));
191	KASSERT(sx->sx_recurse == 0, ("sx lock still recursed"));
192	sx->sx_lock = SX_LOCK_DESTROYED;
193	lock_destroy(&sx->lock_object);
194}
195
196int
197_sx_slock(struct sx *sx, int opts, const char *file, int line)
198{
199	int error = 0;
200
201	MPASS(curthread != NULL);
202	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
203	    ("sx_slock() of destroyed sx @ %s:%d", file, line));
204	WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line);
205	error = __sx_slock(sx, opts, file, line);
206	if (!error) {
207		LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line);
208		WITNESS_LOCK(&sx->lock_object, 0, file, line);
209		curthread->td_locks++;
210	}
211
212	return (error);
213}
214
215int
216_sx_try_slock(struct sx *sx, const char *file, int line)
217{
218	uintptr_t x;
219
220	x = sx->sx_lock;
221	KASSERT(x != SX_LOCK_DESTROYED,
222	    ("sx_try_slock() of destroyed sx @ %s:%d", file, line));
223	if ((x & SX_LOCK_SHARED) && atomic_cmpset_acq_ptr(&sx->sx_lock, x,
224	    x + SX_ONE_SHARER)) {
225		LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line);
226		WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line);
227		curthread->td_locks++;
228		return (1);
229	}
230
231	LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 0, file, line);
232	return (0);
233}
234
235int
236_sx_xlock(struct sx *sx, int opts, const char *file, int line)
237{
238	int error = 0;
239
240	MPASS(curthread != NULL);
241	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
242	    ("sx_xlock() of destroyed sx @ %s:%d", file, line));
243	WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
244	    line);
245	error = __sx_xlock(sx, curthread, opts, file, line);
246	if (!error) {
247		LOCK_LOG_LOCK("XLOCK", &sx->lock_object, 0, sx->sx_recurse,
248		    file, line);
249		WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
250		curthread->td_locks++;
251	}
252
253	return (error);
254}
255
256int
257_sx_try_xlock(struct sx *sx, const char *file, int line)
258{
259	int rval;
260
261	MPASS(curthread != NULL);
262	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
263	    ("sx_try_xlock() of destroyed sx @ %s:%d", file, line));
264
265	if (sx_xlocked(sx) && (sx->lock_object.lo_flags & SX_RECURSE) != 0) {
266		sx->sx_recurse++;
267		atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
268		rval = 1;
269	} else
270		rval = atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED,
271		    (uintptr_t)curthread);
272	LOCK_LOG_TRY("XLOCK", &sx->lock_object, 0, rval, file, line);
273	if (rval) {
274		WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
275		    file, line);
276		curthread->td_locks++;
277	}
278
279	return (rval);
280}
281
282void
283_sx_sunlock(struct sx *sx, const char *file, int line)
284{
285
286	MPASS(curthread != NULL);
287	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
288	    ("sx_sunlock() of destroyed sx @ %s:%d", file, line));
289	_sx_assert(sx, SA_SLOCKED, file, line);
290	curthread->td_locks--;
291	WITNESS_UNLOCK(&sx->lock_object, 0, file, line);
292	LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line);
293#ifdef LOCK_PROFILING_SHARED
294	if (SX_SHARERS(sx->sx_lock) == 1)
295		lock_profile_release_lock(&sx->lock_object);
296#endif
297	__sx_sunlock(sx, file, line);
298}
299
300void
301_sx_xunlock(struct sx *sx, const char *file, int line)
302{
303
304	MPASS(curthread != NULL);
305	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
306	    ("sx_xunlock() of destroyed sx @ %s:%d", file, line));
307	_sx_assert(sx, SA_XLOCKED, file, line);
308	curthread->td_locks--;
309	WITNESS_UNLOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
310	LOCK_LOG_LOCK("XUNLOCK", &sx->lock_object, 0, sx->sx_recurse, file,
311	    line);
312	if (!sx_recursed(sx))
313		lock_profile_release_lock(&sx->lock_object);
314	__sx_xunlock(sx, curthread, file, line);
315}
316
317/*
318 * Try to do a non-blocking upgrade from a shared lock to an exclusive lock.
319 * This will only succeed if this thread holds a single shared lock.
320 * Return 1 if if the upgrade succeed, 0 otherwise.
321 */
322int
323_sx_try_upgrade(struct sx *sx, const char *file, int line)
324{
325	uintptr_t x;
326	int success;
327
328	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
329	    ("sx_try_upgrade() of destroyed sx @ %s:%d", file, line));
330	_sx_assert(sx, SA_SLOCKED, file, line);
331
332	/*
333	 * Try to switch from one shared lock to an exclusive lock.  We need
334	 * to maintain the SX_LOCK_EXCLUSIVE_WAITERS flag if set so that
335	 * we will wake up the exclusive waiters when we drop the lock.
336	 */
337	x = sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS;
338	success = atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x,
339	    (uintptr_t)curthread | x);
340	LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line);
341	if (success)
342		WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
343		    file, line);
344	return (success);
345}
346
347/*
348 * Downgrade an unrecursed exclusive lock into a single shared lock.
349 */
350void
351_sx_downgrade(struct sx *sx, const char *file, int line)
352{
353	uintptr_t x;
354
355	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
356	    ("sx_downgrade() of destroyed sx @ %s:%d", file, line));
357	_sx_assert(sx, SA_XLOCKED | SA_NOTRECURSED, file, line);
358#ifndef INVARIANTS
359	if (sx_recursed(sx))
360		panic("downgrade of a recursed lock");
361#endif
362
363	WITNESS_DOWNGRADE(&sx->lock_object, 0, file, line);
364
365	/*
366	 * Try to switch from an exclusive lock with no shared waiters
367	 * to one sharer with no shared waiters.  If there are
368	 * exclusive waiters, we don't need to lock the sleep queue so
369	 * long as we preserve the flag.  We do one quick try and if
370	 * that fails we grab the sleepq lock to keep the flags from
371	 * changing and do it the slow way.
372	 *
373	 * We have to lock the sleep queue if there are shared waiters
374	 * so we can wake them up.
375	 */
376	x = sx->sx_lock;
377	if (!(x & SX_LOCK_SHARED_WAITERS) &&
378	    atomic_cmpset_rel_ptr(&sx->sx_lock, x, SX_SHARERS_LOCK(1) |
379	    (x & SX_LOCK_EXCLUSIVE_WAITERS))) {
380		LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
381		return;
382	}
383
384	/*
385	 * Lock the sleep queue so we can read the waiters bits
386	 * without any races and wakeup any shared waiters.
387	 */
388	sleepq_lock(&sx->lock_object);
389
390	/*
391	 * Preserve SX_LOCK_EXCLUSIVE_WAITERS while downgraded to a single
392	 * shared lock.  If there are any shared waiters, wake them up.
393	 */
394	x = sx->sx_lock;
395	atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) |
396	    (x & SX_LOCK_EXCLUSIVE_WAITERS));
397	if (x & SX_LOCK_SHARED_WAITERS)
398		sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, -1,
399		    SQ_SHARED_QUEUE);
400	else
401		sleepq_release(&sx->lock_object);
402
403	LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
404}
405
406/*
407 * This function represents the so-called 'hard case' for sx_xlock
408 * operation.  All 'easy case' failures are redirected to this.  Note
409 * that ideally this would be a static function, but it needs to be
410 * accessible from at least sx.h.
411 */
412int
413_sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
414    int line)
415{
416	GIANT_DECLARE;
417#ifdef ADAPTIVE_SX
418	volatile struct thread *owner;
419#endif
420	uint64_t waittime = 0;
421	uintptr_t x;
422	int contested = 0, error = 0;
423
424	/* If we already hold an exclusive lock, then recurse. */
425	if (sx_xlocked(sx)) {
426		KASSERT((sx->lock_object.lo_flags & SX_RECURSE) != 0,
427	    ("_sx_xlock_hard: recursed on non-recursive sx %s @ %s:%d\n",
428		    sx->lock_object.lo_name, file, line));
429		sx->sx_recurse++;
430		atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
431		if (LOCK_LOG_TEST(&sx->lock_object, 0))
432			CTR2(KTR_LOCK, "%s: %p recursing", __func__, sx);
433		return (0);
434	}
435
436	if (LOCK_LOG_TEST(&sx->lock_object, 0))
437		CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
438		    sx->lock_object.lo_name, (void *)sx->sx_lock, file, line);
439
440	while (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid)) {
441#ifdef ADAPTIVE_SX
442		/*
443		 * If the lock is write locked and the owner is
444		 * running on another CPU, spin until the owner stops
445		 * running or the state of the lock changes.
446		 */
447		x = sx->sx_lock;
448		if (!(x & SX_LOCK_SHARED) &&
449		    (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
450			x = SX_OWNER(x);
451			owner = (struct thread *)x;
452			if (TD_IS_RUNNING(owner)) {
453				if (LOCK_LOG_TEST(&sx->lock_object, 0))
454					CTR3(KTR_LOCK,
455					    "%s: spinning on %p held by %p",
456					    __func__, sx, owner);
457				GIANT_SAVE();
458				lock_profile_obtain_lock_failed(
459				    &sx->lock_object, &contested, &waittime);
460				while (SX_OWNER(sx->sx_lock) == x &&
461				    TD_IS_RUNNING(owner))
462					cpu_spinwait();
463				continue;
464			}
465		}
466#endif
467
468		sleepq_lock(&sx->lock_object);
469		x = sx->sx_lock;
470
471		/*
472		 * If the lock was released while spinning on the
473		 * sleep queue chain lock, try again.
474		 */
475		if (x == SX_LOCK_UNLOCKED) {
476			sleepq_release(&sx->lock_object);
477			continue;
478		}
479
480#ifdef ADAPTIVE_SX
481		/*
482		 * The current lock owner might have started executing
483		 * on another CPU (or the lock could have changed
484		 * owners) while we were waiting on the sleep queue
485		 * chain lock.  If so, drop the sleep queue lock and try
486		 * again.
487		 */
488		if (!(x & SX_LOCK_SHARED) &&
489		    (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
490			owner = (struct thread *)SX_OWNER(x);
491			if (TD_IS_RUNNING(owner)) {
492				sleepq_release(&sx->lock_object);
493				continue;
494			}
495		}
496#endif
497
498		/*
499		 * If an exclusive lock was released with both shared
500		 * and exclusive waiters and a shared waiter hasn't
501		 * woken up and acquired the lock yet, sx_lock will be
502		 * set to SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS.
503		 * If we see that value, try to acquire it once.  Note
504		 * that we have to preserve SX_LOCK_EXCLUSIVE_WAITERS
505		 * as there are other exclusive waiters still.  If we
506		 * fail, restart the loop.
507		 */
508		if (x == (SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS)) {
509			if (atomic_cmpset_acq_ptr(&sx->sx_lock,
510			    SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS,
511			    tid | SX_LOCK_EXCLUSIVE_WAITERS)) {
512				sleepq_release(&sx->lock_object);
513				CTR2(KTR_LOCK, "%s: %p claimed by new writer",
514				    __func__, sx);
515				break;
516			}
517			sleepq_release(&sx->lock_object);
518			continue;
519		}
520
521		/*
522		 * Try to set the SX_LOCK_EXCLUSIVE_WAITERS.  If we fail,
523		 * than loop back and retry.
524		 */
525		if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
526			if (!atomic_cmpset_ptr(&sx->sx_lock, x,
527			    x | SX_LOCK_EXCLUSIVE_WAITERS)) {
528				sleepq_release(&sx->lock_object);
529				continue;
530			}
531			if (LOCK_LOG_TEST(&sx->lock_object, 0))
532				CTR2(KTR_LOCK, "%s: %p set excl waiters flag",
533				    __func__, sx);
534		}
535
536		/*
537		 * Since we have been unable to acquire the exclusive
538		 * lock and the exclusive waiters flag is set, we have
539		 * to sleep.
540		 */
541		if (LOCK_LOG_TEST(&sx->lock_object, 0))
542			CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
543			    __func__, sx);
544
545		GIANT_SAVE();
546		lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
547		    &waittime);
548		sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
549		    SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
550		    SLEEPQ_INTERRUPTIBLE : 0), SQ_EXCLUSIVE_QUEUE);
551		if (!(opts & SX_INTERRUPTIBLE))
552			sleepq_wait(&sx->lock_object);
553		else
554			error = sleepq_wait_sig(&sx->lock_object);
555
556		if (error) {
557			if (LOCK_LOG_TEST(&sx->lock_object, 0))
558				CTR2(KTR_LOCK,
559			"%s: interruptible sleep by %p suspended by signal",
560				    __func__, sx);
561			break;
562		}
563		if (LOCK_LOG_TEST(&sx->lock_object, 0))
564			CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
565			    __func__, sx);
566	}
567
568	GIANT_RESTORE();
569	if (!error)
570		lock_profile_obtain_lock_success(&sx->lock_object, contested,
571		    waittime, file, line);
572	return (error);
573}
574
575/*
576 * This function represents the so-called 'hard case' for sx_xunlock
577 * operation.  All 'easy case' failures are redirected to this.  Note
578 * that ideally this would be a static function, but it needs to be
579 * accessible from at least sx.h.
580 */
581void
582_sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line)
583{
584	uintptr_t x;
585	int queue;
586
587	MPASS(!(sx->sx_lock & SX_LOCK_SHARED));
588
589	/* If the lock is recursed, then unrecurse one level. */
590	if (sx_xlocked(sx) && sx_recursed(sx)) {
591		if ((--sx->sx_recurse) == 0)
592			atomic_clear_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
593		if (LOCK_LOG_TEST(&sx->lock_object, 0))
594			CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, sx);
595		return;
596	}
597	MPASS(sx->sx_lock & (SX_LOCK_SHARED_WAITERS |
598	    SX_LOCK_EXCLUSIVE_WAITERS));
599	if (LOCK_LOG_TEST(&sx->lock_object, 0))
600		CTR2(KTR_LOCK, "%s: %p contested", __func__, sx);
601
602	sleepq_lock(&sx->lock_object);
603	x = SX_LOCK_UNLOCKED;
604
605	/*
606	 * The wake up algorithm here is quite simple and probably not
607	 * ideal.  It gives precedence to shared waiters if they are
608	 * present.  For this condition, we have to preserve the
609	 * state of the exclusive waiters flag.
610	 */
611	if (sx->sx_lock & SX_LOCK_SHARED_WAITERS) {
612		queue = SQ_SHARED_QUEUE;
613		x |= (sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS);
614	} else
615		queue = SQ_EXCLUSIVE_QUEUE;
616
617	/* Wake up all the waiters for the specific queue. */
618	if (LOCK_LOG_TEST(&sx->lock_object, 0))
619		CTR3(KTR_LOCK, "%s: %p waking up all threads on %s queue",
620		    __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" :
621		    "exclusive");
622	atomic_store_rel_ptr(&sx->sx_lock, x);
623	sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, -1, queue);
624}
625
626/*
627 * This function represents the so-called 'hard case' for sx_slock
628 * operation.  All 'easy case' failures are redirected to this.  Note
629 * that ideally this would be a static function, but it needs to be
630 * accessible from at least sx.h.
631 */
632int
633_sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
634{
635	GIANT_DECLARE;
636#ifdef ADAPTIVE_SX
637	volatile struct thread *owner;
638#endif
639#ifdef LOCK_PROFILING_SHARED
640	uint64_t waittime = 0;
641	int contested = 0;
642#endif
643	uintptr_t x;
644	int error = 0;
645
646	/*
647	 * As with rwlocks, we don't make any attempt to try to block
648	 * shared locks once there is an exclusive waiter.
649	 */
650	for (;;) {
651		x = sx->sx_lock;
652
653		/*
654		 * If no other thread has an exclusive lock then try to bump up
655		 * the count of sharers.  Since we have to preserve the state
656		 * of SX_LOCK_EXCLUSIVE_WAITERS, if we fail to acquire the
657		 * shared lock loop back and retry.
658		 */
659		if (x & SX_LOCK_SHARED) {
660			MPASS(!(x & SX_LOCK_SHARED_WAITERS));
661			if (atomic_cmpset_acq_ptr(&sx->sx_lock, x,
662			    x + SX_ONE_SHARER)) {
663#ifdef LOCK_PROFILING_SHARED
664				if (SX_SHARERS(x) == 0)
665					lock_profile_obtain_lock_success(
666					    &sx->lock_object, contested,
667					    waittime, file, line);
668#endif
669				if (LOCK_LOG_TEST(&sx->lock_object, 0))
670					CTR4(KTR_LOCK,
671					    "%s: %p succeed %p -> %p", __func__,
672					    sx, (void *)x,
673					    (void *)(x + SX_ONE_SHARER));
674				break;
675			}
676			continue;
677		}
678
679#ifdef ADAPTIVE_SX
680		/*
681		 * If the owner is running on another CPU, spin until
682		 * the owner stops running or the state of the lock
683		 * changes.
684		 */
685		else if (sx->lock_object.lo_flags & SX_ADAPTIVESPIN) {
686			x = SX_OWNER(x);
687			owner = (struct thread *)x;
688			if (TD_IS_RUNNING(owner)) {
689				if (LOCK_LOG_TEST(&sx->lock_object, 0))
690					CTR3(KTR_LOCK,
691					    "%s: spinning on %p held by %p",
692					    __func__, sx, owner);
693				GIANT_SAVE();
694#ifdef LOCK_PROFILING_SHARED
695				lock_profile_obtain_lock_failed(
696				    &sx->lock_object, &contested, &waittime);
697#endif
698				while (SX_OWNER(sx->sx_lock) == x &&
699				    TD_IS_RUNNING(owner))
700					cpu_spinwait();
701				continue;
702			}
703		}
704#endif
705
706		/*
707		 * Some other thread already has an exclusive lock, so
708		 * start the process of blocking.
709		 */
710		sleepq_lock(&sx->lock_object);
711		x = sx->sx_lock;
712
713		/*
714		 * The lock could have been released while we spun.
715		 * In this case loop back and retry.
716		 */
717		if (x & SX_LOCK_SHARED) {
718			sleepq_release(&sx->lock_object);
719			continue;
720		}
721
722#ifdef ADAPTIVE_SX
723		/*
724		 * If the owner is running on another CPU, spin until
725		 * the owner stops running or the state of the lock
726		 * changes.
727		 */
728		if (!(x & SX_LOCK_SHARED) &&
729		    (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
730			owner = (struct thread *)SX_OWNER(x);
731			if (TD_IS_RUNNING(owner)) {
732				sleepq_release(&sx->lock_object);
733				continue;
734			}
735		}
736#endif
737
738		/*
739		 * Try to set the SX_LOCK_SHARED_WAITERS flag.  If we
740		 * fail to set it drop the sleep queue lock and loop
741		 * back.
742		 */
743		if (!(x & SX_LOCK_SHARED_WAITERS)) {
744			if (!atomic_cmpset_ptr(&sx->sx_lock, x,
745			    x | SX_LOCK_SHARED_WAITERS)) {
746				sleepq_release(&sx->lock_object);
747				continue;
748			}
749			if (LOCK_LOG_TEST(&sx->lock_object, 0))
750				CTR2(KTR_LOCK, "%s: %p set shared waiters flag",
751				    __func__, sx);
752		}
753
754		/*
755		 * Since we have been unable to acquire the shared lock,
756		 * we have to sleep.
757		 */
758		if (LOCK_LOG_TEST(&sx->lock_object, 0))
759			CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
760			    __func__, sx);
761
762		GIANT_SAVE();
763#ifdef LOCK_PROFILING_SHARED
764		lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
765		    &waittime);
766#endif
767		sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
768		    SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
769		    SLEEPQ_INTERRUPTIBLE : 0), SQ_SHARED_QUEUE);
770		if (!(opts & SX_INTERRUPTIBLE))
771			sleepq_wait(&sx->lock_object);
772		else
773			error = sleepq_wait_sig(&sx->lock_object);
774
775		if (error) {
776			if (LOCK_LOG_TEST(&sx->lock_object, 0))
777				CTR2(KTR_LOCK,
778			"%s: interruptible sleep by %p suspended by signal",
779				    __func__, sx);
780			break;
781		}
782		if (LOCK_LOG_TEST(&sx->lock_object, 0))
783			CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
784			    __func__, sx);
785	}
786
787	GIANT_RESTORE();
788	return (error);
789}
790
791/*
792 * This function represents the so-called 'hard case' for sx_sunlock
793 * operation.  All 'easy case' failures are redirected to this.  Note
794 * that ideally this would be a static function, but it needs to be
795 * accessible from at least sx.h.
796 */
797void
798_sx_sunlock_hard(struct sx *sx, const char *file, int line)
799{
800	uintptr_t x;
801
802	for (;;) {
803		x = sx->sx_lock;
804
805		/*
806		 * We should never have sharers while at least one thread
807		 * holds a shared lock.
808		 */
809		KASSERT(!(x & SX_LOCK_SHARED_WAITERS),
810		    ("%s: waiting sharers", __func__));
811
812		/*
813		 * See if there is more than one shared lock held.  If
814		 * so, just drop one and return.
815		 */
816		if (SX_SHARERS(x) > 1) {
817			if (atomic_cmpset_ptr(&sx->sx_lock, x,
818			    x - SX_ONE_SHARER)) {
819				if (LOCK_LOG_TEST(&sx->lock_object, 0))
820					CTR4(KTR_LOCK,
821					    "%s: %p succeeded %p -> %p",
822					    __func__, sx, (void *)x,
823					    (void *)(x - SX_ONE_SHARER));
824				break;
825			}
826			continue;
827		}
828
829		/*
830		 * If there aren't any waiters for an exclusive lock,
831		 * then try to drop it quickly.
832		 */
833		if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
834			MPASS(x == SX_SHARERS_LOCK(1));
835			if (atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1),
836			    SX_LOCK_UNLOCKED)) {
837				if (LOCK_LOG_TEST(&sx->lock_object, 0))
838					CTR2(KTR_LOCK, "%s: %p last succeeded",
839					    __func__, sx);
840				break;
841			}
842			continue;
843		}
844
845		/*
846		 * At this point, there should just be one sharer with
847		 * exclusive waiters.
848		 */
849		MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS));
850
851		sleepq_lock(&sx->lock_object);
852
853		/*
854		 * Wake up semantic here is quite simple:
855		 * Just wake up all the exclusive waiters.
856		 * Note that the state of the lock could have changed,
857		 * so if it fails loop back and retry.
858		 */
859		if (!atomic_cmpset_ptr(&sx->sx_lock,
860		    SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS,
861		    SX_LOCK_UNLOCKED)) {
862			sleepq_release(&sx->lock_object);
863			continue;
864		}
865		if (LOCK_LOG_TEST(&sx->lock_object, 0))
866			CTR2(KTR_LOCK, "%s: %p waking up all thread on"
867			    "exclusive queue", __func__, sx);
868		sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, -1,
869		    SQ_EXCLUSIVE_QUEUE);
870		break;
871	}
872}
873
874#ifdef INVARIANT_SUPPORT
875#ifndef INVARIANTS
876#undef	_sx_assert
877#endif
878
879/*
880 * In the non-WITNESS case, sx_assert() can only detect that at least
881 * *some* thread owns an slock, but it cannot guarantee that *this*
882 * thread owns an slock.
883 */
884void
885_sx_assert(struct sx *sx, int what, const char *file, int line)
886{
887#ifndef WITNESS
888	int slocked = 0;
889#endif
890
891	if (panicstr != NULL)
892		return;
893	switch (what) {
894	case SA_SLOCKED:
895	case SA_SLOCKED | SA_NOTRECURSED:
896	case SA_SLOCKED | SA_RECURSED:
897#ifndef WITNESS
898		slocked = 1;
899		/* FALLTHROUGH */
900#endif
901	case SA_LOCKED:
902	case SA_LOCKED | SA_NOTRECURSED:
903	case SA_LOCKED | SA_RECURSED:
904#ifdef WITNESS
905		witness_assert(&sx->lock_object, what, file, line);
906#else
907		/*
908		 * If some other thread has an exclusive lock or we
909		 * have one and are asserting a shared lock, fail.
910		 * Also, if no one has a lock at all, fail.
911		 */
912		if (sx->sx_lock == SX_LOCK_UNLOCKED ||
913		    (!(sx->sx_lock & SX_LOCK_SHARED) && (slocked ||
914		    sx_xholder(sx) != curthread)))
915			panic("Lock %s not %slocked @ %s:%d\n",
916			    sx->lock_object.lo_name, slocked ? "share " : "",
917			    file, line);
918
919		if (!(sx->sx_lock & SX_LOCK_SHARED)) {
920			if (sx_recursed(sx)) {
921				if (what & SA_NOTRECURSED)
922					panic("Lock %s recursed @ %s:%d\n",
923					    sx->lock_object.lo_name, file,
924					    line);
925			} else if (what & SA_RECURSED)
926				panic("Lock %s not recursed @ %s:%d\n",
927				    sx->lock_object.lo_name, file, line);
928		}
929#endif
930		break;
931	case SA_XLOCKED:
932	case SA_XLOCKED | SA_NOTRECURSED:
933	case SA_XLOCKED | SA_RECURSED:
934		if (sx_xholder(sx) != curthread)
935			panic("Lock %s not exclusively locked @ %s:%d\n",
936			    sx->lock_object.lo_name, file, line);
937		if (sx_recursed(sx)) {
938			if (what & SA_NOTRECURSED)
939				panic("Lock %s recursed @ %s:%d\n",
940				    sx->lock_object.lo_name, file, line);
941		} else if (what & SA_RECURSED)
942			panic("Lock %s not recursed @ %s:%d\n",
943			    sx->lock_object.lo_name, file, line);
944		break;
945	case SA_UNLOCKED:
946#ifdef WITNESS
947		witness_assert(&sx->lock_object, what, file, line);
948#else
949		/*
950		 * If we hold an exclusve lock fail.  We can't
951		 * reliably check to see if we hold a shared lock or
952		 * not.
953		 */
954		if (sx_xholder(sx) == curthread)
955			panic("Lock %s exclusively locked @ %s:%d\n",
956			    sx->lock_object.lo_name, file, line);
957#endif
958		break;
959	default:
960		panic("Unknown sx lock assertion: %d @ %s:%d", what, file,
961		    line);
962	}
963}
964#endif	/* INVARIANT_SUPPORT */
965
966#ifdef DDB
967static void
968db_show_sx(struct lock_object *lock)
969{
970	struct thread *td;
971	struct sx *sx;
972
973	sx = (struct sx *)lock;
974
975	db_printf(" state: ");
976	if (sx->sx_lock == SX_LOCK_UNLOCKED)
977		db_printf("UNLOCKED\n");
978	else if (sx->sx_lock == SX_LOCK_DESTROYED) {
979		db_printf("DESTROYED\n");
980		return;
981	} else if (sx->sx_lock & SX_LOCK_SHARED)
982		db_printf("SLOCK: %ju\n", (uintmax_t)SX_SHARERS(sx->sx_lock));
983	else {
984		td = sx_xholder(sx);
985		db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
986		    td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
987		if (sx_recursed(sx))
988			db_printf(" recursed: %d\n", sx->sx_recurse);
989	}
990
991	db_printf(" waiters: ");
992	switch(sx->sx_lock &
993	    (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)) {
994	case SX_LOCK_SHARED_WAITERS:
995		db_printf("shared\n");
996		break;
997	case SX_LOCK_EXCLUSIVE_WAITERS:
998		db_printf("exclusive\n");
999		break;
1000	case SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS:
1001		db_printf("exclusive and shared\n");
1002		break;
1003	default:
1004		db_printf("none\n");
1005	}
1006}
1007
1008/*
1009 * Check to see if a thread that is blocked on a sleep queue is actually
1010 * blocked on an sx lock.  If so, output some details and return true.
1011 * If the lock has an exclusive owner, return that in *ownerp.
1012 */
1013int
1014sx_chain(struct thread *td, struct thread **ownerp)
1015{
1016	struct sx *sx;
1017
1018	/*
1019	 * Check to see if this thread is blocked on an sx lock.
1020	 * First, we check the lock class.  If that is ok, then we
1021	 * compare the lock name against the wait message.
1022	 */
1023	sx = td->td_wchan;
1024	if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx ||
1025	    sx->lock_object.lo_name != td->td_wmesg)
1026		return (0);
1027
1028	/* We think we have an sx lock, so output some details. */
1029	db_printf("blocked on sx \"%s\" ", td->td_wmesg);
1030	*ownerp = sx_xholder(sx);
1031	if (sx->sx_lock & SX_LOCK_SHARED)
1032		db_printf("SLOCK (count %ju)\n",
1033		    (uintmax_t)SX_SHARERS(sx->sx_lock));
1034	else
1035		db_printf("XLOCK\n");
1036	return (1);
1037}
1038#endif
1039