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.
Related
I am working on signals in C programming. I have parent process and 5 child processes, I am trying to send SIGUSR2 from child processes to parent process when they are done some calculations while parent waits for them with sigsuspend(). When all 5 child processes sends SIGUSR2, parent process continues its work. I increment a global variable in the signal handler function to do so. Sometimes it runs fine but sometimes parent process gets stuck waiting.
Can one of you guys help me with a better solution approach rather than counting the signals received (I must use signals for synchronization)?
To the best of my knowledge, you can't use signals for that. If two signals of the same kind are sent to a process before it gets scheduled to handle the first one, it will only see one signal. Think of it as a bit mask, there is one bit for each pending signal, and when the process gets scheduled it will receive them all. But if it is waiting for some other process, and a signal for which the bit in the mask is already set, then nothing more happens.
A better solution would probably be to open a pipe to each subprocess, and each of them writes a message when done. When the parent has read the message from all children, it can continue. There are other synchronisation methods, but this would probably be the simplest.
Is there any way in C programming language , to stop a child process , and then call it again to start from the beginning? I have realised that if I use SIGKILL and then call the child process again nothing happens.
void handler {
printf(“entered handler”);
kill(getpid(),SIGKILL);
}
int main () {
pid_t child;
child=fork();
if (child<0) printf(“error”);
else if (child==0) {
signal(SIGINT,handler);
pause();
}
else {
kill(child,SIGINT);
kill(child,SIGINT);
}
This should print two times “Entered Handler” but it does not. Probably because it cannot call child again . Could I correct this in some way?
This should print two times “Entered Handler” but it does not.
Probably because it cannot call child again .
There are several problems here, but a general inability to deliver SIGINT twice to the same process is not one of them. The problems include:
The signal handler delivers a SIGKILL to the process in which it is running, effecting that process's immediate termination. Once terminated, the process will not respond to further signals, so there is no reason to expect that the child would ever print "entered handler" twice.
There is a race condition between the child installing a handler for SIGINT and the parent sending it that signal. If the child receives the signal before installing a handler for it, then the child will terminate without producing any output.
There is a race condition between the the first signal being accepted by the child and the second being delivered to it. Normal signals do not queue, so the second will be lost if delivered while the first is still pending.
There is a race condition between the child blocking in pause() and the parent signaling. If the signal handler were not killing the child, then it would be possible for the child to receive both signals before reaching the pause() call, and therefore fail to terminate at all.
In the event that the child made it to blocking in pause() before the parent first signaled it, and if it did not commit suicide by delivering itself a SIGKILL, then the signal should cause it to unblock and return from pause(), on a path to terminating normally. Thus, there would then also be a race condition between delivery of the second signal and normal termination of the child.
The printf() function is not async-signal safe. Calling it from a signal handler produces undefined behavior.
You should always use sigaction() to install signal handlers, not signal(), because the behavior of signal() is underspecified and varies in practice. The only safe use for signal() is to reset the disposition of a signal to its default.
Could I correct this in
some way?
Remove the kill() call from the signal handler.
Replace the printf() call in the signal handler with a corresponding write() call.
Use sigaction() instead of signal() to install the handler. The default flags should be appropriate for your use.
Solve the various race conditions by
Having the parent block SIGINT (via sigprocmask()) before forking, so that it will initially be blocked in the child.
Have the child use sigsuspend(), with an appropriate signal mask, instead of pause().
Have the child send some kind of response to the parent after returning from sigsuspend() (a signal of its own, perhaps, or a write to a pipe that the parent can read), and have parent await that response before sending the second signal.
Have the child call sigsuspend() a second time to receive the second signal.
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.
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)."
I am writing a C program in which the parent forks n child processes. A child process once created invokes a SIGSTOP to allow other child processes to be created. The parent after creating all the n child processes sends a SIGCONT signal to all the child.
All the child processes execute an infinite loop and share a common resource using semaphores. Now I want that whenever the user presses ctrl-c, the parent and all the child processes terminate together. However before terminating the child processes should update in a file how many times each has used the resource.
eg:
Process 1 - 5 times
Process 2 - 3 times
and so on.
Need help in this implementation please...
The formal signal handler function should do as little as feasible. The C standard says it can write to a volatile sig_atomic_t variable, or call abort() or _Exit() (or, with restrictions, signal()). POSIX allows more to happen, and you're probably working on Linux (though you didn't say so). So, your signal handler will change the value of a sig_atomic_t variable from 0 to 1 to indicate that the signal occurred.
So, your child processes will be looping. As part of the loop condition, you should check a sig_atomic_t variable to see whether the child should terminate. When it detects that a signal occurred, it will stop looping, open the log file for append, write its information to that file, and exit. You could check the sig_atomic_t variable at other points in the processing than just the main loop condition; that's your decision.
Note that you should use sigaction() rather than signal() to control the signal handling, and you should block interrupts while processing a signal.
So, to summarize:
Your signal handler does as little as possible.
Your code detects in the main loop when the signal handler has been called and arranges to exit.
Your code can also detect when the signal handler has been called at other convenient points.
You can call a function to do the logging and exit.
In order to write the file, you need to add the code to write to said file in your signal handler for SIGINT. If you want each process to write to that file, you're going to need to make sure that the SIGINT gets sent to the entire process group.
You can probably get by without sending the SIGQUIT to each, as you could have each process simply exit itself after processing SIGINT. If you want to optimize a little, you could keep a shared data structure of which processes have already received the SIGINT so that you don't send each process several SIGINTs.