FreeBSD/sys/kern/subr_devstat.c
/*
 * This is the sysctl handler for the devstat package.  The data pushed out
 * on the kern.devstat.all sysctl variable consists of the current devstat
 * generation number, and then an array of devstat structures, one for each
 * device in the system.
 *
 * This is more cryptic that obvious, but basically we neither can nor
 * want to hold the devstat_mutex for any amount of time, so we grab it
 * only when we need to and keep an eye on devstat_generation all the time.
 */
This is the sysctl handler for the devstat package.  The data pushed out
on the kern.devstat.all sysctl variable consists of the current devstat
generation number, and then an array of devstat structures, one for each
device in the system.

This is more cryptic that obvious, but basically we neither can nor
want to hold the devstat_mutex for any amount of time, so we grab it
only when we need to and keep an eye on devstat_generation all the time.
This is the sysctl handler for the devstat package . The data pushed out on the kern . devstat . all sysctl variable consists of the current devstat generation number and then an array of devstat structures one for each device in the system . This is more cryptic that obvious but basically we neither can nor want to hold the devstat_mutex for any amount of time so we grab it only when we need to and keep an eye on devstat_generation all the time .
static int
sysctl_devstat(SYSCTL_HANDLER_ARGS)
{
	int error;
	long mygen;
	struct devstat *nds;
	mtx_assert(&devstat_mutex, MA_NOTOWNED);
	mygen = devstat_generation;
	error = SYSCTL_OUT(req, &mygen, sizeof(mygen));
	if (devstat_num_devs == 0)
		return(0);
	if (error != 0)
		return (error);
	mtx_lock(&devstat_mutex);
	nds = STAILQ_FIRST(&device_statq); 
	if (mygen != devstat_generation)
		error = EBUSY;
	mtx_unlock(&devstat_mutex);
	if (error != 0)
		return (error);
	for (;nds != NULL;) {
		error = SYSCTL_OUT(req, nds, sizeof(struct devstat));
		if (error != 0)
			return (error);
		mtx_lock(&devstat_mutex);
		if (mygen != devstat_generation)
			error = EBUSY;
		else
			nds = STAILQ_NEXT(nds, dev_links);
		mtx_unlock(&devstat_mutex);
		if (error != 0)
			return (error);
	}
	return(error);
}
static int sysctl_devstat ( SYSCTL_HANDLER_ARGS ) { int error ; long mygen ; struct devstat * nds ; mtx_assert ( & devstat_mutex , MA_NOTOWNED ) ; mygen = devstat_generation ; error = SYSCTL_OUT ( req , & mygen , sizeof ( mygen ) ) ; if ( devstat_num_devs == 0 ) return ( 0 ) ; if ( error != 0 ) return ( error ) ; mtx_lock ( & devstat_mutex ) ; nds = STAILQ_FIRST ( & device_statq ) ; if ( mygen != devstat_generation ) error = EBUSY ; mtx_unlock ( & devstat_mutex ) ; if ( error != 0 ) return ( error ) ; for ( ; nds != NULL ; ) { error = SYSCTL_OUT ( req , nds , sizeof ( struct devstat ) ) ; if ( error != 0 ) return ( error ) ; mtx_lock ( & devstat_mutex ) ; if ( mygen != devstat_generation ) error = EBUSY ; else nds = STAILQ_NEXT ( nds , dev_links ) ; mtx_unlock ( & devstat_mutex ) ; if ( error != 0 ) return ( error ) ; } return ( error ) ; }
This is the sysctl handler for the devstat package.
This is the sysctl handler for the devstat package .
/*
	 * XXX devstat_generation should really be "volatile" but that
	 * XXX freaks out the sysctl macro below.  The places where we
	 * XXX change it and inspect it are bracketed in the mutex which
	 * XXX guarantees us proper write barriers.  I don't believe the
	 * XXX compiler is allowed to optimize mygen away across calls
	 * XXX to other functions, so the following is belived to be safe.
	 */