Why we generally ignore SIGCHLD - c

I was studying about signals and going through this link
https://en.wikipedia.org/wiki/Child_process#cite_note-1
And this is what it says : "The SIGCHLD signal is sent to the parent of a child process when it exits, is interrupted, or resumes after being interrupted. By default the signal is simply ignored"
is there any reason why we ignore SIGCHLD.

Try having kids and you'll understand why sometimes you have to ignore SIGCHLD to maintain your sanity :).
Jokes aside, all that statement means is that POSIX systems do not define a default signal behavior, other than to ignore it, for SIGCHLD. Compare this with SIGINT, SIGTERM, etc where the default behavior might be to terminate the process.
See man 7 signal on linux for a list of all signals, all default handlers, and the mapping of signals->default handler.
Often it makes sense to ignore SIGCHLD because you can know everything you need to know from waitpid.

Even though my answer is late, it might be helpful for a wonderer person thinking reason for need of SIGCHLD and why it is ignored. Let's listen my story.
I've taken a project in which we are streaming online radio stations whose extensions are .pls, .m3u or just IP:Port. Each station is a channel for us. There are two doodads - a potentiometer and a rotary encoder - which are able to be rotated(switched) either clockwise or counter clockwise. The former is used to adjust volume of the radio, likewise the latter is to change channels. I'm using a media player working via terminal, so it is also another process. Likewise, I'm using amixer which is also additional another process to adjust volume abruptly within a while infinite loop . In the main process, I create two processes. To change channel I opt to send SIGKILL signal to terminate the player process which is liable to play selected station to go new channel and wait() in parent. wait() usage is appropriate here because I had killed him before I waited. It would immediately returns without blocking. On the volume changer's side, it works until radio device is turned off. Its process is being run in an infinite loop.
So, what would be happen if I opt to make wait its parent process for the volume adjuster process?
The main process would block forever since the volume adjuster process would never return. In lieu, I opt to handle explicitly but in ignoring way. Why? Because I don't care when it is terminated or what its return value is. I only care that after its termination, I don't want the child to turn into a zombie. I just want when the child exits it is reaped immediately as well as non-blocking main process.
Why do we generally ignore SIGCHLD?
If (as in the aforementioned example) the signal handler does nothing beyond calling waitpid then an alternative is available. Setting the SIGCHLD handler to SIG_IGN will cause zombie processes to be reaped automatically.
Don't forget that to do that, explicitly calling sigaction() with the disposition SIG_IGN is needed.

Related

How to do something in C when a process terminates without hanging the program?

Currently, I'm learning about processes on the UNIX system.
My issue is, I need to do something every time a background process terminates. That means that I can't use the typical functionality of waitpid because then the process won't be running in the background and it'll hang the program.
I'm also aware of the SIGCHLD signal which is sent whenever a child of the parent process is terminated however I'm not aware of how to get the process id of the said process which I will need.
What is the proper way to go about this in C? I've tried things such as WNOHANG option on waitpid however that of course only gets called once so I don't see how I could make that apply to my current situation.
waitpid because then the process won't be running in the background and it'll hang the program.
If the process won't be running in the backrgound, waitpid with the pid argument will exit immediately (assuming there are no pid clashes). And still, that's not true - just use WNOHANG...
however I'm not aware of how to get the process id of the said process which I will need. What is the proper way to go about this in C?
Use sigaction to register the signal handler and use the field si_pid from the second signal handler argument of type siginfo_t. From man sigaction:
SIGCHLD fills in si_pid, si_uid, si_status, si_utime, and si_stime,
providing information about the child. The si_pid field is the
process ID of the child
A working example that uses it is in the man 3p wait page under section Waiting for a Child Process in a Signal Handler for SIGCHLD.
What is the proper way to go about this in C?
The C standard is not aware of child processes and SIGCHLD signals. These are part of your operating system. In this case the behavior is standardized by POSIX.

What could happen when I register signal handlers for previously ignored signals

