core: Optimize fork/exec for *BSD and Solaris.
authorWerner Koch <wk@gnupg.org>
Fri, 3 Feb 2017 12:56:23 +0000 (13:56 +0100)
committerWerner Koch <wk@gnupg.org>
Fri, 3 Feb 2017 12:56:23 +0000 (13:56 +0100)
* configure.ac (closefrom): Add to ac_check_funcs.
* src/posix-io.c (_gpgme_io_spawn): Use closefrom.

Signed-off-by: Werner Koch <wk@gnupg.org>
configure.ac
src/posix-io.c

index 9903751..f28480b 100644 (file)
@@ -694,7 +694,7 @@ fi
 #
 
 # Check for getgid etc
-AC_CHECK_FUNCS(getgid getegid)
+AC_CHECK_FUNCS(getgid getegid closefrom)
 
 
 # Replacement functions.
index cabb3e5..a351806 100644 (file)
@@ -459,10 +459,9 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
       /* Intermediate child to prevent zombie processes.  */
       if ((pid = fork ()) == 0)
        {
-         int max_fds = get_max_fds ();
-         int fd;
-
          /* Child.  */
+          int max_fds = -1;
+          int fd;
          int seen_stdin = 0;
          int seen_stdout = 0;
          int seen_stderr = 0;
@@ -470,15 +469,40 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
          if (atfork)
            atfork (atforkvalue, 0);
 
-         /* First close all fds which will not be inherited.  */
-         for (fd = 0; fd < max_fds; fd++)
-           {
-             for (i = 0; fd_list[i].fd != -1; i++)
-               if (fd_list[i].fd == fd)
-                 break;
-             if (fd_list[i].fd == -1)
-               close (fd);
-           }
+          /* First close all fds which will not be inherited.  If we
+           * have closefrom(2) we first figure out the highest fd we
+           * do not want to close, then call closefrom, and on success
+           * use the regular code to close all fds up to the start
+           * point of closefrom.  Note that Solaris' closefrom does
+           * not return errors.  */
+#ifdef HAVE_CLOSEFROM
+          {
+            fd = -1;
+            for (i = 0; fd_list[i].fd != -1; i++)
+              if (fd_list[i].fd > fd)
+                fd = fd_list[i].fd;
+            fd++;
+#ifdef __sun
+            closefrom (fd);
+            max_fds = fd;
+#else /*!__sun */
+            while ((i = closefrom (fd)) && errno == EINTR)
+              ;
+            if (!i || errno == EBADF)
+              max_fds = fd;
+#endif /*!__sun*/
+          }
+#endif /*HAVE_CLOSEFROM*/
+          if (max_fds == -1)
+            max_fds = get_max_fds ();
+          for (fd = 0; fd < max_fds; fd++)
+            {
+              for (i = 0; fd_list[i].fd != -1; i++)
+                if (fd_list[i].fd == fd)
+                  break;
+              if (fd_list[i].fd == -1)
+                close (fd);
+            }
 
          /* And now dup and close those to be duplicated.  */
          for (i = 0; fd_list[i].fd != -1; i++)