I am reading several shell implementations. One thing that confuses me is it seems very common to block SIGCHLD before spawning a child process and unblock it right after fork() in both parent and child processes.
What is the purpose of doing that? What will happen if I don't block this signal?
So bascially, it is used to avoid the race between parent and child. This can make sure the sigchild handler won't be received before parent executing something.
Related
Hello I am new to learning about system calls. I am currently learning about fork() and wait() system calls. I know that fork() creates a new child process. What confuses me is the wait() call.
This is what I understand so far:
(1) When a process dies, it goes into a 'Zombie State' i.e. it does not release its PID but waits for its parent to acknowledge that the child process has died and then the PID is released
(2) So we need a way to figure out when the child process has ended so that we don't leave any processes in the zombie state
I am confused with the following things:
(1) When running a C program where I fork a new child process, if I don't call wait() explicitly, is it done internally when the child process ends? Because you could still write a block of code in C where you run fork() without wait() and it seems to work fine?
(2) What does wait() do? I know it returns the PID of the child process that was terminated, but how is this helpful/related to releasing the PID of the terminated process?
I am sorry for such naive questions but this is something I was really curious about and I couldn't find any good resources online! Your help is much appreciated!
wait isn't about preventing zombie states. Zombie states are your friend.
POSIX more or less lets you do two things with pids: signal them with kill or reap them (and synchronize with them) with wait/waitpid/waittid.
The wait syscalls are primarily for waiting on a process to exit or die from a signal (though they can also be used to wait on other process status changes such as the child becoming stopped or the child waking up from being stopped).
Secondarily, they're about reaping exit/died statuses, thereby releasing (zombified) pids.
Until you release a pid with wait/waitpid/waittid, you can continue flogging the pid with requests for it to die (kill(pid,SIGTERM);) or with some other signal (other then SIGKILL) and you can rest assured the pid represents the process you've forked off and that you're not accidentally killing someone else's process.
But once you reap a zombified pid by waiting on it, then the pid is no longer yours and another process might take it (which typically happens after some time, as pids in the system typically increment and then wrap arround).
That's why auto-wait would be a bad idea (in some cases it isn't and then you can achieve it with globally with signal(SIGCHLD,SIG_IGN);) and why (short-lived) zombies states are your friend. They keep the child pid stable for you until you're ready to release it.
If you exit without releasing any of your children's pids, then you don't have to worry about zombie children anymore--your child processes will be reparented to the init process, which will wait on them for you when they die.
When you call fork(), a new process is created with you being its parent. When the child process finishes its running with a call to exit(), its process descriptor is still kept in the kernel's memory. It is your responsibility as its parent to collect its exit code, which is done with a call to wait() syscall. wait() blocks the parent process until one of its childrens is finished.
Zombie process is the name given to a process whose exit code was never collected by its parent.
Regarding to your first question - wait() is not called automatically as zombie processes wouldn't exist if it did. It is your responsibility as a programmer. Omitting the call to wait() will still work as you mentioned - but it is considered a bad practice.
Both this link and this link explains it good.
When my child process crash, it need a lot of time to do coredump (because I dump hugepages) and then the parent got SIGCHLD, but it is too late for me. So I use signal handler in child process to notify parent process and then do coredump, I just want to send the child pid to parent process. But I am not sure which mechanism is safe in this case. pipe or ipc message queue or unix socket?
You haven't provided enough details, but I assume in almost all the languages that allow you to explicitly spawn a new process there is a mechanism to get the child PID right when it gets created.
For example in C when you call fork() if the child process is created successfully it returns the child PID.
Yeah, I choose POSIX message queue finally, though it may be unsafe to call mq_send() in signal handler.
Say I create a process with multiple child process and I call wait() in the main process. If one child terminates, its pid is returned. But what happens if a couple of child process terminate simultaneously? The call should return with one of them, and a second call should return with the other, right? Is there a particular order in which they will return (maybe there is a precedence to the child with lower pid)?
No.
SUSv4 leaves explicitly unspecified in which order (if any) child processes are reaped by one or several wait calls. There is also no "accidential" order that you could rely on, since different Linux kernel versions perform differently. (Source: M. Kerrisk, TLPI, 26.1.1, page 542).
Somewhat related trivia:
You might wonder why you can reliably wait on several child processes that terminate concurrently at all. If you think about how signals work, you might be inclined to believe that it is perfectly possible to lose child termination signals. Signals, a well-known fact, are not queued (except for realtime signals, but SIGCHLD isn't one!). Which means that if you go strictly by the letter of the book, then clearly several children terminating could cause some child termination signals becoming lost!
You can only call wait once at the same time, so you can at most consume one signal synchronously as it is generated, and have a second one made pending before your next call to wait. It appears that there is no way to account for any other signals that are generated in the mean time.
Luckily, that isn't the case. Waiting on child processes demonstrably works fine. Always, 100%. But why?
The reason is simple, the kernel is "cheating". If a child process exits while you are blocked in wait, there is no question as to what's happening. The signal is immediately delivered, the status information is being filled in, the parent unblocks, and the child process goes * poof *.
On the other hand, if a child is exiting and the parent isn't in a wait call (or if the parent is in a wait call reaping another child), the system converts the exiting process to a "zombie".
Now, when the parent process performs a wait, and there are any zombie processes, it won't block waiting for a signal to be generated (which may never happen if all the children have already exited!). Instead, it will just reap one of the zombies, pretending the signal was delivered just now.
In linux, after calling fork(), my child process is going to call exec soon. Is there a way for the parent process to wait() and not do anything till the child has exec'ed?
Thanks.
There is no (API) way for the parent to know that the child is performing an exec().
But there is a nice pipe-trick: have the child inherit a filedescriptor (for a pipe) and (before the fork() ) set the close-on-exec flag for the pipe. The parent will be notified by an EOF on the pipe when it is closed by the exec().
Please note that this does not need any collaboration from the child.
Use vfork() instead of fork(). That causes the parent to be suspended until the child either exits or calls one of the execve() family of functions.
You need to use waitpid using the process ID returned from the fork call that is returned to the parent.
EDIT
Or if you mean that you want to know that the child is about to call exec use pause in the parent. Get the child to call kill with a suitable signal to the parent (whose process ID can be obtained from getppid). USR1 signal might be useful to use. Do this just before the exec.
There is a function in QNX procmgr_guardian which sets a child process as the guardian of the other child process in case of the parent's death.
Is there such functionality in Linux too ? How do I implement it in Linux? Any pointers are appreciated.
There is no direct method for monitoring a process that is not your own child. However, there is a hack you can use: Create a FIFO using pipe(); ensure that the process to be monitored holds the write end of the pipe (and that it is closed in all other processes). If the process dies, an EOF condition will be signalled in the read end of the pipe (ie, select will indicate a readable condition).
If you want the process to be reparented when its immediate parent dies, you may be able to achieve this with PID namespaces. By arranging for the 'guardian' process to be PID 1 in the PID namespace, it will inherit all orphaned processes in that namespace.