[alsa-devel] [PATCH][RFC][alsa-utils 4/9] alsactl: use epoll(7) instead of poll(2)
Takashi Sakamoto
o-takashi at sakamocchi.jp
Fri Oct 5 16:47:24 CEST 2018
Linux kernel supports unique system call; epoll(7). This allows
applications to make associations for descriptor-unique data in a
easy way.
This commit uses epoll(7) instead of poll(2) for this point.
Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
alsactl/monitor.c | 144 ++++++++++++++++++++++++++++++++++++----------
1 file changed, 115 insertions(+), 29 deletions(-)
diff --git a/alsactl/monitor.c b/alsactl/monitor.c
index 79e8fd9..cf5c50a 100644
--- a/alsactl/monitor.c
+++ b/alsactl/monitor.c
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <string.h>
#include <signal.h>
+#include <sys/epoll.h>
#include <alsa/asoundlib.h>
static int signal_type;
@@ -120,47 +121,118 @@ static int print_event(int card, snd_ctl_t *ctl)
return 0;
}
-static int run_dispatcher(snd_ctl_t **ctls, int ncards, int show_cards)
+static int operate_dispatcher(int epfd, uint32_t op, struct epoll_event *epev,
+ snd_ctl_t *ctl)
{
- interrupted = false;
- int err = 0;
+ struct pollfd *pfds;
+ int count;
+ unsigned int pfd_count;
+ int i;
+ int err;
- for (;ncards > 0;) {
- struct pollfd fds[ncards];
- int i;
+ count = snd_ctl_poll_descriptors_count(ctl);
+ if (count < 0)
+ return count;
+ if (count == 0)
+ return -ENXIO;
+ pfd_count = count;
+
+ pfds = calloc(pfd_count, sizeof(*pfds));
+ if (!pfds)
+ return -ENOMEM;
+
+ count = snd_ctl_poll_descriptors(ctl, pfds, pfd_count);
+ if (count < 0) {
+ err = count;
+ goto end;
+ }
+ if (count != pfd_count) {
+ err = -EIO;
+ goto end;
+ }
- if (interrupted) {
- printf("interrupted: %s\n", strsignal(signal_type));
+ for (i = 0; i < pfd_count; ++i) {
+ err = epoll_ctl(epfd, op, pfds[i].fd, epev);
+ if (err < 0)
break;
- }
+ }
+end:
+ free(pfds);
+ return err;
+}
+
+static int prepare_dispatcher(int epfd, snd_ctl_t **ctls, int ncards)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < ncards; ++i) {
+ snd_ctl_t *ctl = ctls[i];
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ .data.ptr = (void *)ctl,
+ };
+ err = operate_dispatcher(epfd, EPOLL_CTL_ADD, &ev, ctl);
+ if (err < 0)
+ break;
+ }
+
+ return err;
+}
+
+static int run_dispatcher(int epfd, unsigned int max_ev_count, int show_cards)
+{
+ struct epoll_event *epev;
+ int err = 0;
+
+ epev = calloc(max_ev_count, sizeof(*epev));
+ if (!epev)
+ return -ENOMEM;
- for (i = 0; i < ncards; i++)
- snd_ctl_poll_descriptors(ctls[i], &fds[i], 1);
+ while (!interrupted) {
+ int count;
+ int i;
- err = poll(fds, ncards, -1);
- if (err <= 0) {
- // Catch this case by an above condition statement to
+ count = epoll_wait(epfd, epev, max_ev_count, 200);
+ if (count < 0) {
+ err = count;
+
+ // Catch this case by an loop condition statement to
// check value set by signal handler. I note that
- // poll(2) returns EINTR even if configured with
- // SA_RESTART.
- if (errno == EINTR)
+ // epoll_wait(2) returns EINTR even if configured with
+ // SA_RESTART, as well as catching SIGCONT after
+ // SIGSTOP/SIGTSTP/SIGTTIN/SIGTTOU.
+ if (err == EINTR)
continue;
- err = 0;
break;
}
+ if (count == 0)
+ continue;
+
+ for (i = 0; i < count; ++i) {
+ struct epoll_event *ev = epev + i;
+ snd_ctl_t *handle = (snd_ctl_t *)ev->data.ptr;
- for (i = 0; i < ncards; i++) {
- unsigned short revents;
- snd_ctl_poll_descriptors_revents(ctls[i], &fds[i], 1,
- &revents);
- if (revents & POLLIN)
- print_event(show_cards ? i : -1, ctls[i]);
+ if (ev->events & EPOLLIN)
+ print_event(show_cards ? i : -1, handle);
}
}
+ free(epev);
+
return err;
}
+static void clear_dispatcher(int epfd, snd_ctl_t **ctls, int ncards)
+{
+ int i;
+
+ for (i = 0; i < ncards; ++i) {
+ snd_ctl_t *ctl = ctls[i];
+ operate_dispatcher(epfd, EPOLL_CTL_DEL, NULL, ctl);
+ }
+}
+
static void handle_unix_signal_for_finish(int sig)
{
signal_type = sig;
@@ -187,9 +259,10 @@ static int prepare_signal_handler(void)
int monitor(const char *name)
{
- snd_ctl_t *ctls[MAX_CARDS];
+ snd_ctl_t *ctls[MAX_CARDS] = {0};
int ncards = 0;
int show_cards;
+ int epfd;
int i;
int err = 0;
@@ -197,6 +270,10 @@ int monitor(const char *name)
if (err < 0)
return err;
+ epfd = epoll_create(1);
+ if (epfd < 0)
+ return -errno;
+
if (!name) {
struct snd_card_iterator iter;
const char *cardname;
@@ -217,9 +294,18 @@ int monitor(const char *name)
show_cards = 0;
}
- err = run_dispatcher(ctls, ncards, show_cards);
- error:
- for (i = 0; i < ncards; i++)
- snd_ctl_close(ctls[i]);
+ err = prepare_dispatcher(epfd, ctls, ncards);
+ if (err >= 0)
+ err = run_dispatcher(epfd, ncards, show_cards);
+ clear_dispatcher(epfd, ctls, ncards);
+
+error:
+ for (i = 0; i < ncards; i++) {
+ if (ctls[i])
+ snd_ctl_close(ctls[i]);
+ }
+
+ close(epfd);
+
return err;
}
--
2.19.0
More information about the Alsa-devel
mailing list