]> git.alsa-project.org Git - alsa-utils.git/commitdiff
alsactl: use epoll(7) instead of poll(2)
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Sun, 14 Oct 2018 14:36:28 +0000 (23:36 +0900)
committerJaroslav Kysela <perex@perex.cz>
Sun, 14 Oct 2018 14:57:15 +0000 (16:57 +0200)
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@sakamocchi.jp>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
alsactl/monitor.c

index 008ceb303b24ca9ac14dbe0d8ce842e27a4b9b4d..7050eebf08d107d841e4a531a3b17bf4f31b0363 100644 (file)
@@ -20,6 +20,9 @@
 #include "aconfig.h"
 #include "version.h"
 #include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/epoll.h>
 #include <alsa/asoundlib.h>
 
 #define MAX_CARDS      256
@@ -114,41 +117,121 @@ 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)
 {
+       struct pollfd *pfds;
+       int count;
+       unsigned int pfd_count;
+       int i;
+       int err;
+
+       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;
+       }
+
+       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 (;ncards > 0;) {
-               struct pollfd fds[ncards];
-               int i;
+       for (i = 0; i < ncards; ++i) {
+               snd_ctl_t *ctl = ctls[i];
+               struct epoll_event ev;
+               ev.events = EPOLLIN;
+               ev.data.ptr = (void *)ctl;
+               err = operate_dispatcher(epfd, EPOLL_CTL_ADD, &ev, ctl);
+               if (err < 0)
+                       break;
+       }
 
-               for (i = 0; i < ncards; i++)
-                       snd_ctl_poll_descriptors(ctls[i], &fds[i], 1);
+       return err;
+}
 
-               err = poll(fds, ncards, -1);
-               if (err <= 0) {
-                       err = 0;
+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;
+
+       while (true) {
+               int count;
+               int i;
+
+               count = epoll_wait(epfd, epev, max_ev_count, 200);
+               if (count < 0) {
+                       err = count;
                        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);
+       }
+}
+
 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 i, err = 0;
+       int epfd;
+       int i;
+       int err = 0;
+
+       epfd = epoll_create(1);
+       if (epfd < 0)
+               return -errno;
 
        if (!name) {
                struct snd_card_iterator iter;
@@ -170,9 +253,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;
 }