I am dealing with some issue, I have a function that's handling a signal and like that:
void sigChld(int noSig)
{
//some action here
}
void F1 () // some child process
{
struct sigaction action;
.... // initialisation of the structure with sigChld as the function handler
sigaction(SIGCHLD, &action, 0);
while(1)
callToFunction();
}
In my child process F1, I am attaching the handler to SIGCHLD to sigChld() and then I do callToFunction() that creates another process and do some treatment. At the end of its execution, It sends me a SIGCHLD which I need to treat in my handler.
Now my question is : I need the return value of callToFunction() so I thought about using a waitpid in the handler of sigchld before doing some actions. But what if during waitpid() or the actions, callToFunction() send another signal ? will the current handler stop ? or will continue its execution and then treat the next signal ?
In my problem, I need to treat completely the signals one after another one like if I was executing the handler in parallel.
I'm not sure it's actually possible for a waitpid() in a SIGCHLD handler to get interrupted by a signal, since it should return instantly if there's a child available, but in general signals can occur during a signal handler just like anywhere else.
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.
The pause() function blocks until a signal arrives.
Assuming the process got a signal and pause() returned, does the signal handler will be executed before the code that follows the pause() call, or the result is unexpected?
Example:
void sigusr1_handler()
{
// .. handler code
}
void main()
{
// .. bind handler to SIGUSR1
pause(); // wait for SIGUSR1
// some more code
}
Does "some more code" will always be executed after sigusr1_handler() has finished, or there is a race condition? If so, what is the solution?
I cannot think of anything besides busy-waiting, but then the pause won't be needed at all..
Citing from the man page for pause(2):
pause() returns only when a signal was caught and the signal-catching function returned. In this case, pause() returns -1, and errno is set to EINTR.
You can be sure that your signal handler runs before some more code.
Signal handlers do not run concurrently; they interrupt the thread that handles them, and the interrupted flow only continues when the signal handler returns.
However, there may be other race conditions associated with your example; with just sparse pseudo-code and not a full explanation of your usage case, it's hard to say. For example a different signal might arrive and interrupt the pause before your signal does, and then your handler could end up running later than you expected.
There are several "right ways" to do this instead:
write a single byte to a pipe in the signal handler, and read from it in the main flow of execution.
sem_post a semaphore from the signal handler, and sem_wait in the main flow of execution.
Use sigwaitinfo or sigtimedwait instead of a signal handler.
Still use pause, but in a loop:
while(!signal_handler_finished) pause();
where signal_handler_finished has type volatile sig_atomic_t, and is set to a nonzero value in the signal handler.
I have a main process that has forked some kid processes.
Each kid does something and blocks itself. By blocking itself every child sends a SICHLD signal to the parent process.
I also have declared a sigaction action, in the main process code, in order to catch the SIGCLHD that the kids will send.
static struct sigaction action;
action.sa_handler = handler
sigfillset(&(action.sa_mask));
sigaction(SIGCHLD, &action, NULL);
The SIGCHLD handler when called, checks which kid sent the SIGCHLD signal and does something for that kid.
The question is, what happens if multiple kids send signals at the same time? Let's say that kid(1) sent SIGCHLD. The handler catches it and before he completes the handle, kid(2) and kid(3) both send signals. Will the handler run for each of these signals after he is done with kid(1) or will these signals get ignored?
SIGCHLD is somewhat special in that you get exactly one signal per exiting child; these signals are tied to the corresponding zombies/wait-status left behind by the child processes they correspond to. But in general most signals are just flags, not queues. If possible it's best not to use SIGCHLD and instead just use waitpid and track child exit in some other way (e.g. by observing EOF status on a pipe from the child in your poll loop or such).
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.