DF-4192 / trighammer.c
/* 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; } |