i have a program which creates 2 child processes, so, child 1 sends SIGINT to child 2, child 2 handles SIGINT(the handler of SIGINT blocks SIGUSR1), after SIGINT, child 1 sends SIGUSR1 to child 2.
I don't know why SIGUSR1 terminates child 2. SIGUSR1 gets blocked when SIGINT is sent.
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
sigset_t base_mask, waiting_mask;
void handler(int signum)
{
signal(SIGINT, handler);
sigemptyset (&base_mask);
sigaddset (&base_mask, SIGUSR1);
/* Block user interrupts while doing other processing. */
if(sigprocmask (SIG_BLOCK, &base_mask, NULL) != 0)
printf("cannot block\n");
else
printf("SIGUSR1 blocked\n");
if(sigismember(&base_mask, SIGUSR1))
printf("sigusr1 in mask\n");
}
int main()
{
if(fork())
{
if(fork())
{
printf("parent out\n");
}
else//child 2
{
printf("i am sib 2 with pid = %d\n", getpid());
signal(SIGINT, handler);
pause();
printf("before sleep\n");
sleep(10);
printf("after sleep\n");
/* After a while, check to see whether any signals are pending. */
sigpending (&waiting_mask);
if (sigismember (&waiting_mask, SIGUSR1))
printf("/* SIGUSR1 pending. */\n");
sleep(2);
printf("2 out\n");
}
}
else//child 1
{
printf("i am sib 1 with pid = %d\n", getpid());
sleep(2);
printf("SIGINT to %d\n", getpid() + 1);
if(kill(getpid() + 1, SIGINT))
printf("Signal cannot be sent\n");
sleep(4);
if(kill(getpid() + 1, SIGUSR1))
printf("Signal 2 cannot be sent\n");
else
printf("SIGUSR1 sent to %d\n", getpid() + 1);
sleep(4);
}
return 0;
}
output:
parent out,
i am sib 1 with pid = 2525,
i am sib 2 with pid = 2526,
SIGINT to 2526,
SIGUSR1 blocked,
sigusr1 in mask,
before sleep,
SIGUSR1 sent to 2526
The problem is: You block the signal here in the signal handler:
void handler(int signum) {
...
if(sigprocmask (SIG_BLOCK, &base_mask, NULL) != 0)
printf("cannot block\n");
else
printf("SIGUSR1 blocked\n");
if(sigismember(&base_mask, SIGUSR1))
printf("sigusr1 in mask\n");
}
But after returning from the signal handler, the blocked signals mask is restored to the value it had on entry of the handler! So, calling sigprocmask() has only effect on the blocked signals during the current handler invocation. You have to call it outside the signal handler.
Related
In the following code, I try to send SIGINT, SIGHUP, SIGQUIT signal to child process.
void sighup(int sig);
void sigint(int sig);
void sigquit(int sig);
These are my signal handler.
the issue is signal handler never invoked.
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
void sighup(int sig);
void sigint(int sig);
void sigquit(int sig);
int main()
{
int pid, i, j, k;
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if(pid == 0)
{
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
}
else
{
j = 0;
for (i = 1; i <= 5; i++)
{
j++;
if (i % 2 == 0)
{
printf("PARENT: sending SIGHUP Signal : %d\n", j);
kill(pid, SIGHUP);
sleep(3);
}
else
{
printf("PARENT: sending SIGINT signal : %d\n", j);
kill(pid, SIGINT);
sleep(3);
}
}
printf("Parent sending SIGQUIT\n");
kill(pid, SIGQUIT);
}
}
void sighup(int sig)
{
signal(SIGHUP, sighup);
printf("Child: I have received sighup\n");
}
void sigint(int sig)
{
signal(SIGINT, sigint);
printf("Child: I have received sighINT\n");
}
void sigquit(int sig)
{
printf("My daddy has killed me\n");
exit(0);
}
Below lines never printed on screen
Child: I have received sighup
Child: I have received sighINT
My daddy has killed me
Output
PARENT: sending SIGINT signal : 1
PARENT: sending SIGHUP Signal : 2
PARENT: sending SIGINT signal : 3
PARENT: sending SIGHUP Signal : 4
PARENT: sending SIGINT signal : 5
Parent sending SIGQUIT
You have two problems here.
First, after the child process sets up its signal handlers, it exits right away. So the parent might get to send the first signal depending on timing, but not any others.
Put the child in a pause loop to have it wait for signals.
The other problem is that it's possible that the parent might send the first signal to the child before it can set up its signal handlers. So put a short delay in the parent to allow that to happen.
if(pid == 0)
{
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
while (1) pause();
}
else
{
sleep(1);
...
Also, calling printf and exit from a signal handler are not considered safe. It's better to have the signal handlers set a global variable and have the main part of the code check for that.
int gotsig = 0;
void sighup(int sig)
{
signal(SIGHUP, sighup);
gotsig = sig;
}
void sigint(int sig)
{
signal(SIGINT, sigint);
gotsig = sig;
}
void sigquit(int sig)
{
gotsig = sig;
}
...
while (1) {
pause();
if (gotsig == SIGHUP) {
printf("Child: I have received sighup\n");
} else if (gotsig == SIGINT) {
printf("Child: I have received sighINT\n");
} else if (gotsig == SIGQUIT) {
printf("My daddy has killed me\n");
exit(0);
}
gotsig = 0;
}
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
void signint(int sig);
void sighup(int sig);
void sigquit(int sig);
int gotsig;
int main()
{
int pid,i;
pid = fork();
if(pid < 0)
{
perror("fork");
exit(0);
}
if(pid == 0)
{
signal(SIGHUP,sighup);
signal(SIGINT,signint);
signal(SIGQUIT,sigquit);
pause();
while(1)
{
if(gotsig == SIGINT)
{
printf("Child : Child process recieved SIGINT signal\n");
gotsig = -1;
}else if(gotsig == SIGHUP)
{
printf("Child : Child process recieved SIGHUP signal\n");
gotsig = -1;
}else if(gotsig == SIGQUIT)
{
printf("Dady killed me....!\n");
exit(0);
}
}
}else
{
sleep(1);
for(i = 1; i <=5 ; i++)
{
if(i % 2 == 0)
{
printf("Parent : sending SIGINT signal\n");
kill(pid,SIGINT);
sleep(3);
}else
{
printf("Parent : sending SIGHUP signal\n");
kill(pid,SIGHUP);
sleep(3);
}
}
printf("Parent : sending SIGQUIT signal\n");
kill(pid,SIGQUIT);
}
}
void signint(int sig)
{
gotsig = sig;
}
void sighup(int sig)
{
gotsig = sig;
}
void sigquit(int sig)
{
gotsig = sig;
}
Above code work fine for me.
Output :
Parent : sending SIGHUP signal
Child : Child process recieved SIGHUP signal
Parent : sending SIGINT signal
Child : Child process recieved SIGINT signal
Parent : sending SIGHUP signal
Child : Child process recieved SIGHUP signal
Parent : sending SIGINT signal
Child : Child process recieved SIGINT signal
Parent : sending SIGHUP signal
Child : Child process recieved SIGHUP signal
Parent : sending SIGQUIT signal
Dady killed me....!
I`m writing the program in which parent and child processes synchronize their actions with signals.
So, as result, I need a repeated cycle:
The parent process should send signal SIGUSR1 to a group of the child processes.
After getting the signal from the parent, the child processes should send signal SIGUSR2 to the parent.
After getting the signals from all child processes, the parent process should sleep for 1 s. But if the parent process gets signal SIGTERM from the child, the parent should send SIGTERM to all child processes and they should stop working.
I`ve already written how to create the group of child processes and send to them signal SIGUSR1. But I don't know how to send signal SIGUSR2 from child processes to the parent process and verify if all child processes sent a signal and if the sent signals contain SIGTERM signal.
Please, help me!
##include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static volatile sig_atomic_t got_signal;
void sig_child(int signo){
printf("Signal caught.");
}
void handler(int sig)
{
printf("caught signal: %d\n", getpid());
got_signal = 1;
signal(SIGUSR2, sig_child);
printf("sent signal: %d\n", getpid());
kill(getppid(), SIGUSR2);
}
int main() {
pid_t child;
pid_t children[3];
int status;
int i = 0;
signal(SIGUSR1, handler);
for (; i < 3; i++) {
switch (child = fork()) {
case -1:
perror("could not create child: ");
break;
case 0:
printf("child: %d\n", getpid());
while (!got_signal);
_exit(0);
default:
children[i] = child;
/*put all children in process group of eldest child*/
setpgid(child, children[0]);
}
}
sleep(1);
/* send signal to all child by sending signal to process group of eldest child */
kill(-children[0], SIGUSR1);
int n = 0;
while (n < 3) {
waitpid(children[n], &status, 0);
n++;
}
exit(0);
}
my code is a simple c code where have two processes first one the parents sends signals and print out what it send and the other is the child that receives the signals and print what it received
the output of my code is
PARENT: sending SIGHUP
PARENT: sending SIGINT
PARENT: sending SIGQUIT
it should be
PARENT: sending SIGHUP
child received SIGHUP
etc...
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
// driver code
int main()
{
int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
signal(SIGSEGV, sigsegv);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
return 0 ;
}
// sighup() function definition
void sighup(int signo)
{
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: 1 [sighub]\n");
}
// sigint() function definition
void sigint(int signo)
{
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: 2 [sigint]\n");
}
// sigsegv() function definition
void sigsegv(int signo)
{
signal(SIGSEGV, sigsegv); /* reset signal */
printf("CHILD: 11 [sigsegv]\n");
}
// sigquit() function definition
void sigquit(int signo)
{
signal(SIGINT, sigquit); /* reset signal */
printf("3 [sigquit]\n");
}
You have several "issues" with the logic of the code (apart from the use of the non async-signal-safe functions).
There is no guarantee which process will start working after the fork(). This depends on the kernel and on the system. Linux kernel allows you to make this a deterministic by setting a value in /proc/sys/kernel/sched_child_runs_first, where if value is 0 (default) the parent runs first, and if value is non-zero the child runs first. Nevertheless, it's not a good practice to depend on this switch for the synchronisation, since on multiprocessor environments, both can run at the same time if we have available CPUs.
The processes can be pre-empted at any given moment, either due to the use of system calls, or due to the cpu time. Therefore, there is no guarantee that the child had set all the signal handlers before the parent had issued the signals, so some of the signals are lost (actually on my tests I got cases where all signals ware lost, once sleep was removed).
For the same reason as 2, there is no guarantee that the child got the signal before parent sends the new signal.
To solve the problem and guarantee the order of execution, you need to create a synchronisation barrier(s). Here is example based on IPC pipes that assures the synchronisation. In the example, the parent waits for the child to set-up the signals, and than, for each signal it sends, it waits for the child to confirm that the signal was received.
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
int fd[2]; // communication pipe
// driver code
int main()
{
int pid;
if (pipe(fd)==-1)
{
fprintf(stderr, "Pipe Failed" );
exit(1);
}
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
close(fd[0]); // Close reading end
printf("Preparing the signals");
signal(SIGHUP, sighup);
printf(".");
signal(SIGINT, sigint);
printf(".");
signal(SIGQUIT, sigquit);
printf(".");
signal(SIGSEGV, sigsegv);
printf(".Signals ready\n");
write(fd[1],"ready\0", 6);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
char readb[1024];
readb[1023] = 0; //Safty stop
close(fd[1]); // Close writting end
printf("Waiting for child to finish\n");
read(fd[0], readb, 1023);
printf("Child sends %s", readb);
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
read(fd[0], readb, 1023);
printf("%s\n", readb);
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
read(fd[0], readb, 1023);
printf("%s\n", readb);
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
read(fd[0], readb, 1023);
printf("%s\n", readb);
close(fd[0]);
}
return 0 ;
}
// sighup() function definition
void sighup(int signo)
{
signal(SIGHUP, sighup); /* reset signal */
write(fd[1],"CHILD: 1 [sighub]\0",18);
}
// sigint() function definition
void sigint(int signo)
{
signal(SIGINT, sigint); /* reset signal */
write(fd[1],"CHILD: 2 [sigint]\0",18);
}
// sigsegv() function definition
void sigsegv(int signo)
{
signal(SIGSEGV, sigsegv); /* reset signal */
write(fd[1],"CHILD: 11 [sigsegv]\0",20);
}
// sigquit() function definition
void sigquit(int signo)
{
signal(SIGINT, sigquit); /* reset signal */
write(fd[1],"CHILD: 3 [sigquit]\0",19);
}
Probably the first signal is sent before the child has initialized it's signal handling. At least I could reproduce the behaviour by adding sleep(2); directly after if (pid == 0) {.
Try adding a sleep() in the parent process before you start sending signals
The parent process forks two children, each replace SIGUSR1 and SIGUSR2 signal respectively.
The parent process replace SIGINT signal, on catching it, send SIGUSR1 and SIGUSR2 to its children respectively.
The expected output when Ctrl-C is pressed should be:
Ctrl+C is pressed。
received SIGUSR1 signal
received SIGUSR2 signal
But on Ctrl-C I've got
Ctrl+C is pressed。
I have no idea why sig_handler_1 and sig_handler_2 are not excuted.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);
pid_t pid1;
pid_t pid2;
int status;
int main() {
pid1 = fork();
if (pid1 == 0) { // child 1
// avoid to be killed
(void) signal(SIGINT, SIG_IGN);
// replace SIGUSR1
(void) signal(SIGUSR1, sig_handler_1);
raise(SIGSTOP);
} else {
pid2 = fork();
if (pid2 == 0) { // child 2
// avoid to be killed
(void) signal(SIGINT, SIG_IGN);
// replace SIGUSR2
(void) signal(SIGUSR2, sig_handler_2);
raise(SIGSTOP);
} else { // parent
(void) signal(SIGINT, fun_ctrl_c);
waitpid(-1, &status, 0);
}
}
return 0;
}
void fun_ctrl_c(int)
{
printf("Ctrl+C is pressed。\n");
kill(pid1 ,SIGUSR1);
kill(pid2 ,SIGUSR2);
(void) signal(SIGINT, SIG_DFL);
}
void sig_handler_1(int)
{
printf("received SIGUSR1 signal\n");
}
void sig_handler_2(int)
{
printf("received SIGUSR2 signal\n");
}
Your problem is that you do raise(SIGSTOP); in the child processes, so they're stopped and cannot respond to signals at all.
Replace that with pause(); — the code then works.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);
pid_t pid1;
pid_t pid2;
int main(void)
{
pid1 = fork();
if (pid1 == 0)
{
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGUSR1, sig_handler_1);
pause();
printf("PID %d exiting\n", (int)getpid());
}
else if ((pid2 = fork()) == 0)
{
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGUSR2, sig_handler_2);
pause();
printf("PID %d exiting\n", (int)getpid());
}
else
{
(void) signal(SIGINT, fun_ctrl_c);
int status;
int pid;
printf("Interrupt me!\n");
while ((pid = waitpid(-1, &status, 0)) != -1)
printf("Child %d exited with status 0x%.4X\n", pid, status);
printf("Parent %d exiting\n", (int)getpid());
}
return 0;
}
void fun_ctrl_c(int signum)
{
printf("Ctrl+C is pressed。Received SIGINT (%d) signal\n", signum);
kill(pid1, SIGUSR1);
kill(pid2, SIGUSR2);
(void) signal(SIGINT, SIG_DFL);
}
void sig_handler_1(int signum)
{
printf("received SIGUSR1 (%d) signal\n", signum);
}
void sig_handler_2(int signum)
{
printf("received SIGUSR2 (%d) signal\n", signum);
}
Sample run (I called the program sigintusr12):
$ ./sigintusr12
Interrupt me!
^CCtrl+C is pressed。Received SIGINT (2) signal
received SIGUSR2 (31) signal
received SIGUSR1 (30) signal
PID 31184 exiting
PID 31183 exiting
Child 31184 exited with status 0x0000
Child 31183 exited with status 0x0000
Parent 31182 exiting
$
Note that you're not strictly supposed to use printf() (and many other functions, especially those that might need to allocate memory) inside a signal handler. It'll work OK here, but it is not good practice. See How to avoid using printf() in a signal handler? for more information.
I'm learning the signal of inter process communication, I made the very simple test code below:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void sighup();
void sigint();
void sigquit();
int main(int argc, const char *argv[])
{
int child_pid;
if((child_pid = fork()) < 0) exit (1);
if(child_pid == 0) {
sleep(2);
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
puts("this is the end of the child process");
} else {
printf("\n Parent: sending SIGHUP signal to child\n\n");
kill(child_pid, SIGHUP);
printf("\n Parent: sending SIGINT signal to child\n\n");
kill(child_pid, SIGINT);
printf("\n Parent: sending SIGQUIT signal to child\n\n");
kill(child_pid, SIGQUIT);
}
}
void sighup() {
signal(SIGHUP, sighup);
printf("CHILD: I have received a SIGHUP\n");
}
void sigint() {
signal(SIGINT, sigint);
printf("CHILD: I have received a SIGINT\n");
}
void sigquit() {
sleep(2);
printf("CHILD: My parent process has killed me!!");
printf("CHILD: cleaning up...\n");
exit(0);
}
It seems like the child process doesn't do anything, even doesn't print the end of the process string. any idea?
Your signal handlers are not being invoked in the child because of a race condition. The parent thread sends the child thread a signal before the child calls signal() that overrides the signal handling behavior.
In this case, the child receives a SIGINT and performs its default behavior, which is to terminate. Thus the child terminates before executing the statements after sleep(2).