bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

posix_spawn on AIX


From: Bruno Haible
Subject: posix_spawn on AIX
Date: Thu, 2 Oct 2008 01:26:30 +0200
User-agent: KMail/1.5.4

Hi,

posix_spawn exists on AIX 5.3 and 6.1, but it is unusable. Rainer Tammer
identified two bugs:
  - failure to execute any program in the child process, when the parent
    program uses POSIX threads.
  - when the child process fails to execute the given program, it outputs
    the stdio buffers before calling _exit(127). The parent later flushes
    its stdio buffers as well. So in the end the buffered contents is
    output twice.

I'm committing this:


2008-10-01  Bruno Haible  <address@hidden>

        Avoid the broken posix_spawn function on AIX 5.3 and 6.1.
        * m4/posix_spawn.m4 (gl_POSIX_SPAWN_WORKS): New macro.
        (gl_POSIX_SPAWN_BODY): Invoke it. Set REPLACE_POSIX_SPAWN if needed.
        * doc/posix-functions/posix_spawn.texi: Mention the AIX bugs.
        * doc/posix-functions/posix_spawnp.texi: Likewise.
        * m4/execute.m4 (gl_EXECUTE): Invoke gl_POSIX_SPAWN_WORKS, to check
        whether posix_spawn actually works.
        * m4/pipe.m4 (gl_PIPE): Likewise.
        * modules/execute (Files): Add m4/posix_spawn.m4.
        * modules/pipe (Files): Add m4/posix_spawn.m4.
        Reported and analyzed by Rainer Tammer <address@hidden>.

*** m4/posix_spawn.m4.orig      2008-10-02 01:13:30.000000000 +0200
--- m4/posix_spawn.m4   2008-10-01 13:45:50.000000000 +0200
***************
*** 1,4 ****
! # posix_spawn.m4 serial 1
  dnl Copyright (C) 2008 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
--- 1,4 ----
! # posix_spawn.m4 serial 2
  dnl Copyright (C) 2008 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
***************
*** 36,50 ****
    dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigmask])
    dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigmask])
    dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_destroy])
!   if test $ac_cv_func_posix_spawn != yes; then
      HAVE_POSIX_SPAWN=0
-     dnl For now, assume that if posix_spawn exists, it also works.
-     if false; then
-       REPLACE_POSIX_SPAWN=1
-     fi
    fi
  ])
  
  AC_DEFUN([gl_POSIX_SPAWN_INTERNAL],
  [
    AC_LIBOBJ([spawni])
--- 36,214 ----
    dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigmask])
    dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigmask])
    dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_destroy])
!   if test $ac_cv_func_posix_spawn = yes; then
!     gl_POSIX_SPAWN_WORKS
!     case "$gl_cv_func_posix_spawn_works" in
!       *yes) ;;
!       *) REPLACE_POSIX_SPAWN=1 ;;
!     esac
!   else
      HAVE_POSIX_SPAWN=0
    fi
  ])
  
