Rafael Garcia-Suarez <[EMAIL PROTECTED]> writes: > Makes sense to me... more than reformulating $? anyway (historically > perl trying to hide the differences between platforms rather than to > show them.)
This is a patch that I think can be applied to blead. It contains additional doc tweaks as well as test suite additions to prove that ${^CHILD_ERROR_NATIVE} works as expected. I've tested this patch on Linux and AIX. --Gisle diff -ru perl-current/doio.c perl-hack/doio.c --- perl-current/doio.c 2005-05-11 10:24:13.000000000 +0200 +++ perl-hack/doio.c 2005-05-18 13:47:31.808879838 +0200 @@ -1046,7 +1046,7 @@ const int status = PerlProc_pclose(IoIFP(io)); if (not_implicit) { STATUS_NATIVE_SET(status); - retval = (STATUS_POSIX == 0); + retval = (STATUS_UNIX == 0); } else { retval = (status != -1); diff -ru perl-current/embedvar.h perl-hack/embedvar.h --- perl-current/embedvar.h 2005-05-13 13:38:15.000000000 +0200 +++ perl-hack/embedvar.h 2005-05-18 13:47:31.809879632 +0200 @@ -386,6 +386,7 @@ #define PL_srand_called (vTHX->Isrand_called) #define PL_stashcache (vTHX->Istashcache) #define PL_statusvalue (vTHX->Istatusvalue) +#define PL_statusvalue_posix (vTHX->Istatusvalue_posix) #define PL_statusvalue_vms (vTHX->Istatusvalue_vms) #define PL_stderrgv (vTHX->Istderrgv) #define PL_stdingv (vTHX->Istdingv) @@ -693,6 +694,7 @@ #define PL_Isrand_called PL_srand_called #define PL_Istashcache PL_stashcache #define PL_Istatusvalue PL_statusvalue +#define PL_Istatusvalue_posix PL_statusvalue_posix #define PL_Istatusvalue_vms PL_statusvalue_vms #define PL_Istderrgv PL_stderrgv #define PL_Istdingv PL_stdingv diff -ru perl-current/gv.c perl-hack/gv.c --- perl-current/gv.c 2005-05-11 10:24:13.000000000 +0200 +++ perl-hack/gv.c 2005-05-18 13:47:31.810879425 +0200 @@ -932,6 +932,10 @@ if (strEQ(name2, "ERSION")) GvMULTI_on(gv); break; + case '\003': /* $^CHILD_ERROR_NATIVE */ + if (strEQ(name2, "HILD_ERROR_NATIVE")) + goto magicalize; + break; case '\005': /* $^ENCODING */ if (strEQ(name2, "NCODING")) goto magicalize; diff -ru perl-current/intrpvar.h perl-hack/intrpvar.h --- perl-current/intrpvar.h 2005-05-13 13:38:15.000000000 +0200 +++ perl-hack/intrpvar.h 2005-05-18 13:47:31.810879425 +0200 @@ -74,6 +74,8 @@ PERLVAR(Iexit_flags, U8) /* was exit() unexpected, etc. */ #ifdef VMS PERLVAR(Istatusvalue_vms,U32) +#else +PERLVAR(Istatusvalue_posix,I32) #endif /* shortcuts to various I/O objects */ diff -ru perl-current/mg.c perl-hack/mg.c --- perl-current/mg.c 2005-05-17 17:44:22.000000000 +0200 +++ perl-hack/mg.c 2005-05-18 13:47:31.812879013 +0200 @@ -581,8 +581,13 @@ case '\001': /* ^A */ sv_setsv(sv, PL_bodytarget); break; - case '\003': /* ^C */ - sv_setiv(sv, (IV)PL_minus_c); + case '\003': /* ^C, ^CHILD_ERROR_NATIVE */ + if (*(mg->mg_ptr+1) == '\0') { + sv_setiv(sv, (IV)PL_minus_c); + } + else if (strEQ(mg->mg_ptr, "\003HILD_ERROR_NATIVE")) { + sv_setiv(sv, (IV)STATUS_NATIVE); + } break; case '\004': /* ^D */ @@ -2291,7 +2296,7 @@ STATUS_NATIVE_SET((U32)(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv))); else #endif - STATUS_POSIX_SET(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); + STATUS_UNIX_SET(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv)); break; case '!': { diff -ru perl-current/perl.c perl-hack/perl.c --- perl-current/perl.c 2005-05-16 19:23:31.000000000 +0200 +++ perl-hack/perl.c 2005-05-18 13:47:31.814878600 +0200 @@ -4806,13 +4806,13 @@ #else int exitstatus; if (errno & 255) - STATUS_POSIX_SET(errno); + STATUS_UNIX_SET(errno); else { - exitstatus = STATUS_POSIX >> 8; + exitstatus = STATUS_UNIX >> 8; if (exitstatus & 255) - STATUS_POSIX_SET(exitstatus); + STATUS_UNIX_SET(exitstatus); else - STATUS_POSIX_SET(255); + STATUS_UNIX_SET(255); } #endif my_exit_jump(); diff -ru perl-current/perl.h perl-hack/perl.h --- perl-current/perl.h 2005-05-17 21:14:54.000000000 +0200 +++ perl-hack/perl.h 2005-05-18 13:47:31.817877981 +0200 @@ -2414,6 +2414,7 @@ # include "netware.h" #endif +#define STATUS_UNIX PL_statusvalue #ifdef VMS # define STATUS_NATIVE PL_statusvalue_vms # define STATUS_NATIVE_EXPORT \ @@ -2430,13 +2431,12 @@ else \ PL_statusvalue = (PL_statusvalue_vms & STS$M_SEVERITY) << 8; \ } STMT_END -# define STATUS_POSIX PL_statusvalue # ifdef VMSISH_STATUS -# define STATUS_CURRENT (VMSISH_STATUS ? STATUS_NATIVE : STATUS_POSIX) +# define STATUS_CURRENT (VMSISH_STATUS ? STATUS_NATIVE : STATUS_UNIX) # else -# define STATUS_CURRENT STATUS_POSIX +# define STATUS_CURRENT STATUS_UNIX # endif -# define STATUS_POSIX_SET(n) \ +# define STATUS_UNIX_SET(n) \ STMT_START { \ PL_statusvalue = (n); \ if (PL_statusvalue != -1) { \ @@ -2448,19 +2448,55 @@ # define STATUS_ALL_SUCCESS (PL_statusvalue = 0, PL_statusvalue_vms = 1) # define STATUS_ALL_FAILURE (PL_statusvalue = 1, PL_statusvalue_vms = 44) #else -# define STATUS_NATIVE STATUS_POSIX -# define STATUS_NATIVE_EXPORT STATUS_POSIX -# define STATUS_NATIVE_SET STATUS_POSIX_SET -# define STATUS_POSIX PL_statusvalue -# define STATUS_POSIX_SET(n) \ +# define STATUS_NATIVE PL_statusvalue_posix +# define STATUS_NATIVE_EXPORT STATUS_NATIVE +# if defined(WCOREDUMP) +# define STATUS_NATIVE_SET(n) \ + STMT_START { \ + PL_statusvalue_posix = (n); \ + if (PL_statusvalue_posix == -1) \ + PL_statusvalue = -1; \ + else { \ + PL_statusvalue = \ + (WIFEXITED(PL_statusvalue_posix) ? (WEXITSTATUS(PL_statusvalue_posix) << 8) : 0) | \ + (WIFSIGNALED(PL_statusvalue_posix) ? (WTERMSIG(PL_statusvalue_posix) & 0x7F) : 0) | \ + (WIFSIGNALED(PL_statusvalue_posix) && WCOREDUMP(PL_statusvalue_posix) ? 0x80 : 0); \ + } \ + } STMT_END +# elif defined(WIFEXITED) +# define STATUS_NATIVE_SET(n) \ + STMT_START { \ + PL_statusvalue_posix = (n); \ + if (PL_statusvalue_posix == -1) \ + PL_statusvalue = -1; \ + else { \ + PL_statusvalue = \ + (WIFEXITED(PL_statusvalue_posix) ? (WEXITSTATUS(PL_statusvalue_posix) << 8) : 0) | \ + (WIFSIGNALED(PL_statusvalue_posix) ? (WTERMSIG(PL_statusvalue_posix) & 0x7F) : 0); \ + } \ + } STMT_END +# else +# define STATUS_NATIVE_SET(n) \ + STMT_START { \ + PL_statusvalue_posix = (n); \ + if (PL_statusvalue_posix == -1) \ + PL_statusvalue = -1; \ + else { \ + PL_statusvalue = \ + PL_statusvalue_posix & 0xFFFF; \ + } \ + } STMT_END +# endif +# define STATUS_UNIX_SET(n) \ STMT_START { \ PL_statusvalue = (n); \ + PL_statusvalue_posix = PL_statusvalue; \ if (PL_statusvalue != -1) \ PL_statusvalue &= 0xFFFF; \ } STMT_END -# define STATUS_CURRENT STATUS_POSIX -# define STATUS_ALL_SUCCESS (PL_statusvalue = 0) -# define STATUS_ALL_FAILURE (PL_statusvalue = 1) +# define STATUS_CURRENT STATUS_UNIX +# define STATUS_ALL_SUCCESS (PL_statusvalue = 0, PL_statusvalue_posix = 0) +# define STATUS_ALL_FAILURE (PL_statusvalue = 1, PL_statusvalue_posix = 1) #endif /* flags in PL_exit_flags for nature of exit() */ diff -ru perl-current/perlapi.h perl-hack/perlapi.h --- perl-current/perlapi.h 2005-05-13 13:38:15.000000000 +0200 +++ perl-hack/perlapi.h 2005-05-18 13:47:31.817877981 +0200 @@ -551,6 +551,8 @@ #define PL_stashcache (*Perl_Istashcache_ptr(aTHX)) #undef PL_statusvalue #define PL_statusvalue (*Perl_Istatusvalue_ptr(aTHX)) +#undef PL_statusvalue_posix +#define PL_statusvalue_posix (*Perl_Istatusvalue_posix_ptr(aTHX)) #undef PL_statusvalue_vms #define PL_statusvalue_vms (*Perl_Istatusvalue_vms_ptr(aTHX)) #undef PL_stderrgv diff -ru perl-current/pod/perlfunc.pod perl-hack/pod/perlfunc.pod --- perl-current/pod/perlfunc.pod 2005-05-12 11:15:46.000000000 +0200 +++ perl-hack/pod/perlfunc.pod 2005-05-18 14:59:07.807723949 +0200 @@ -782,7 +782,8 @@ program exited non-zero, C<$!> will be set to C<0>.) Closing a pipe also waits for the process executing on the pipe to complete, in case you want to look at the output of the pipe afterwards, and -implicitly puts the exit status value of that command into C<$?>. +implicitly puts the exit status value of that command into C<$?> and +C<${^CHILD_ERROR_NATIVE}>. Prematurely closing the read end of a pipe (i.e. before the process writing to it at the other end has closed it) will result in a @@ -3126,7 +3127,8 @@ of $^F. See L<perlvar/$^F>. Closing any piped filehandle causes the parent process to wait for the -child to finish, and returns the status value in C<$?>. +child to finish, and returns the status value in C<$?> and +C<${^CHILD_ERROR_NATIVE}>. The filename passed to 2-argument (or 1-argument) form of open() will have leading and trailing whitespace deleted, and the normal @@ -5975,8 +5977,8 @@ printf "child exited with value %d\n", $? >> 8; } -or more portably by using the W*() calls of the POSIX extension; -see L<perlport> for more information. +Alternatively you might inspect the value of C<${^CHILD_ERROR_NATIVE}> +with the W*() calls of the POSIX extension. When the arguments get executed via the system shell, results and return codes will be subject to its quirks and capabilities. @@ -6761,7 +6763,8 @@ Behaves like the wait(2) system call on your system: it waits for a child process to terminate and returns the pid of the deceased process, or -C<-1> if there are no child processes. The status is returned in C<$?>. +C<-1> if there are no child processes. The status is returned in C<$?> +and C<{^CHILD_ERROR_NATIVE}. Note that a return value of C<-1> could mean that child processes are being automatically reaped, as described in L<perlipc>. @@ -6770,7 +6773,7 @@ Waits for a particular child process to terminate and returns the pid of the deceased process, or C<-1> if there is no such child process. On some systems, a value of 0 indicates that there are processes still running. -The status is returned in C<$?>. If you say +The status is returned in C<$?> and C<{^CHILD_ERROR_NATIVE}. If you say use POSIX ":sys_wait_h"; #... diff -ru perl-current/pod/perlport.pod perl-hack/pod/perlport.pod --- perl-current/pod/perlport.pod 2005-05-04 23:18:41.000000000 +0200 +++ perl-hack/pod/perlport.pod 2005-05-18 14:14:09.207332644 +0200 @@ -1964,16 +1964,6 @@ =item system LIST -In general, do not assume the UNIX/POSIX semantics that you can shift -C<$?> right by eight to get the exit value, or that C<$? & 127> -would give you the number of the signal that terminated the program, -or that C<$? & 128> would test true if the program was terminated by a -coredump. Instead, use the POSIX W*() interfaces: for example, use -WIFEXITED($?) and WEXITVALUE($?) to test for a normal exit and the exit -value, WIFSIGNALED($?) and WTERMSIG($?) for a signal exit and the -signal. Core dumping is not a portable concept, so there's no portable -way to test for that. - Only implemented if ToolServer is installed. (S<Mac OS>) As an optimization, may not call the command shell specified in diff -ru perl-current/pod/perlvar.pod perl-hack/pod/perlvar.pod --- perl-current/pod/perlvar.pod 2005-05-04 14:42:51.000000000 +0200 +++ perl-hack/pod/perlvar.pod 2005-05-18 13:47:31.822876949 +0200 @@ -617,7 +617,7 @@ The status returned by the last pipe close, backtick (C<``>) command, successful call to wait() or waitpid(), or from the system() operator. This is just the 16-bit status word returned by the -wait() system call (or else is made up to look like it). Thus, the +traditional Unix wait() system call (or else is made up to look like it). Thus, the exit value of the subprocess is really (C<<< $? >> 8 >>>), and C<$? & 127> gives which signal, if any, the process died from, and C<$? & 128> reports whether there was a core dump. (Mnemonic: @@ -643,6 +643,17 @@ Also see L<Error Indicators>. +=item ${^CHILD_ERROR_NATIVE} + +The native status returned by the last pipe close, backtick (C<``>) +command, successful call to wait() or waitpid(), or from the system() +operator. On POSIX like system this value can be decoded with the +WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WIFSTOPPED, WSTOPSIG +and WIFCONTINUED functions provided by the L<POSIX> module. + +Under VMS this reflect the actual VMS exit status; i.e. it is the same +as $? when the pragma C<use vmsish 'status'> is in effect. + =item ${^ENCODING} The I<object reference> to the Encode object that is used to convert diff -ru perl-current/t/run/exit.t perl-hack/t/run/exit.t --- perl-current/t/run/exit.t 2004-01-07 20:28:47.000000000 +0100 +++ perl-hack/t/run/exit.t 2005-05-18 14:45:07.911815970 +0200 @@ -20,7 +20,7 @@ BEGIN { # MacOS system() doesn't have good return value - $numtests = ($^O eq 'VMS') ? 7 : ($^O eq 'MacOS') ? 0 : 3; + $numtests = ($^O eq 'VMS') ? 10 : ($^O eq 'MacOS') ? 0 : 17; } require "test.pl"; @@ -31,11 +31,35 @@ $exit = run('exit'); is( $exit >> 8, 0, 'Normal exit' ); +is( $exit, $?, 'Normal exit $?' ); +is( ${^CHILD_ERROR_NATIVE}, 0, 'Normal exit ${^CHILD_ERROR_NATIVE}' ); if ($^O ne 'VMS') { + my $posix_ok = eval { require POSIX; }; $exit = run('exit 42'); is( $exit >> 8, 42, 'Non-zero exit' ); + is( $exit, $?, 'Non-zero exit $?' ); + isnt( !${^CHILD_ERROR_NATIVE}, 0, 'Non-zero exit ${^CHILD_ERROR_NATIVE}' ); + SKIP: { + skip("No POSIX", 3) unless $posix_ok; + ok(POSIX::WIFEXITED(${^CHILD_ERROR_NATIVE}), "WIFEXITED"); + ok(!POSIX::WIFSIGNALED(${^CHILD_ERROR_NATIVE}), "WIFSIGNALED"); + is(POSIX::WEXITSTATUS(${^CHILD_ERROR_NATIVE}), 42, "WEXITSTATUS"); + } + + $exit = run('kill 15, $$; sleep(1);'); + + is( $exit & 127, 15, 'Term by signal' ); + ok( !($exit & 128), 'No core dump' ); + is( $? & 127, 15, 'Term by signal $?' ); + isnt( ${^CHILD_ERROR_NATIVE}, 0, 'Term by signal ${^CHILD_ERROR_NATIVE}' ); + SKIP: { + skip("No POSIX", 3) unless $posix_ok; + ok(!POSIX::WIFEXITED(${^CHILD_ERROR_NATIVE}), "WIFEXITED"); + ok(POSIX::WIFSIGNALED(${^CHILD_ERROR_NATIVE}), "WIFSIGNALED"); + is(POSIX::WTERMSIG(${^CHILD_ERROR_NATIVE}), 15, "WTERMSIG"); + } } else { @@ -63,7 +87,7 @@ # On VMS, in the child process the actual exit status will be SS$_ABORT, # which is what you get from any non-zero value of $? that has been -# dePOSIXified by STATUS_POSIX_SET. In the parent process, all we'll +# dePOSIXified by STATUS_UNIX_SET. In the parent process, all we'll # see are the severity bits (0-2) shifted left by 8. $exit_arg = (44 & 7) if $^O eq 'VMS';