I am having trouble understanding the fork
behavior in Perl when it is called from within a BEGIN
block. In perlfork, I read this
BEGIN blocks
The
fork()
emulation will not work entirely correctly when called from within aBEGIN
block. The forked copy will run the contents of theBEGIN
block, but will not continue parsing the source stream after theBEGIN
block. For example, consider the following code:BEGIN { fork and exit; # fork child and exit the parent print "inner\n"; } print "outer\n";
This will print:
inner
rather than the expected:
inner outer
But, as I read it, this only applies to platforms where fork
is emulated. Since I'm concerned about (and test the code on) Linux, that shouldn't be a problem, should it?
Indeed, if I copy the example code from that document
BEGIN {
fork and exit;
print "inner\n";
}
print "outer\n";
this is what happens when I run it
jirka@debian:~/xpath$ perl /tmp/test.pl
jirka@debian:~/xpath$ inner
outer
which seems consistent.
However, when I removed the exit
I expected to have both a parent and a child process. That that didn't behave as I expected.
Here is my new code
BEGIN {
fork;
print "inner\n";
}
print "outer\n";
and here is the run
jirka@debian:~/xpath$ perl /tmp/test.pl
inner
outer
jirka@debian:~/xpath$ inner
I expected two inner
and two outer
. The second outer
is missing.
My question is, what causes this strange behaviour, and how could it even be described.
It looks to me like the child no longer has the source file open (or it is all buffered in the parent only?)
Trying the code via -e succeeds.
OK, the problem really seems to be that the child and the parent stomp on each other's source file descriptor. Strace gives:
read(3, "BEGIN {\n fork;\n\tprint \"in"..., 8192) = 67
_llseek(3, 46, [46], SEEK_SET) = 0
_llseek(3, 0, [46], SEEK_CUR) = 0
clone(Process 29716 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb75329a8) = 29716
[pid 29715] write(1, "inner\n", 6inner
) = 6
[pid 29715] read(3, " print \"outer\\n\";\n", 8192) = 21
[pid 29715] read(3, "", 8192) = 0
[pid 29715] close(3) = 0
...
write(1, "inner\n", 6inner
) = 6
read(3, "", 8192) = 0
close(3) = 0
This seems to be caused by the fact that parent and child share a single file read pointer. From man fork
:
- The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two descriptors share open file status flags, current file offset, ...
Now, this begs the question: How to separate those file descriptors' offsets?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With