random: Use poll instead of select

NIIBE Yutaka gniibe at fsij.org
Mon Nov 2 09:31:07 CET 2015


Hello,

I'm trying to fix a bug in GnuPG 1.4 (caused by (a kind of bug in)
duplicity which uses many file descriptors):

    https://bugs.gnupg.org/gnupg/issue1818
    https://bugs.debian.org/771263

And find a patch for libgcrypt in Fedora:

    http://pkgs.fedoraproject.org/cgit/libgcrypt.git/tree/
    libgcrypt-1.6.1-use-poll.patch

I think that the patch by Fedora is almost good, but it's not that
accurate in the comment and the behavior of setting any_need_entropy to 1
when poll timeouts.

So, this is the version which keeps the original behavior; It simply
replaces select by poll.  Note: poll uses millisecond for its timeout.

I think that all Linux kernel nowadays support poll(2).


diff --git a/random/rndlinux.c b/random/rndlinux.c
index 9eeec57..267a07e 100644
--- a/random/rndlinux.c
+++ b/random/rndlinux.c
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <poll.h>
 #include "types.h"
 #include "g10lib.h"
 #include "rand-internal.h"
@@ -179,12 +180,14 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
                  return with something we will actually use 100ms. */
   while (length)
     {
-      fd_set rfds;
-      struct timeval tv;
       int rc;
+      struct pollfd pfd;
+
+      pfd.fd = fd;
+      pfd.events = POLLIN;

       /* If we collected some bytes update the progress indicator.  We
-         do this always and not just if the select timed out because
+         do this always and not just if the poll timed out because
          often just a few bytes are gathered within the timeout
          period.  */
       if (any_need_entropy || last_so_far != (want - length) )
@@ -195,33 +198,19 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
           any_need_entropy = 1;
         }

-      /* If the system has no limit on the number of file descriptors
-         and we encounter an fd which is larger than the fd_set size,
-         we don't use the select at all.  The select code is only used
-         to emit progress messages.  A better solution would be to
-         fall back to poll() if available.  */
-#ifdef FD_SETSIZE
-      if (fd < FD_SETSIZE)
-#endif
+      if ( !(rc = poll (&pfd, 1, delay)) )
         {
-          FD_ZERO(&rfds);
-          FD_SET(fd, &rfds);
-          tv.tv_sec = delay;
-          tv.tv_usec = delay? 0 : 100000;
-          if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) )
-            {
-              any_need_entropy = 1;
-              delay = 3; /* Use 3 seconds henceforth.  */
-              continue;
-            }
-          else if( rc == -1 )
-            {
-              log_error ("select() error: %s\n", strerror(errno));
-              if (!delay)
-                delay = 1; /* Use 1 second if we encounter an error before
-                              we have ever blocked.  */
-              continue;
-            }
+          any_need_entropy = 1;
+          delay = 3000; /* Use 3 seconds henceforth.  */
+          continue;
+        }
+      else if( rc == -1 )
+        {
+          log_error ("poll() error: %s\n", strerror (errno));
+          if (!delay)
+            delay = 1000; /* Use 1 second if we encounter an error before
+                             we have ever blocked.  */
+          continue;
         }

       do
--



More information about the Gcrypt-devel mailing list