I am writing a simple program in which parent and child process are alternatively printing into a file. I have managed to do this using user defined signals. Now I want to handle the SIGINT signal. Once ctrl-c is received the parent must send termination signal to child,the child should then should terminate and finally the parent should terminate.
My question is, in order to make this work properly I must catch the SIGINT signal ONLY from parent and IGNORE it from child. Is it right? If yes any hints on doing this?
Call:
signal(SIGINT, SIG_IGN);
from the child process which will make the child process ignore the SIGINT signal. From man signal:
If the disposition is set to SIG_IGN, then the signal is ignored.
Related
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 am making a program that creates numerous processes using fork(), which then calls an exec function to the same program (this is required by the professor).
I need it to react to CTRL+C (SIGINT) and ask the user if he/she wants to leave. The problem is that the signal handler is implemented in all the child processes too, so, when the signal is sent, the user has to answer the same amount of times as the number of processes.
I only want it to ask the user once per CTRL+C.
What solutions can I implement?
When you call fork(), the parent process will get back the pid of the child. You can send a SIGTERM or SIGKILL signal to the children through the kill syscall when the parent receives the SIGINT signal.
You can set a global variable pid and populate it with the result of getpid() on launch. And inside the signal handler test getpid() against pid then execute your code. Something like, if you are the main process please proceed, if not exit!
End result: You will have a signal handler that is run once by the main process....
I have a child process which might receive sigterm signal from its parent or from somewhere else. I have to take appropriate action if the signal is from parent.
How can i find if the received signal is from parent in c(linux)?
You set up your signal handler with sigaction using the SA_SIGINFO flag. Your handler will accept a parameter of siginfo_t. Within the siginfo_t struct is the field si_pid. This is the process id of the sending process. Match that against the child's ppid().
I am writing a shell, now it comes to control the child process.
When I use signal (SIGTERM, SIG_DFL); in the child process,
the signal SIGINT is generated by Ctrl + C, and that signal terminates whole the OS shell.
how can I just terminate the process e.g “cat” only, but not whole shell??
Should I use somethings like:
void sig_handler(int sig) {
if(sig ==SIGINT)
{
kill(pid);
}
}
Really thanks a slot.
Your question is rather vague. Can you be more clear on what you want to achieve?
I think you should be using signal(SIGTERM, sig_handler) instead of SIG_DFL which is the default action taken. Since, you have a signal handler, you call it instead of predefined functions like SIG_INT or SIG_DFL. The code inside your function looks fine. As long as you know the pid, you can do a kill(pid).
In the exec'd child, the SIGINT (and SIGQUIT) handlers will be SIG_DFL if they were set to a handler in the parent shell, and that's most likely correct. (You can't inherit a non-default signal handler across an exec, of course, because the function usually doesn't even exist in the exec'd process.)
Setting a handler for SIGTERM won't affect the response to SIGINT, or vice versa.
Your shell shouldn't need to deliver signals to its children.
Suppose there are two processes, a parent and a child, which use the signal for synchronization. In the parent process, the function used to sync with child acts as below.
WAIT_CHILD(){
while(sigflag == 0){ //sigflag will be set to 1 in a signal handler in the child process
sigsuspend(&zeromask); //No signal is in the mask set
}
//do sth....
}
My question is can we use pause() to replace the sigsuspend(&zeromask)?
No. The posted code is only race-condition-free if the prevailing signal mask is blocking the signal that is sent by the child, and if that is the case then, since pause() will not change the signal mask, it would block forever.
The reason that the signal must be initially blocked is that otherwise, a signal could arrive in between the test sigflag == 0 and the sigsuspend(), which means the process would have missed the signal and get stuck.