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);
}
Related
In original program kill(pid, SIGUSR1); is called first and the pause(); in parent process and In child process pause(); is called first and then kill(getppid(), SIGUSR1); its output is given below
In changed program if I replace the kill(getppid(), SIGUSR1); with pause(); in child process output is totally different I have pasted the output below the code.
Can someone explain me the why the output is changed
**********************ORIGINAL PROGRAM***********************************
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void action(int dummy){
sleep(1);
printf("Switching\n");
}
int main(int argc, char *argv[]){
pid_t pid;
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
pause();
printf("Child is running\n");
kill(getppid(), SIGUSR1);
}
}
//OUTPUT OF THIS PROGRAM
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
*********************CHANGED PROGRAM************************
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void action(int dummy){
sleep(1);
printf("Switching\n");
}
int main(int argc, char *argv[]){
pid_t pid;
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
kill(getppid(), SIGUSR1);
printf("Child is running\n");
pause();
}
}
//OUTPUT OF THIS PROGRAM
//Child is running
//User defined signal 1
If a process receives SIGUSR1 before it has set up a signal handler for it (and is not ignoring or holding it), the process will be terminated. (For details. see the signal man page).
Your code (both versions) has several race conditions.
In the first version:
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
pause();
printf("Child is running\n");
kill(getppid(), SIGUSR1);
}
The child will wait for SIGUSR1.
At about the same time, the parent will sleep, then send SIGUSR1 to the child.
The child, after the signal has been received, will do a couple printfs, then send SIGUSR1 to the parent.
At about the same time, the parent will set up a signal handler for SIGUSR1.
It's likely (but not necessarily always the case) that the child will set up the signal handler while the parent is doing the sleep(1); the signal sent from the parent to the child will be caught rather than causing the child to be terminated.
It's likely (but not necessarily always the case) that by the time the child has done its two printfs, the parent has set up the signal handler; the signal sent from the child to the parent will be caught rather than causing the parent to be terminated.
But, since there are race conditions, slight changes in timing can cause things to break.
In the second version:
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
kill(getppid(), SIGUSR1);
printf("Child is running\n");
pause();
}
The child sends SIGUSR1 to the parent just after it forks, and this will almost certainly happen while the parent is in the middle of the sleep(1). Since the parent hasn't yet set up a handler for SIGUSR1, the signal will terminate it. The shell then prints out User defined signal 1, which is the long name of the SIGUSR1 signal.
Things will work better if you set up a signal handler for SIGUSR1 before the fork. That way, both parent and child will be ready to handle the signal.
Let's say that whenever main program receives SIGINT signal, the youngest (i.e. the lastly forked) process is forked. In other words:
p1 SIGINT
p1->p2 SIGINT
p1->p2->p3
and so on
My problem is that I don't know how to tell the grand-grand-...-children to fork.
My problem is that I don't know how to tell the
grand-grand-...-children to fork.
Parent should install SIGINT handler using SA_SIGINFO flag.
When a grandchild is created it should send signal to parent(p1).
P1 through its signal handler(si_pid field of handler's siginfo_t argument) reads pid of grandchild.
When Parent receives SIGINT then it send signal to grand child.
When grand child receives signal it should fork a new child.
Repeat from 2-5 for newly created child.
One more approach:
Let parent poll for SIGINT signal.
When SIGINT received by parent, create child.
Mask SIGINT in parents context and wait for SIGINT in child context.
repeat step 1 to 3 in childs context.
Example:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#define CHILD_NEEDED 10
static volatile sig_atomic_t got_sigint;
static volatile sig_atomic_t child_created;
void sigint_handler(int sig, siginfo_t *f, void *main_context) {
ucontext_t *uc = main_context;
// to mask SIGINT while returning from handler.
sigaddset(&uc->uc_sigmask, SIGINT);
++child_created;
got_sigint = 1;
}
void create_child(void)
{
pid_t pid = fork();
sigset_t set;
sigemptyset(&set);
if (-1 == pid) {
perror("Fork failed\n");
exit(1);
} else if (0 == pid) {
// Exit if expected child are created
if (child_created == CHILD_NEEDED) {
printf("New Child\nTotal Child: %d\n", child_created);
exit(0);
}
got_sigint = 0;
// As parent mask is copied to child so clear child mask set.
sigprocmask(SIG_SETMASK, &set, NULL);
printf("New Child\n Please send signal to create child\n");
while (!got_sigint);
create_child();
}
}
int main(int argc, const char *argv[]) {
struct sigaction act = {.sa_sigaction = sigint_handler, .sa_mask = 0, .sa_flags = SA_SIGINFO};
sigset_t mask;
int status;
parent = getpid();
sigaction(SIGINT, &act, NULL);
printf("parent\n Please send signal to create child\n");
while (!got_sigint);
// As we have returned from signal so SIGINT will be mask for parent.
create_child();
// parent will wait here.
wait(&status);
exit(0);
}
All your processes will receive the SIGINT signal, so the main process doesn't need to tell the youngest process to fork; just let the process that hasn't forked yet fork, and all other processes do nothing.
I have written C code to have understanding of how pthreads behave in face of receiving a signal. For this, I have setup a signal handler using sigaction, done fork to create child process, setup number of pthreads from child process, and sent a signal from parent process to child process. I am printing id of thread from signal handler.
I had read that when a process has number of threads, then the signal will be handled by any of the threads and the behaviour is undefined (that is not sure of which thread will handle the signal). But what I have observed in my program is that every time the signal handler is printing id of only one thread and this seems to be id of parent thread. I was expecting that random id of any of the threads will be printed every time the signal is sent, but this is not happening. Can someone please throw some light on this?
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
pthread_t tid[5];
void* doSomeThing2(void *arg)
{
int i;
printf("In thread handler.my pid is %x\n",pthread_self());
i=5;
while(i--)
{
sleep(1);
}
return NULL;
}
static void my_completion_handler( int signo, siginfo_t *info, void *context )
{
int ret;
printf("In completion handler.my pid is %x\n",pthread_self());
return;
}
int main()
{
int ret,err;
struct sigaction sig_act;
pid_t mypid;
int i,j;
/* Setup the signal handler */
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags = SA_SIGINFO;
sig_act.sa_sigaction = my_completion_handler;
/* Map the Signal to the Signal Handler */
ret = sigaction( SIGTERM, &sig_act, NULL );
mypid=fork();
switch(mypid) {
case -1:
printf("fork failed\n");
return -1;
case 0:
/* child process */
printf("In child process,my pid is %x\n",pthread_self());
for(j=0;j<5;j++) {
err = pthread_create(&(tid[j]), NULL, &doSomeThing2, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
}
for(j=0;j<5;j++)
{
pthread_join(tid[j], NULL);
}
exit(0);
default:
/* parent process */
printf("Got child pid of %d\n",mypid);
i=5;
while(i--)
{
sleep(1);
printf("Parent sending signal to child \n");
kill(mypid,SIGTERM);
}
break;
}
return 0;
}
When I executed this program, I got below results:
root#sri-ThinkCentre-M72e:/home/sri/Downloads# ./signal-fork
Got child pid of 10049
In child process,my pid is b7573700
In thread handler.my pid is b6d71b40
In thread handler.my pid is b6570b40
In thread handler.my pid is b5d6fb40
In thread handler.my pid is b7572b40
In thread handler.my pid is b556eb40
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
I am trying to use signals to pass between a parent and child process, but after the first 2 statements are printed
for example in mine it shows:
CHILD 4225: Running, parent is 4224
PARENT 4224: Telling the Child Process 4225 to start
it just gets stuck running forever! I'm not sure where I am going wrong on this...
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
void p_sig_usr(int signo){
if(signo == SIGUSR1){
printf("*** Parent SIGUSR1 handler - Received 'task started' signal from child ***\n");
}
if(signo == SIGUSR2){
printf("*** Parent SIGUSR2 handler - Received 'task completed' signal from child ***\n");
}
else
printf("unexpected signal received");
return;
}
void c_sig_usr(int signo){
if(signo == SIGUSR1){
printf("*** Child SIGUSR1 handler - Received 'task start' signal from parent ***\n");
}
if(signo == SIGUSR2){
printf("*** Child SIGUSR2 handler - Received 'task complete verification' signal from parent ***\n");
}
else
printf("unexpected signal received");
return;
}
int main(void)
{
pid_t child_pid, parent_pid;
parent_pid = getpid();
struct sigaction p_sig;
sigemptyset(&p_sig.sa_mask);
p_sig.sa_flags = 0;
p_sig.sa_handler = p_sig_usr;
child_pid = fork();
if ( child_pid == -1){
perror("failed to fork a new process");
return 1;
}
if (child_pid == 0){
struct sigaction c_sig;
sigset_t c_myset;
sigemptyset(&c_sig.sa_mask);
c_sig.sa_flags = 0;
c_sig.sa_handler = c_sig_usr;
child_pid = getpid();
printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
sigfillset(&c_myset);
sigdelset(&c_myset, SIGUSR1);
sigsuspend(&c_myset);//suspend until get SIGUSR1
printf("CHILD: Telling parent that I'm starting task.\n");
sleep(3);
kill(parent_pid, SIGUSR1);
printf("CHILD: Performing task\n");
sigfillset(&c_myset);
sigdelset(&c_myset, SIGUSR2);
sigsuspend(&c_myset);//suspend and wait for SIGUSR2
printf("CHILD: Telling parent that work is done.\n");
kill(parent_pid, SIGUSR2);
printf("CHILD %d: Finished\n", child_pid);
}
else{
struct sigaction p_sig;
sigset_t p_myset;
sigemptyset(&p_myset);
sleep(3);//parent now sleeping to let child set up handlers
printf("PARENT %d: Telling the Child Process %d to start\n", parent_pid, child_pid);
kill(child_pid, SIGUSR1);
sigfillset(&p_myset);
sigdelset(&p_myset, SIGUSR1);
sigsuspend(&p_myset);//suspend until get SIGUSR1
sleep(3);
kill(child_pid,SIGUSR2);
printf("PARENT: Told child to notify of task completion.\n");
sigfillset(&p_myset);
sigdelset(&p_myset, SIGUSR2);//suspend until get SIGUSR2
printf("PARENT %d: Finished.", parent_pid);
}
return 0;
}
Thank you in advance for the help!
I'm just referring to the documentation for these functions—I have no experience using them.
It appears what sigfillset() is going to do is load the process signal mask into your sigset_t. This means that your sigset_t is going to contain the set of signals that are currently blocked by your process. I assume the default is nothing is blocked, so the set would be empty.
You might want to test this by printing out the contents of the set, or just looking at it in a debugger.
Now from the docs I understand what sigdelset(&p_myset, SIGUSR1) will do is remove the signal SIGUSR1 from the set you just filled. This set is by assumption already empty so it's unlikely this call does anything. Again, verify by looking at it in a debugger.
So now what sigsuspend() is going to do is replace your process signal mask with your new mask, which by assumption isn't any different than the default mask (again, check this in a debugger). Then on the child side will wait until the process receives SIGUSR1 and processes it via a signal handler. So your child will process SIGUSR1 but only because that's the default behaviour.
Your example code doesn't seem to have installed any signal handlers. I think you would have to call the sigaction() function to do that. Therefore very likely the default signal handler will run to process SIGUSR1.
According to this page, the default signal handling for SIGUSR1 is
(i) ... Abnormal termination of the process. The process is terminated with all the consequences of _exit() except that the status made available to wait() and waitpid() indicates abnormal termination by the specified signal.
So I'm guessing the child dies when the parent does kill(child_pid, SIGUSR1). This would mean the child isn't around to signal the parent back.
This is mainly guesswork on my part. What I recommend for you is learning how to use gdb or some other debugger so you can set some breakpoints and step through and learn what the program is actually doing.
You forgot to call sigaction after defining the struct sigaction on both the parent and child. Also, beware that the struct sigaction p_sig is redefined in the parent process.
So, I guess if you change your program to something like listed below, it should work.
--- foo.c 2014-06-16 16:37:10.918932118 -0300
+++ bar.c 2014-06-16 16:37:48.710228467 -0300
## -36,10 +36,6 ##
{
pid_t child_pid, parent_pid;
parent_pid = getpid();
- struct sigaction p_sig;
- sigemptyset(&p_sig.sa_mask);
- p_sig.sa_flags = 0;
- p_sig.sa_handler = p_sig_usr;
child_pid = fork();
if ( child_pid == -1){
perror("failed to fork a new process");
## -51,6 +47,7 ##
sigemptyset(&c_sig.sa_mask);
c_sig.sa_flags = 0;
c_sig.sa_handler = c_sig_usr;
+ sigaction(SIGUSR1, &c_sig, NULL);
child_pid = getpid();
printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
sigfillset(&c_myset);
## -69,6 +66,10 ##
}
else{
struct sigaction p_sig;
+ sigemptyset(&p_sig.sa_mask);
+ p_sig.sa_flags = 0;
+ p_sig.sa_handler = p_sig_usr;
+ sigaction(SIGUSR1, &p_sig, NULL);
sigset_t p_myset;
sigemptyset(&p_myset);
sleep(3);//parent now sleeping to let child set up handlers
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).