Typically the parent process waits until the child process ends by calling waitpid
. The parent process gets the PID of the process from fork
.
This means the child never signals the parent process in any way that it exited or what happened. This is done by the system and not the child process.
If you are talking about the output of the program, the parent typically never receives the output of the child process unless it provided fds. This also means that the child process prints the output and not the parent process. The parent process just receives information about the state of the process (for more information see the macros in the waitpid
manpage)
So when a command is fired from a shell, fork() inherits a child
process of it and exec() loads the child process to the memory and
executes.
Not quite. fork()
clones the current process, creating an identical child. exec()
loads a new program into the current process, replacing the existing one.
My qs is:
If the child process contains all the attributes of the parent process(which is the original process), then what is the need of this
child process? The original process also could have been loaded to the
memory.
The need is because the parent process does not want to terminate yet; it wants a new process to go off and do something at the same time that it continues to execute as well.
Does this fork and exec concept apply to all the executable program in
UNIX?Like for shell script also or only for commands? Does it also
apply for shell builtin commands?
For external commands, the shell does a fork()
so that the command runs in a new process. Builtins are just run by the shell directly. Another notable command is exec
, which tells the shell to exec()
the external program without first fork()
ing. This means that the shell itself is replaced with the new program, and so is no longer there for that program to return to when it exits. If you say, exec true
, then /bin/true
will replace your shell, and immediately exit, leaving nothing running in your terminal anymore, so it will close.
when copy on write concept is used if I'll execute a command/script?
Back in the stone age, fork()
actually had to copy all of the memory in the calling process to the new process. Copy on Write is an optimization where the page tables are set up so that the two processes start off sharing all of the same memory, and only the pages that are written to by either process are copied when needed.
Best Answer
Signals come in two flavours, synchronous and asynchronous. Synchronous ones begin with the kernel in response to something the process did -- e.g., the ever popular SIGSEGV. Asynchronous signals generally come from other processes, and, as the name implies, arrive at some arbitrary point. A "pending" signal is either one which simply hasn't been delivered yet, or one which has been blocked temporarily by the receiving process. Consider some pending scenarios and why it would be inappropriate for the child to inherit them.
Synchronous, undelivered: Let's take the example of a SIGSEGV that's pending because the parent committed an access violation -- something I'm sure actually doesn't happen or doesn't happen for long enough to really consider it as "pending" from a userspace perspective, but for sake of argument -- then it's the parent that committed the violation, not the child. If the child then proceeds to do something similar (which it likely would), it will get its own signal anyway. If by chance it doesn't, then it shouldn't receive one that was pending for the parent.
Asynchronous, undelivered: In this case, it really cannot be meaningful if the signal was pending for the duration of the fork and then delivered to the parent, since the signal is asynchronous -- it cannot be intended to interrupt the process at a particular point, it's like a phone call; the caller isn't intending to catch you while you are still sitting in your chair because the caller can't know that. The point of the call is just to communicate something to you. Further, signals are addressed to specific process, and the child is a separate process with its own PID. If I send a signal to process 1001, I do not expect it to also go to process 1002.
Blocked (synchronous or asynchronous): In this case, the signal is left pending intentionally by the process, so it had the opportunity to unblock it before the fork (but didn't). Since it is known that such signals will not be inherited by the child, this scenario occurs by design. For example, a server receives a signal and for what ever reason decides to block it temporarily while it answers an incoming request --
pselect()
will accomplish this, I think -- and to handle the request it forks a child. Then it deals with the pending signal.That seems integral to the concept of a fork: the child is a copy of the parent. Signal handlers are just regular functions with a special purpose. Again, since this is known it can be exploited by design, or conversely, compensated for. It is easy enough to remove a handler if you no longer want to use it.