mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-09 23:55:42 +01:00
alsactl: use signalfd to catch UNIX signal
In a mode of 'monitor, event loop runs to dispatch asynchronous event emitted by control node. In this case, UNIX signal is used to terminate the event loop. This commit uses signalfd to catch the UNIX signal. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
e57a0a0809
commit
46cb575b9b
1 changed files with 50 additions and 7 deletions
|
@ -26,6 +26,8 @@
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/signalfd.h>
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -290,12 +292,18 @@ end:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prepare_dispatcher(int epfd, int infd, struct list_head *srcs)
|
static int prepare_dispatcher(int epfd, int sigfd, int infd,
|
||||||
|
struct list_head *srcs)
|
||||||
{
|
{
|
||||||
struct epoll_event ev = {0};
|
struct epoll_event ev = {0};
|
||||||
struct src_entry *entry;
|
struct src_entry *entry;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.fd = sigfd;
|
||||||
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &ev) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
ev.events = EPOLLIN;
|
ev.events = EPOLLIN;
|
||||||
ev.data.fd = infd;
|
ev.data.fd = infd;
|
||||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, infd, &ev) < 0)
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, infd, &ev) < 0)
|
||||||
|
@ -312,7 +320,7 @@ static int prepare_dispatcher(int epfd, int infd, struct list_head *srcs)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run_dispatcher(int epfd, int infd, struct list_head *srcs,
|
static int run_dispatcher(int epfd, int sigfd, int infd, struct list_head *srcs,
|
||||||
bool *retry)
|
bool *retry)
|
||||||
{
|
{
|
||||||
struct src_entry *entry;
|
struct src_entry *entry;
|
||||||
|
@ -343,6 +351,9 @@ static int run_dispatcher(int epfd, int infd, struct list_head *srcs,
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
struct epoll_event *ev = epev + i;
|
struct epoll_event *ev = epev + i;
|
||||||
|
|
||||||
|
if (ev->data.fd == sigfd)
|
||||||
|
goto end;
|
||||||
|
|
||||||
if (ev->data.fd == infd) {
|
if (ev->data.fd == infd) {
|
||||||
err = check_control_cdev(infd, retry);
|
err = check_control_cdev(infd, retry);
|
||||||
if (err < 0 || *retry)
|
if (err < 0 || *retry)
|
||||||
|
@ -366,7 +377,8 @@ end:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_dispatcher(int epfd, int infd, struct list_head *srcs)
|
static void clear_dispatcher(int epfd, int sigfd, int infd,
|
||||||
|
struct list_head *srcs)
|
||||||
{
|
{
|
||||||
struct src_entry *entry;
|
struct src_entry *entry;
|
||||||
|
|
||||||
|
@ -374,20 +386,49 @@ static void clear_dispatcher(int epfd, int infd, struct list_head *srcs)
|
||||||
operate_dispatcher(epfd, EPOLL_CTL_DEL, NULL, entry);
|
operate_dispatcher(epfd, EPOLL_CTL_DEL, NULL, entry);
|
||||||
|
|
||||||
epoll_ctl(epfd, EPOLL_CTL_DEL, infd, NULL);
|
epoll_ctl(epfd, EPOLL_CTL_DEL, infd, NULL);
|
||||||
|
|
||||||
|
epoll_ctl(epfd, EPOLL_CTL_DEL, sigfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int prepare_signalfd(int *sigfd)
|
||||||
|
{
|
||||||
|
sigset_t mask;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGINT);
|
||||||
|
sigaddset(&mask, SIGTERM);
|
||||||
|
|
||||||
|
if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
fd = signalfd(-1, &mask, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return -errno;
|
||||||
|
*sigfd = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int monitor(const char *name)
|
int monitor(const char *name)
|
||||||
{
|
{
|
||||||
LIST_HEAD(srcs);
|
LIST_HEAD(srcs);
|
||||||
|
int sigfd = 0;
|
||||||
int epfd;
|
int epfd;
|
||||||
int infd;
|
int infd;
|
||||||
int wd = 0;
|
int wd = 0;
|
||||||
bool retry;
|
bool retry;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
err = prepare_signalfd(&sigfd);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
epfd = epoll_create(1);
|
epfd = epoll_create(1);
|
||||||
if (epfd < 0)
|
if (epfd < 0) {
|
||||||
|
close(sigfd);
|
||||||
return -errno;
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
infd = inotify_init1(IN_NONBLOCK);
|
infd = inotify_init1(IN_NONBLOCK);
|
||||||
if (infd < 0) {
|
if (infd < 0) {
|
||||||
|
@ -405,10 +446,10 @@ retry:
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
err = prepare_dispatcher(epfd, infd, &srcs);
|
err = prepare_dispatcher(epfd, sigfd, infd, &srcs);
|
||||||
if (err >= 0)
|
if (err >= 0)
|
||||||
err = run_dispatcher(epfd, infd, &srcs, &retry);
|
err = run_dispatcher(epfd, sigfd, infd, &srcs, &retry);
|
||||||
clear_dispatcher(epfd, infd, &srcs);
|
clear_dispatcher(epfd, sigfd, infd, &srcs);
|
||||||
|
|
||||||
if (retry) {
|
if (retry) {
|
||||||
// A simple makeshift for timing gap between creation of nodes
|
// A simple makeshift for timing gap between creation of nodes
|
||||||
|
@ -426,5 +467,7 @@ error:
|
||||||
|
|
||||||
close(epfd);
|
close(epfd);
|
||||||
|
|
||||||
|
close(sigfd);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue