[Libguestfs] [PATCH] lib: command: switch from select() to poll()
Daniel P. Berrangé
berrange at redhat.com
Wed Feb 26 14:08:24 UTC 2020
On Wed, Feb 26, 2020 at 02:39:04PM +0100, Pino Toscano wrote:
> select() has a maximum value for the FDs it can monitor, and since
> the libguestfs library can be used in other applications, this limit
> may be hit by users in case lots of FDs are opened.
>
> As solution, switch to poll(): it has a slightly better interface to
> check what changed and for which FD, and it does not have a limit in the
> value of the FDs monitored.
>
> poll() is supported on the platforms we support, so there is no need to
> use the gnulib module for it.
> ---
> lib/command.c | 54 ++++++++++++++++++++++++++++++++++-----------------
> 1 file changed, 36 insertions(+), 18 deletions(-)
>
> diff --git a/lib/command.c b/lib/command.c
> index f2161de9a..13b084934 100644
> --- a/lib/command.c
> +++ b/lib/command.c
> @@ -89,9 +89,8 @@
> #include <signal.h>
> #include <errno.h>
> #include <assert.h>
> -#include <sys/types.h>
> #include <sys/stat.h>
> -#include <sys/select.h>
> +#include <poll.h>
>
> #ifdef HAVE_SYS_TIME_H
> #include <sys/time.h>
> @@ -650,37 +649,41 @@ run_child (struct command *cmd)
> static int
> loop (struct command *cmd)
> {
> - fd_set rset, rset2;
> - int maxfd = -1, r;
> + struct pollfd fds[2];
> + int r;
> size_t nr_fds = 0;
> CLEANUP_FREE char *buf = safe_malloc (cmd->g, BUFSIZ);
> ssize_t n;
>
> - FD_ZERO (&rset);
> + memset (&fds, 0, sizeof fds);
> +
> + fds[0].fd = cmd->errorfd;
> + fds[1].fd = cmd->outfd;
>
> if (cmd->errorfd >= 0) {
> - FD_SET (cmd->errorfd, &rset);
> - maxfd = MAX (cmd->errorfd, maxfd);
> + fds[0].events = POLLIN;
> nr_fds++;
> }
>
> if (cmd->outfd >= 0) {
> - FD_SET (cmd->outfd, &rset);
> - maxfd = MAX (cmd->outfd, maxfd);
> + fds[1].events = POLLIN;
> nr_fds++;
> }
>
> while (nr_fds > 0) {
> - rset2 = rset;
> - r = select (maxfd+1, &rset2, NULL, NULL, NULL);
> + r = poll (fds, 2, -1);
> if (r == -1) {
> if (errno == EINTR || errno == EAGAIN)
> continue;
> - perrorf (cmd->g, "select");
> + perrorf (cmd->g, "poll");
> + return -1;
> + }
> + if (fds[0].revents & POLLERR || fds[1].revents & POLLERR) {
> + perrorf (cmd->g, "poll");
> return -1;
> }
>
> - if (cmd->errorfd >= 0 && FD_ISSET (cmd->errorfd, &rset2)) {
> + if (fds[0].revents & POLLIN) {
> /* Read output and send it to the log. */
> n = read (cmd->errorfd, buf, BUFSIZ);
> if (n > 0)
> @@ -689,20 +692,26 @@ loop (struct command *cmd)
> else if (n == 0) {
> if (close (cmd->errorfd) == -1)
> perrorf (cmd->g, "close: errorfd");
> - FD_CLR (cmd->errorfd, &rset);
> + fds[0].fd = -1;
> cmd->errorfd = -1;
> nr_fds--;
> }
> else if (n == -1) {
> perrorf (cmd->g, "read: errorfd");
> close (cmd->errorfd);
> - FD_CLR (cmd->errorfd, &rset);
> + fds[0].fd = -1;
> cmd->errorfd = -1;
> nr_fds--;
> }
> }
> + if (fds[0].revents & POLLHUP) {
> + close (cmd->errorfd);
> + fds[0].fd = -1;
> + cmd->errorfd = -1;
> + nr_fds--;
> + }
Now fds[0] is -1, and fds[1] is still an open file
descriptor.
Next time around the loop it will call poll() on 'fds' array
which contains this FD == -1. In theory that results in POLLNVAL,
but on OS-X at least it causes poll() itself to return an error.
I'd initialize 'struct pollfd' inside the loop, such that
it only ever contains valid open FDs.
>
> - if (cmd->outfd >= 0 && FD_ISSET (cmd->outfd, &rset2)) {
> + if (fds[1].revents & POLLIN) {
> /* Read the output, buffer it up to the end of the line, then
> * pass it to the callback.
> */
> @@ -716,18 +725,27 @@ loop (struct command *cmd)
> cmd->outbuf.close_data (cmd);
> if (close (cmd->outfd) == -1)
> perrorf (cmd->g, "close: outfd");
> - FD_CLR (cmd->outfd, &rset);
> + fds[1].fd = -1;
> cmd->outfd = -1;
> nr_fds--;
> }
> else if (n == -1) {
> perrorf (cmd->g, "read: outfd");
> close (cmd->outfd);
> - FD_CLR (cmd->outfd, &rset);
> + fds[1].fd = -1;
> cmd->outfd = -1;
> nr_fds--;
> }
> }
> + if (fds[1].revents & POLLHUP) {
> + if (cmd->outbuf.close_data)
> + cmd->outbuf.close_data (cmd);
> + if (close (cmd->outfd) == -1)
> + perrorf (cmd->g, "close: outfd");
> + fds[1].fd = -1;
> + cmd->outfd = -1;
> + nr_fds--;
> + }
> }
>
> return 0;
> --
> 2.24.1
>
> _______________________________________________
> Libguestfs mailing list
> Libguestfs at redhat.com
> https://www.redhat.com/mailman/listinfo/libguestfs
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
More information about the Libguestfs
mailing list