The child is trying to read from the terminal after its parent has died. That doesn't work because the child is no longer in the foreground process group.
Ok, what's a foreground process group? The basic idea is that a process group the set of processes that are in the same shell job. When you run a program from a shell in a terminal, the shell creates a process group for that program. If the program forks, the children belong to the same process group. If you run the program in the background (myprogram &
), the process group is a background process group; if you run the program in the foreground (without &
) then the process group is the foreground process group (there can only be one foreground process group). The shell commands fg
and bg
can bring process groups into the foreground or into the background. Process groups are used for two things: you can signal them together, and they determine who is allowed to access the terminal.
Only the foreground process group is allowed to read from the terminal. If a background process tries to read from the terminal, the read
system call returns EIO
. This is a user interface design decision: when the user is interacting with a program in the foreground, background processes don't get to disrupt this.
Let's instrument the child to print information about its process group:
#!/usr/bin/python3
import os
def main():
print("Child: pid={pid:d} ppid={ppid:d} pgid={pgid:d}".format(pid=os.getpid(), ppid=os.getppid(), pgid=os.getpgrp()))
a=input("enter a no : ")
print("I am child "+str(a))
main()
Sample output:
$ ./parent.py
I am parent
$ Child: pid=15593 ppid=1 pgid=15592
enter a no : Traceback (most recent call last):
File "child1.py", line 7, in <module>
main()
File "child1.py", line 5, in main
a=input("enter a no : ")
EOFError
The process group of the child is still the process ID of the parent, but the parent has already died (so now the parent process ID of the child is 1). Thus the child is now in a process group of its own. Since it is not in the foreground (the shell is now back in the foreground), the child is in the background, so it cannot access the terminal.
Contrast what happens if you add a call to os.wait()
before print("I am parent")
:
$ ./parent.py
Child: pid=15619 ppid=15618 pgid=15618
enter a no : hello
I am child hello
I am parent
This time the child is still in the foreground process group, so it can access the terminal as expected.
I don't know why Python reports the error as EOFError
rather than IOError
.