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 <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]>. *** 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