xref: /dflybsd-src/sys/kern/kern_refcount.c (revision 0486d94aa7bae282562c0a132d7393ed3e4aa661)
112f43c12SMatthew Dillon /*
212f43c12SMatthew Dillon  * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
312f43c12SMatthew Dillon  *
412f43c12SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
512f43c12SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
612f43c12SMatthew Dillon  *
712f43c12SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
812f43c12SMatthew Dillon  * modification, are permitted provided that the following conditions
912f43c12SMatthew Dillon  * are met:
1012f43c12SMatthew Dillon  *
1112f43c12SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
1212f43c12SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
1312f43c12SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
1412f43c12SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
1512f43c12SMatthew Dillon  *    the documentation and/or other materials provided with the
1612f43c12SMatthew Dillon  *    distribution.
1712f43c12SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
1812f43c12SMatthew Dillon  *    contributors may be used to endorse or promote products derived
1912f43c12SMatthew Dillon  *    from this software without specific, prior written permission.
2012f43c12SMatthew Dillon  *
2112f43c12SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2212f43c12SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2312f43c12SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2412f43c12SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2512f43c12SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2612f43c12SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2712f43c12SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2812f43c12SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2912f43c12SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3012f43c12SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3112f43c12SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3212f43c12SMatthew Dillon  * SUCH DAMAGE.
3312f43c12SMatthew Dillon  */
3412f43c12SMatthew Dillon /*
3512f43c12SMatthew Dillon  * Implement helper routines for the refcount inlines in sys/refcount.h.
3612f43c12SMatthew Dillon  *
3712f43c12SMatthew Dillon  * These helpers implement the refcount_release_wakeup() and refcount_wait()
3812f43c12SMatthew Dillon  * APIs for the non-trivial or race case.  The trivial non-race case is
3912f43c12SMatthew Dillon  * handled by the inline in sys/refcount.h
4012f43c12SMatthew Dillon  */
4112f43c12SMatthew Dillon 
4212f43c12SMatthew Dillon #include <sys/param.h>
4312f43c12SMatthew Dillon #include <sys/systm.h>
4412f43c12SMatthew Dillon #include <sys/kernel.h>
4512f43c12SMatthew Dillon #include <sys/sysctl.h>
4612f43c12SMatthew Dillon #include <sys/thread.h>
4712f43c12SMatthew Dillon #include <sys/refcount.h>
4812f43c12SMatthew Dillon 
4912f43c12SMatthew Dillon #include <machine/cpufunc.h>
5012f43c12SMatthew Dillon 
5112f43c12SMatthew Dillon /*
52*0486d94aSMatthew Dillon  * Interlocked wait against a decrement-to-0 (sans the REFCNTF_WAITING flag).
5312f43c12SMatthew Dillon  *
5412f43c12SMatthew Dillon  * Users of this waiting API must use refcount_release_wakeup() to release
5512f43c12SMatthew Dillon  * refs instead of refcount_release().  refcount_release() will not wake
5612f43c12SMatthew Dillon  * up waiters.
5712f43c12SMatthew Dillon  */
5812f43c12SMatthew Dillon void
_refcount_wait(volatile u_int * countp,const char * wstr)59ed2fb120SVenkatesh Srinivas _refcount_wait(volatile u_int *countp, const char *wstr)
6012f43c12SMatthew Dillon {
6112f43c12SMatthew Dillon 	u_int n;
62761f8226SMatthew Dillon 	int base_ticks = ticks;
6312f43c12SMatthew Dillon 
6412f43c12SMatthew Dillon 	n = *countp;
65*0486d94aSMatthew Dillon 	for (;;) {
66d69db72bSMatthew Dillon 		cpu_ccfence();
67*0486d94aSMatthew Dillon 		if ((n & ~REFCNTF_WAITING) == 0)
6812f43c12SMatthew Dillon 			break;
69761f8226SMatthew Dillon 		if ((int)(ticks - base_ticks) >= hz*60 - 1) {
70*0486d94aSMatthew Dillon 			kprintf("warning: refcount_wait %s: long wait\n", wstr);
71761f8226SMatthew Dillon 			base_ticks = ticks;
72ed2fb120SVenkatesh Srinivas 		}
7312f43c12SMatthew Dillon 		tsleep_interlock(countp, 0);
74*0486d94aSMatthew Dillon 		if (atomic_fcmpset_int(countp, &n, n | REFCNTF_WAITING))
75ed2fb120SVenkatesh Srinivas 			tsleep(countp, PINTERLOCKED, wstr, hz*10);
7612f43c12SMatthew Dillon 	}
7712f43c12SMatthew Dillon }
78