[alsa-devel] [alsa-utils][PATCH 3/9] alsactl: use epoll(7) instead of poll(2)

Takashi Sakamoto o-takashi at sakamocchi.jp
Sun Oct 14 16:36:28 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 | 134 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 113 insertions(+), 21 deletions(-)

diff --git a/alsactl/monitor.c b/alsactl/monitor.c
index 008ceb3..7050eeb 100644
--- a/alsactl/monitor.c
+++ b/alsactl/monitor.c
@@ -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;
 }
-- 
2.19.1



More information about the Alsa-devel mailing list