+ dnl Test whether posix_spawn actually works.
+ dnl posix_spawn on AIX 5.3..6.1 has a bug: When it fails to execute the
+ dnl program, the child process exits with exit() rather than _exit(),
+ dnl which causes the stdio buffers to be flushed. Reported by Rainer Tammer.
+ dnl posix_spawn on AIX 5.3..6.1 has also a second bug: It does not work
+ dnl when POSIX threads are used. But we don't test against this bug here.
+ AC_DEFUN([gl_POSIX_SPAWN_WORKS],
+ [
+   AC_REQUIRE([AC_PROG_CC])
+   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+   AC_CACHE_CHECK([whether posix_spawn works], [gl_cv_func_posix_spawn_works],
+     [if test $cross_compiling = no; then
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <signal.h>
+ #include <spawn.h>
+ #include <stdbool.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ 
+ extern char **environ;
+ 
+ #ifndef STDIN_FILENO
+ # define STDIN_FILENO 0
+ #endif
+ #ifndef STDOUT_FILENO
+ # define STDOUT_FILENO 1
+ #endif
+ #ifndef STDERR_FILENO
+ # define STDERR_FILENO 2
+ #endif
+ 
+ #ifndef WTERMSIG
+ # define WTERMSIG(x) ((x) & 0x7f)
+ #endif
+ #ifndef WCOREDUMP
+ # define WCOREDUMP(x) ((x) & 0x80)
+ #endif
+ #ifndef WEXITSTATUS
+ # define WEXITSTATUS(x) (((x) >> 8) & 0xff)
+ #endif
+ #ifndef WIFSIGNALED
+ # define WIFSIGNALED(x) (WTERMSIG (x) != 0 && WTERMSIG(x) != 0x7f)
+ #endif
+ #ifndef WIFEXITED
+ # define WIFEXITED(x) (WTERMSIG (x) == 0)
+ #endif
+ #ifndef WIFSTOPPED
+ # define WIFSTOPPED(x) (WTERMSIG (x) == 0x7f)
+ #endif
+ 
+ #define CHILD_PROGRAM_FILENAME "/non/exist/ent"
+ 
+ static int
+ fd_safer (int fd)
+ {
+   if (0 <= fd && fd <= 2)
+     {
+       int f = fd_safer (dup (fd));
+       int e = errno;
+       close (fd);
+       errno = e;
+       fd = f;
+     }
+ 
+   return fd;
+ }  
+ ]],
+ dnl Now comes the main() function.
+ [[
+   char *argv[2] = { CHILD_PROGRAM_FILENAME, NULL };
+   int ofd[2];
+   sigset_t blocked_signals;
+   sigset_t fatal_signal_set;
+   posix_spawn_file_actions_t actions;
+   bool actions_allocated;
+   posix_spawnattr_t attrs;
+   bool attrs_allocated;
+   int err;
+   pid_t child;
+   int status;
+   int exitstatus;
+ 
+   setvbuf (stdout, NULL, _IOFBF, 0);
+   puts ("This should be seen only once.");
+   if (pipe (ofd) < 0 || (ofd[1] = fd_safer (ofd[1])) < 0)
+     {
+       perror ("cannot create pipe");
+       exit (1);
+     }
+   sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
+   sigemptyset (&fatal_signal_set);
+   sigaddset (&fatal_signal_set, SIGINT);
+   sigaddset (&fatal_signal_set, SIGTERM);
+   sigaddset (&fatal_signal_set, SIGHUP);
+   sigaddset (&fatal_signal_set, SIGPIPE);
+   sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
+   actions_allocated = false;
+   attrs_allocated = false;
+   if ((err = posix_spawn_file_actions_init (&actions)) != 0
+       || (actions_allocated = true,
+           (err = posix_spawn_file_actions_adddup2 (&actions, ofd[0], 
STDIN_FILENO)) != 0
+           || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
+           || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
+           || (err = posix_spawnattr_init (&attrs)) != 0
+           || (attrs_allocated = true,
+               (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) 
!= 0
+               || (err = posix_spawnattr_setflags (&attrs, 
POSIX_SPAWN_SETSIGMASK)) != 0)
+           || (err = posix_spawnp (&child, CHILD_PROGRAM_FILENAME, &actions, 
&attrs, argv, environ)) != 0))
+     {
+       if (actions_allocated)
+       posix_spawn_file_actions_destroy (&actions);
+       if (attrs_allocated)
+       posix_spawnattr_destroy (&attrs);
+       sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+       errno = err;
+       perror ("subprocess failed");
+       exit (1);
+     }
+   posix_spawn_file_actions_destroy (&actions);
+   posix_spawnattr_destroy (&attrs);
+   sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+   close (ofd[0]);
+   close (ofd[1]);
+   status = 0;
+   while (waitpid (child, &status, 0) != child)
+     ;
+   if (!WIFEXITED (status))
+     {
+       fprintf (stderr, "subprocess terminated with unexpected wait status 
%d\n", status);
+       exit (1);
+     }
+   exitstatus = WEXITSTATUS (status);
+   if (exitstatus != 127)
+     {
+       fprintf (stderr, "subprocess terminated with unexpected exit status 
%d\n", exitstatus);
+       exit (1);
+     }
+ ]])],
+          [if test -s conftest$ac_exeext \
+              && ./conftest$ac_exeext > conftest.out \
+              && echo 'This should be seen only once.' > conftest.ok \
+              && cmp conftest.out conftest.ok > /dev/null; then
+             gl_cv_func_posix_spawn_works=yes
+           else
+             gl_cv_func_posix_spawn_works=no
+           fi],
+          [gl_cv_func_posix_spawn_works=no])
+      else
+        case "$host_os" in
+          aix*) gl_cv_func_posix_spawn_works="guessing no";;
+          *)    gl_cv_func_posix_spawn_works="guessing yes";;
+        esac
+      fi
+     ])
+ ])
+ 
  AC_DEFUN([gl_POSIX_SPAWN_INTERNAL],
  [
    AC_LIBOBJ([spawni])
*** doc/posix-functions/posix_spawn.texi.orig   2008-10-02 01:13:30.000000000 
+0200
--- doc/posix-functions/posix_spawn.texi        2008-10-02 01:10:24.000000000 
+0200
***************
*** 11,21 ****
  @item
  This function is missing on some platforms:
  MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 
6.5, OSF/1 5.1, Solaris 9, Cygwin, mingw, Interix 3.5, BeOS.
  @end itemize
  
  Portability problems not fixed by Gnulib:
  @itemize
  @item
  This function does not work on some platforms:
! mingw.
  @end itemize
--- 11,25 ----
  @item
  This function is missing on some platforms:
  MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 
6.5, OSF/1 5.1, Solaris 9, Cygwin, mingw, Interix 3.5, BeOS.
+ @item
+ When this function fails, it causes the stdio buffer contents to be output
+ twice on some platforms:
+ AIX 6.1.
  @end itemize
  
  Portability problems not fixed by Gnulib:
  @itemize
  @item
  This function does not work on some platforms:
! AIX 6.1 (under particular circumstances), mingw.
  @end itemize
*** doc/posix-functions/posix_spawnp.texi.orig  2008-10-02 01:13:30.000000000 
+0200
--- doc/posix-functions/posix_spawnp.texi       2008-10-02 01:10:25.000000000 
+0200
***************
*** 11,21 ****
  @item
  This function is missing on some platforms:
  MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 
6.5, OSF/1 5.1, Solaris 9, Cygwin, mingw, Interix 3.5, BeOS.
  @end itemize
  
  Portability problems not fixed by Gnulib:
  @itemize
  @item
  This function does not work on some platforms:
! mingw.
  @end itemize
--- 11,25 ----
  @item
  This function is missing on some platforms:
  MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 
6.5, OSF/1 5.1, Solaris 9, Cygwin, mingw, Interix 3.5, BeOS.
+ @item
+ When this function fails, it causes the stdio buffer contents to be output
+ twice on some platforms:
+ AIX 6.1.
  @end itemize
  
  Portability problems not fixed by Gnulib:
  @itemize
  @item
  This function does not work on some platforms:
! AIX 6.1 (under particular circumstances), mingw.
  @end itemize
*** m4/execute.m4.orig  2008-10-02 01:13:30.000000000 +0200
--- m4/execute.m4       2008-10-01 13:44:57.000000000 +0200
***************
*** 1,5 ****
! # execute.m4 serial 1
! dnl Copyright (C) 2003 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
  dnl with or without modifications, as long as this notice is preserved.
--- 1,5 ----
! # execute.m4 serial 2
! dnl Copyright (C) 2003, 2008 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
  dnl with or without modifications, as long as this notice is preserved.
***************
*** 11,15 ****
    AC_REQUIRE([AC_TYPE_MODE_T])
    AC_CHECK_HEADERS_ONCE(unistd.h)
    AC_REQUIRE([AC_FUNC_FORK])
!   AC_CHECK_FUNCS(posix_spawn)
  ])
