in reply to END{} Subroutine not being called for Child process

If you kill your program the END block will not be run, unless you handled the kill signal. I think you only handle HUP, so any other terminal signal (INT, TERM, KILL etc.) will terminate your program without the END block being run. See BEGIN, UNITCHECK, CHECK, INIT and END for details.

An END code block is executed as late as possible, that is, after perl has finished running the program and just before the interpreter is being exited, even if it is exiting as a result of a die() function. (But not if it's morphing into another program via exec, or being blown out of the water by a signal--you have to trap that yourself (if you can).)

You open STDOUT and STDERR to /dev/null but then you print to STDERR and call die in various circumstances. For example, in the child the output from the print at the beginning of programExit() will go to /dev/null and will not be seen on your terminal. It might be better to open STDOUT and STDERR to a log file. You might then find why other operations are failing.

I note also that in the loop in your child you fork and both the parent and child continue to loop (the child after executing a system command). Maybe the child should exit after executing the system command or maybe the child should be using exec rather than system.

  • Comment on Re: END{} Subroutine not being called for Child process

Replies are listed 'Best First'.
Re^2: END{} Subroutine not being called for Child process
by SituationSoap (Acolyte) on Aug 04, 2009 at 12:54 UTC

    Appreciate the info on the SIGTERM trapping, that looks like it's my problem. I wasn't aware that sending a kill signal just blew the program out of the water; I think that comes from never having had to code in this context before.

    I've been considering moving STD outputs to files instead of to /dev/null, although at this point, I've coded around much of what's there, so I'm not sure how much more benefit I would gain. I do switch back and forth between having those lines commented out and not; the line you were referring to in the programExit() subroutine was intended to see if I was hitting the END{} sub, and STDOUT was open when I was using it.

    I assume the code you're referring to in the last paragraph is this one:

    if(!($pid = fork)){ system("$parser $script"); }

    I'm confused as to what you're saying, though. When I fork the process, I believed that the process in question would only run what was inside the bracket, then exit. Is that not the case? Should I be using exec(), in that case?

      When I fork the process, I believed that the process in question would only run what was inside the bracket, then exit.

      if doesn't do anything special if the condition happens to be a call to fork. It won't exit if you don't tell it to exit. Indeed, it sounds like you want exec instead of system.

        Thanks for the clarification. I've made that change, and everything seems to be working fine. I appreciate your help.

      In general I don't redirect STDOUT or STDERR to /dev/null and never when I am debugging. Very often, when something unexpected goes wrong, important clues are written to one of these outputs. This may include output from modules that have been used, which might not be obvious without reading all the module source.

        Point well taken. I can see the benefits of not redirecting those outputs, especially during a debugging process. From a long term solution, I think this is the right answer for the script as written, however. If I were to rewrite it, I might rewrite it to simply open those outputs to files instead, but the handling code is already written (and readable, and functional), so I don't see a lot of value in re-factoring that part of the code right now.