in reply to Re: parent process stuck in read(2) on pipe opened to child process using backtick
in thread parent process stuck in read(2) on pipe opened to child process using backtick

Thanks, Guys, for the insights so far. Well, I have been trying to figure out the best way to work-around my original issue, based on the inputs I received, but today I stumbled onto something really weird.

My perl thread is stuck in read(2) again but this time it is because some other completely unrelated thread has a reference to that pipe.

[root@onong 5227]# strace -s 1024 -p 5227 Process 5227 attached - interrupt to quit read(28, The fd in question is a pipe: [root@onong tmp]# ls -l /proc/5227/fd total 0 lr-x------ 1 root root 64 Feb 21 02:02 0 -> /dev/null l-wx------ 1 root root 64 Feb 21 02:02 1 -> /tmp/abc.log . . lr-x------ 1 root root 64 Feb 21 02:02 28 -> pipe:[28443] Following are the processes which have a reference to this pipe: [root@onong tmp]# lsof | grep 28443 perl 5049 root 28r FIFO 0,6 + 28443 pipe ntpd 9936 ntp 28r FIFO 0,6 + 28443 pipe ntpd 9936 ntp 29w FIFO 0,6 + 28443 pipe dhcpd 10228 root 28r FIFO 0,6 + 28443 pipe java 15518 root 28r FIFO 0,6 + 28443 pipe

As you can see, the ntpd process has the write-end of the pipe open!!!!

Any ideas as to how this is even possible????

  • Comment on Re^2: parent process stuck in read(2) on pipe opened to child process using backtick
  • Download Code

Replies are listed 'Best First'.
Re^3: parent process stuck in read(2) on pipe opened to child process using backtick
by onong (Initiate) on Feb 25, 2012 at 14:29 UTC

    Posting my findings with the hope that it would be of help to someone out there.

    system and backtick both fork a child process. Backtick differs from system in that it opens a pipe for gathering the child process/command’s output. And this is what perl doc on fork has to say about file descriptors:

    Any filehandles open at the time of the fork() will be dup()-ed. Thus, the files can be closed independently in the parent and child, but beware that the dup()-ed handles will still share the same seek pointer. Changing the seek position in the parent will change it in the child and vice-versa. One can avoid this by opening files that need distinct seek pointers separately in the child. On some operating systems, notably Solaris and Unixware, calling exit() from a child process will flush and close open filehandles in the parent, thereby corrupting the filehandles. On these systems, calling_exit() is suggested instead. _exit() is available in Perl through the POSIX module. Please consult your system's manpages for more information on this

    So, whatever file descriptors/handles were open at the time of executing system/backtick are inherited by the child process/command. Which means processes like ntpd/dhcpd/named etc inherit all of the parent perl process' open file descriptors including any pipes opened as part of backtick.

    Somehow ntpd, in my case, also inherited the write-end of the pipe which is the reason the parent process, which had the read-end of the pipe, was stuck in read(2) indefinitely because ntpd is a long running process. Now, the parent process closes the write-end of the pipe before forking but the whole operation of opening the pipe and closing the write-end is not atomic so .......

    perl process

    backtick

    pipe()

    <---------- GAP HERE

    close() write-end of pipe

    The solution I used was to write a perl wrapper script which closes all fds except 0/1/2 and then exec the command, like this:

    `closed.pl service xyz restart`;

    There are multiple ways of closing fds. I used the tips from the following discussion : http://www.perlmonks.org/?node_id=476086

    Here's a link which describes a similar issue : http://tdistler.com/2010/06/18/stop-stealing-my-file-descriptors