--- 11,23 ----
    AC_REQUIRE([AC_TYPE_MODE_T])
    AC_CHECK_HEADERS_ONCE(unistd.h)
    AC_REQUIRE([AC_FUNC_FORK])
!   AC_CHECK_FUNC([posix_spawn],
!     [gl_POSIX_SPAWN_WORKS
!      case "$gl_cv_func_posix_spawn_works" in
!        *yes)
!          AC_DEFINE([HAVE_POSIX_SPAWN], 1,
!            [Define if you have the posix_spawn() function and it works.])
!          ;;
!      esac
!     ])
  ])
*** m4/pipe.m4.orig     2008-10-02 01:13:30.000000000 +0200
--- m4/pipe.m4  2008-10-01 13:45:13.000000000 +0200
***************
*** 1,5 ****
! # pipe.m4 serial 1
! dnl Copyright (C) 2004 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
  dnl with or without modifications, as long as this notice is preserved.
--- 1,5 ----
! # pipe.m4 serial 2
! dnl Copyright (C) 2004, 2008 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
  dnl with or without modifications, as long as this notice is preserved.
***************
*** 12,16 ****
    AC_REQUIRE([AC_C_INLINE])
    AC_REQUIRE([AC_TYPE_MODE_T])
    AC_REQUIRE([AC_FUNC_FORK])
!   AC_CHECK_FUNCS(posix_spawn)
  ])
--- 12,24 ----
    AC_REQUIRE([AC_C_INLINE])
    AC_REQUIRE([AC_TYPE_MODE_T])
    AC_REQUIRE([AC_FUNC_FORK])
!   AC_CHECK_FUNC([posix_spawn],
!     [gl_POSIX_SPAWN_WORKS
!      case "$gl_cv_func_posix_spawn_works" in
!        *yes)
!          AC_DEFINE([HAVE_POSIX_SPAWN], 1,
!            [Define if you have the posix_spawn() function and it works.])
!          ;;
!      esac
!     ])
  ])
*** modules/execute.orig        2008-10-02 01:13:30.000000000 +0200
--- modules/execute     2008-10-01 13:45:40.000000000 +0200
***************
*** 6,11 ****
--- 6,12 ----
  lib/execute.c
  lib/w32spawn.h
  m4/execute.m4
+ m4/posix_spawn.m4
  
  Depends-on:
  error
*** modules/pipe.orig   2008-10-02 01:13:30.000000000 +0200
--- modules/pipe        2008-10-01 13:45:44.000000000 +0200
***************
*** 6,11 ****
--- 6,12 ----
  lib/pipe.c
  lib/w32spawn.h
  m4/pipe.m4
+ m4/posix_spawn.m4
  
  Depends-on:
  environ





reply via email to

[Prev in Thread] Current Thread [Next in Thread]