Some operations with blocking flag for ALSA control character devices don't return to userspace when closing a file descriptor corresponding to the character device. I think this is a bug of ALSA core.
While, I find no resources to assist this aspect. In a manual of close(2)/read(2), there'no description about it. On SUSv2, there's descriptions for pipe or FIFO for this behaviour, while nothing for character devices. On Linux kernel documentation, I cannot find this kind of explaination. Thus, I just stand on my experiences to use these operations for files on filesystems, sockets and virtual character devices. It may merely be due to my misunderstanding.
Well, additionally, in unsubscribed state, read operation for the character device returns with EBADFD. On the other hand, in subscribed state and once the operations are going to be blocked, they don't return to userspace even if any unsubscribe ioctl(2) operations are executed. This losts a consistency about the actual effects of unsubscribe operation.
It's my pleasure to discuss about these bugs (and my patch candidate to fix them). You can see these bugs with this sample program.
= Sample program = #include <stdio.h> #include <stdlib.h>
#include <errno.h> #include <string.h>
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h> #include <sound/asound.h>
#include <pthread.h>
static void *thread_run(void *arg) { int fd = *(int *)arg; char buf[512] = {};
while (read(fd, buf, sizeof(buf)) >= 0) ;
return (void *)NULL; }
int main(int argc, char *argv[]) { pthread_t thread = pthread_self(); int fd; int subscribe;
fd = open("/dev/snd/controlC0", O_RDONLY); if (fd < 0) { printf("%s\n", strerror(errno)); return EXIT_FAILURE; }
subscribe = 1; if (ioctl(fd, SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, &subscribe) < 0) { printf("%s\n", strerror(errno)); close(fd); return EXIT_FAILURE; }
if (pthread_create(&thread, NULL, thread_run, (void *)&fd) < 0) { printf("%s\n", strerror(errno)); close(fd); return EXIT_FAILURE; }
sleep(1);
if (argc == 1) { close(fd); } else { subscribe = 0; if (ioctl(fd, SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, &subscribe) < 0) { printf("%s\n", strerror(errno)); close(fd); return EXIT_FAILURE; } }
/* Here, I expect blocking state of read(2) should be released. But... */ pthread_join(thread, NULL);
return EXIT_SUCCESS; }
Takashi Sakamoto (1): ALSA: control: add .flush operation to release blocking operation
sound/core/control.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-)