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

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?

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.

Why we generally ignore SIGCHLD

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.

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)."

Ctrl + C: does it kill threads too along with main process?

While running a thread program and repeatedly killing the main program using Ctrl + C, i see unexpected results in the program in second run. However, if i let the program run and voluntarily exit, there are no issues.
So, my doubt is, does Ctrl + C, kill threads also along with the main process?
Thanks in advance.
In multithreaded programming, signals are delivered to a single thread (usually chosen unpredictably among the threads that don't have that particular signal blocked). However, this does not mean that a signal whose default action is to kill the process only terminates one thread. In fact, there is no way to kill a single thread without killing the whole process.
As long as you leave SIGINT with its default action of terminating the process, it will do so as long as at least one thread leaves SIGINT unblocked. It doesn't matter which thread has it unblocked as long as at least one does, so library code creating threads behind the application's back should always block all signals before calling pthread_create and restore the signal mask in the calling thread afterwards.
Well, the only thing that Ctrl + C does is sending SIGINT to one thread in the process that is not masking the signal. Signals can be handled or ignored.
If the program does handle Ctrl+C, the usual behavior is self-termination, but once again, it could be used for anything else.
In your case, SIGINT is being received by one thread, which probably does kill itself, but does not kill the others.
Under Linux 2.6 using NPTL threads: I am assuming that the process uses the default signal handler, or calls exit() in it: Yes it does. The C library exit() call maps to the exit_group system call which exits all the threads immediately; the default signal handler calls this or something similar.
Under Linux 2.4 using Linuxthreads (or using 2.6 if your app still uses Linuxthreads for some weird reason): Not necessarily.
The Linuxthreads library implements threads using clone(), creating a new process which happens to share its address-space with the parent. This does not necessarily die when the parent dies. To fix this, there is a "master thread" which pthreads creates. This master thread does various things, one of them is to try to ensure that all the threads get killed when the process exits (for whatever reason).
It does not necessarily succeed
If it does succeed, it is not necessarily immediate, particularly if there are a large number of threads.
So if you're using Linuxthreads, possibly not.
The other threads might not exit immediately, or indeed at all.
However, no matter what thread library you use, forked child processes will continue (they might receive the signal if they are still in the same process-group, but can freely ignore it)

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.

Resources