http://qs321.pair.com?node_id=1032725

saintmike has asked for the wisdom of the Perl Monks concerning the following question:

There's funny cases in Perl where a close() on a pipe returns an error because of a signal handler having accidentally reaped the process before close() gets to it:

The second trap with SIGCHLD is related to Perl, not the operating system. Because system , open , and backticks all fork subprocesses and the operating system sends your process a SIGCHLD whenever any of its subprocesses exit, you could get called for something you weren't expecting. The built-in operations all wait for the child themselves, so sometimes the SIGCHLD will arrive before the close on the filehandle blocks to reap it. If the signal handler gets to it first, the zombie won't be there for the normal close. This makes close return false and set $! to "No child processes".
(Perl Cookbook)

As the maintainer of a module, I have no insight in what people's signal handlers are doing and would like to shut up if I detect this situation. If close() fails because of this error, it's (probably) ok and I don't want to bother the user with it, if it fails with something else, I want to raise an exception. What's the best way to do this? Checking $! for the literal string "No child processes" seem frivolous, wouldn't this be something else in other locales maybe?

  • Comment on Check for "No child processes" internationally

Replies are listed 'Best First'.
Re: Check for "No child processes" internationally
by davido (Cardinal) on May 09, 2013 at 06:45 UTC

    I don't think that "No child process" is locale sensitive, but on some platforms could produce "No children" instead (citation). However, you can ignore the error message's text by remembering that $! is a dual-valued variable; In string context it returns the error message. In numeric context, it returns the error number, which can be tested against the &Errno::ECHILD constant (Errno).

    Or you can use %! in some variant on the example code shown in Errno's POD:

    # A variation on Errno's POD example: use Errno qw( ECHILD ); # ........ if ( not close $something ) { if( not $!{ECHILD} ) { die "Houston, we have a problem: $!"; } else { # Silence is golden; ECHILD is silent. } }

    Dave

      # A variation on Errno's POD example: use Errno qw( ECHILD );

      :) Unless you need the number/constant, you don't need to import from Errno

      Also, you don't need to actually use Errno;, using %! in your code will load Errno for you

        Thanks for the tips. :)

        The updated code (removed the 'use', and of course the import):

        # A variation on Errno's POD example: # ........ Do your stuff ........ if ( not close $something ) { if( not $!{ECHILD} ) { die "Houston, we have a problem: $!"; } else { # Silence is golden; ECHILD is silent. } }

        Dave

Re: Check for "No child processes" internationally (Errno %!)
by Anonymous Monk on May 09, 2013 at 06:48 UTC

    See perlvar#%! and/or Errno

    $ perl -le " print $_, ' ', $!=$_ for 1 .. 1555" |ack child 10 No child processes 128 There are no child processes to wait for. 1406 Cannot create a top-level child window. 1442 The window is not a child window. $ perl -MErrno -le " printf qq/%5s %s\n/ , Errno->$_ , $_ for grep /CH +ILD/, keys %! " 1020 ERROR_KEY_HAS_CHILDREN 8332 ERROR_DS_CHILDREN_EXIST 1442 ERROR_NOT_CHILD_WINDOW 8422 ERROR_DS_CANT_RETRIEVE_CHILD 1406 ERROR_TLW_WITH_WSCHILD 1436 ERROR_CHILD_WINDOW_MENU 129 ERROR_CHILD_NOT_COMPLETE 1021 ERROR_CHILD_MUST_BE_VOLATILE 10 ECHILD 1445 ERROR_NON_MDICHILD_WINDOW 128 ERROR_WAIT_NO_CHILDREN 8613 ERROR_DS_EXISTING_AD_CHILD_NC $ perldoc -v %! %OS_ERROR %ERRNO %! Each element of "%!" has a true value only if $! is set to + that value. For example, $!{ENOENT} is true if and only if the current value of $! is "ENOENT"; that is, if the most rece +nt error was "No such file or directory" (or its moral equiva +lent: not all operating systems give that exact error, and certa +inly not all languages). To check if a particular key is meanin +gful on your system, use "exists $!{the_key}"; for a list of le +gal keys, use "keys %!". See Errno for more information, and a +lso see "$!". This variable was added in Perl 5.005.