The following code is from an example in the GNU manual about signal handling
...
if (signal(SIGINT, termination_handler) == SIG_IGN)
signal(SIGINT, SIG_IGN);
...
The manual says,
Note that if a given signal was previously set to be ignored, this code avoids altering that setting. This is because non-job-control shells often ignore certain signals when starting children, and it is important for the children to respect this.
I don't understand why ignored signals should be kept as ignored when non-job-control shells make some signals ignored before starting my process. (What does it mean by "non-job-control shells"?)
I found a similar part in my book, 'The Linux System Programming' written by Robert Love. The book says,
When a process is first executed, all signals are set to their default actions, unless the parent process (the one executing the new process) is ignoring them; in this case, the newly created process will also ignore those signals. Put another way, any signal caught by the parent is reset to the default action in the new process, and all other signals remain the same. This makes sense because a freshly executed process does not share the address space of its parent, and thus any registered signal handlers may not exist.
This behavior on process execution has one notable use: when the shell executes a process "in the background" (or when another background process executes another process), the newly executed process should ignore the interrupt and quit characters.
Thus, before a shell executes a background process, it should set SIGINT and SIGQUIT to SIG_IGN. It is therefore common for programs that handle these signals to first check to make sure they are not ignored.
I tried registering a signal handler for SIGINT (without checking ignored or not) and running it in the background (just to see what happens if I do what they're saying not to do).
$ ./my_program &
But nothing special happened.
What could be happen when I register signal handlers for previously ignored signals?

Intercepting Signals From Processes

How I would go about capturing/intercepting signals sent to another process from my own process? Willing to use C, Ruby, or any Linux package.
You can write a library wrapper that will replace system signal/sigaction calls to intercept setting of the signal handler and set your own handlers. On received signal, you can do your job and call user handler later. Use LD_PRELOAD to replace system signal/sigaction routines by your own.
I think that the ptrace(2) system call is what you want. From the manual: "While being traced, the child will stop each time a signal is delivered, even if the signal is being ignored. (The exception is SIGKILL, which has its usual effect.) The parent will be notified at its next wait(2) and may inspect and modify the child process while it is stopped. The parent then causes the child to continue, optionally ignoring the delivered signal (or even delivering a different signal instead)."

how to handle multiple signals by order of arrival in C

I want to be able to handle many signals of the same type (SIGCHLD), but, I want to make sure that if a signal is arriving while I'm still handling the previous one, I will finish handling the first to arrive, and only after I finish handling it, I'll handle the next ones.
There may be more than one signals waiting to be handled.
Also, does a process sends SIGCHLD if it's terminated or killed (using SIGTERM/SIGKILL) by the parent process?
As long as you use sigaction and not the problematic signal function to setup your signal handler, you can be sure (unless you specify otherwise) that your signal handler will not be interrupted by another occurrence of the signal it's handling. However it's possible if many child processes all die at once that you might not receive a signal for each. On each SIGCHLD, the normal procedure is to attempt to wait for children until your wait-family function says there are no children left to wait for. At this point, you can be sure that any further child termination will give you a new SIGCHLD.
Also, since you're very restricted as to what functions you can use from a signal handler, you'd probably be better off just setting some sort of flag or otherwise notifying your main program loop that it should check for terminated children via one of the wait interfaces.
And finally, yes, a SIGCHLD is delivered regardless of the reason the child terminated - including if it was killed by the parent.

How does a "kill" work? And especically how does a "kill" work on blocked proces?

Who in the kernel is responsible for killing a process.
What if a "kill" comes, and the process is in the blocked state. Does the kill waits until the process comes to running state to clean himself.
If someone can answer more in terms of kernel, like when a SIGINT from the kill command is generated, what all is invoked by the kernel until the TCBs (task control blocks) are cleared in the end.
I presume you are talking about SIGKILL, so I will confine the discussion to that signal only.
When a process raises a SIGKILL on another process, SIGKILL is added as a pending signal on the victim process, and any pending SIGSTOP, SIGTSTP, SIGTTOU or SIGTTIN signals are cleared. The victim is woken up (made runnable) if it is stopped or in an interruptible sleep state.
When the victim process next attempts to go from Kernel mode to User mode, the pending signals are checked. This is where the pending SIGKILL is found, and the Kernel calls do_exit() instead of going back to User mode.
The transition from Kernel mode to User mode will be when the process is next scheduled (unless it was in an uninterruptible sleep - this is the infamous D state). If it's in an uninterrutible sleep, the process won't try to go back to User mode until its woken.
Killing it with a signal other than SIGKILL, just causes a signal to be sent. This can be masked or ignored, but assuming it isn't (or after it's unmasked), then it interrupts the normal running of the program.
If an IPC-type system call is in progress (e.g. reading from a socket, select(), poll(), sleep() etc), then it will be interrupted and fail with EINTR in errno. A properly written application will re-issue the call after handling the signal.
The process then immediately executes a call to the signal handler, which may return to allow processing to continue, or it could call longjmp (in C), or it could exit the process, which is normally the default.
SIGKILL is completely different, none of the above happens. Instead it just quits the system call (which would presumably leave EINTR in errno, if the process was allowed to read it), then causes the task to exit immediately with no possibility to handle it.
But either of them I think waits for a "D" "uninterruptable sleep" state to finish. This would normally be something like a blocking disc read, page fault demand-load or something.
Running kill simply sends a signal to the process (TERM) asking it nicely to terminate. If it won't respond that's it's business. However, you can choose to send any one of several different signals commanding it to go away. What you may be interested in is kill -9 (SIGKILL) which kills it without giving it a choice in the matter.
(Edit: As was pointed out in the comments, TERM is the default)
Killing (rather than interrupting) is usually performed by the SIGKILL signal in UNIX systems (CTRL-C sends SIGINT).
These systems usually provide a method of interrupting blocking system calls by a signal, which allows the signal handler to execute without waiting on a system call to complete (This is where the EINTR error comes into play). So normally, the call is just cancelled, without waiting for it to complete.
Each process can recieve many types of signal, which it can ignore to handle but few aren't delivered to process but "Proceess scheduler" terminates the process....
see this for more explanation
http://www.linux-tutorial.info/modules.php?name=MContent&pageid=289

Resources