]> git.alsa-project.org Git - alsa-utils.git/commitdiff
axfer: add an implementation of waiter for select(2)
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Tue, 13 Nov 2018 06:41:43 +0000 (15:41 +0900)
committerTakashi Iwai <tiwai@suse.de>
Tue, 13 Nov 2018 11:04:50 +0000 (12:04 +0100)
This commit adds support of waiter for select(2) system call.

Below lines are examples to use this option:
$ axfer transfer --waiter-type=select -M -P -d 2 -D hw:0,3 /dev/urandom -f dat -vvv
$ axfer transfer --waiter-type=select -M -C -d 2 -D hw:1,0 /dev/null -r 48000 -vvv

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
axfer/Makefile.am
axfer/waiter-select.c [new file with mode: 0644]
axfer/waiter.c
axfer/waiter.h

index 71230062c51f889877e1451849297146ccc6ea81..867007bc28ea8569d551a7c915959951a45bd9eb 100644 (file)
@@ -51,4 +51,5 @@ axfer_SOURCES = \
        xfer-libasound-irq-mmap.c \
        waiter.h \
        waiter.c \
-       waiter-poll.c
+       waiter-poll.c \
+       waiter-select.c
diff --git a/axfer/waiter-select.c b/axfer/waiter-select.c
new file mode 100644 (file)
index 0000000..a35ea85
--- /dev/null
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// waiter-select.c - Waiter for event notification by select(2).
+//
+// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+//
+// Licensed under the terms of the GNU General Public License, version 2.
+
+#include "waiter.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/select.h>
+
+// Except for POLLERR.
+#define POLLIN_SET     (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP)
+#define POLLOUT_SET    (POLLWRBAND | POLLWRNORM | POLLOUT)
+#define POLLEX_SET     (POLLPRI)
+
+struct select_state {
+       fd_set rfds_rd;
+       fd_set rfds_wr;
+       fd_set rfds_ex;
+};
+
+static int select_prepare(struct waiter_context *waiter)
+{
+       return 0;
+}
+
+static int select_wait_event(struct waiter_context *waiter, int timeout_msec)
+{
+       struct select_state *state = waiter->private_data;
+       struct pollfd *pfd;
+       int fd_max;
+       struct timeval tv, *tv_ptr;
+       int i;
+       int err;
+
+       FD_ZERO(&state->rfds_rd);
+       FD_ZERO(&state->rfds_wr);
+       FD_ZERO(&state->rfds_ex);
+
+       fd_max = 0;
+       for (i = 0; i < waiter->pfd_count; ++i) {
+               pfd = &waiter->pfds[i];
+
+               if (pfd->events & POLLIN_SET)
+                       FD_SET(pfd->fd, &state->rfds_rd);
+               if (pfd->events & POLLOUT_SET)
+                       FD_SET(pfd->fd, &state->rfds_wr);
+               if (pfd->events & POLLEX_SET)
+                       FD_SET(pfd->fd, &state->rfds_ex);
+               if (pfd->fd > fd_max)
+                       fd_max = pfd->fd;
+       }
+
+       if (timeout_msec < 0) {
+               tv_ptr = NULL;
+       } else {
+               tv.tv_sec = 0;
+               tv.tv_usec = timeout_msec * 1000;
+               tv_ptr = &tv;
+       }
+
+       err = select(fd_max + 1, &state->rfds_rd, &state->rfds_wr,
+                    &state->rfds_ex, tv_ptr);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < waiter->pfd_count; ++i) {
+               pfd = &waiter->pfds[i];
+
+               pfd->revents = 0;
+               if (FD_ISSET(pfd->fd, &state->rfds_rd))
+                       pfd->revents |= POLLIN;
+               if (FD_ISSET(pfd->fd, &state->rfds_wr))
+                       pfd->revents |= POLLOUT;
+               if (FD_ISSET(pfd->fd, &state->rfds_ex))
+                       pfd->revents |= POLLHUP;
+       }
+
+       return 0;
+}
+
+static void select_release(struct waiter_context *waiter)
+{
+       return;
+}
+
+const struct waiter_data waiter_select = {
+       .ops = {
+               .prepare        = select_prepare,
+               .wait_event     = select_wait_event,
+               .release        = select_release,
+       },
+       .private_size = sizeof(struct select_state),
+};
index 446e617bb2d98c41c38db247befd6d60aa93cd19..08428e36afbc8ca9b5fe0fb507b968412a458df3 100644 (file)
@@ -17,6 +17,7 @@
 static const char *const waiter_type_labels[] = {
        [WAITER_TYPE_DEFAULT] = "default",
        [WAITER_TYPE_POLL] = "poll",
+       [WAITER_TYPE_SELECT] = "select",
 };
 
 enum waiter_type waiter_type_from_label(const char *label)
@@ -44,6 +45,7 @@ int waiter_context_init(struct waiter_context *waiter,
                const struct waiter_data *waiter;
        } entries[] = {
                {WAITER_TYPE_POLL,      &waiter_poll},
+               {WAITER_TYPE_SELECT,    &waiter_select},
        };
        int i;
 
index 936672473b88d1dacd468e62d909aadb27f96cb5..fec16b77f6f59e84cea4de974dbe8b42c60da358 100644 (file)
@@ -14,6 +14,7 @@
 enum waiter_type {
        WAITER_TYPE_DEFAULT = 0,
        WAITER_TYPE_POLL,
+       WAITER_TYPE_SELECT,
        WAITER_TYPE_COUNT,
 };
 
@@ -53,5 +54,6 @@ struct waiter_data {
 };
 
 extern const struct waiter_data waiter_poll;
+extern const struct waiter_data waiter_select;
 
 #endif