Sending signal from parent to child and vice-versa - c

I am trying to practice signals and was trying to achieve below things
1) Child and parent prints 10 numbers and passes the baton to other
2) Parent/Child wait for there turn through sigsuspend
3) sigaction is just for heck of it to catch the signal
4) kill is used send the signal with respective process id
However the output is marred with race-conditions and I see once parent gets signal from child control is never handed back to child
Also I expected sigaction to catch the signal as well which doesnt seem to happen.
Can you please point what all I am doing wrong ?
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
static volatile int count = 0;
void sighandler(int sig)
{
if (sig == SIGUSR1)
{
printf(" \n child sends parent signal - \n ");
}
if (sig == SIGUSR2)
{
printf("\n parent sends child signal - \n ");
}
}
int main(void)
{
//pid_t pid, cid;
sigset_t block_csignal, block_psignal, empty_signal;
struct sigaction ccatch, pcatch;
setbuf(stdout, NULL);
/* Creating signal set for suspending process till
it receives below signal */
sigfillset(&block_csignal);
sigdelset(&block_csignal, SIGUSR2);
sigfillset(&block_psignal);
sigdelset(&block_psignal, SIGUSR1);
/* Creating signal set for catching the signal
and changing signal disposition */
sigemptyset(&ccatch.sa_mask); /* ccatch for catching signal from parent */
ccatch.sa_flags = 0;
ccatch.sa_handler = sighandler;
sigemptyset(&pcatch.sa_mask); /* pcatch for catching signal from child */
pcatch.sa_flags = 0;
pcatch.sa_handler = sighandler;
sigaction(SIGUSR2, &ccatch, NULL); /* catch signal from parent for child */
sigaction(SIGUSR1, &pcatch, NULL); /* catch signal from child for parent */
switch(fork())
{
case -1:
printf("error in child creation \n ");
exit(-1);
case 0:
printf(" \n Control in hand of child \n ");
while(count < 50)
{
int temp = 0;
printf(" \n c count --- \n ");
while (temp < 10)
{
printf(" %d ", count);
temp++;
count++;
}
printf(" \n parent id in child process --- %d \n ", getppid());
kill(getppid(), SIGUSR1); /* send signal to parent */
sigsuspend(&block_csignal); /* wait till you get signal from parent */
}
exit(1);
default:
printf("\n Control in hand of parent \n ");
sigsuspend(&block_psignal); /*wait till you get signal from child*/
printf("\n Control back in hand of parent \n ");
while (count < 50)
{
int temp = 0;
printf(" \n p count --- \n ");
while (temp < 10)
{
printf(" %d ", count);
temp++;
count++;
}
kill(getpid(), SIGUSR2); /* send signal to child */
}
break;
}
printf("\n ");
return EXIT_SUCCESS;
}

In order to send a signal from parent to child, you need first to store the child's pid (it is the return value from a successful fork). In the parent code, you use getpid() which returns the id of the currently running process, hence the parent.
Try something like:
int cid = fork();
if(cid == 0) //child
if(cid > 0){ // parent
//...
kill(cid,...
}

Related

How to send a signal around specific processes?

I'm trying to send a signal around circle of processes for a certain amount of times. my first argument represents the number of processes I wish to create. my second one is just a place holder I am currently initiating to be 0. My third is the number of time I want to pass this signal around. I have designed the processes to have a relationship as such: Parent->child1,
child1->child2, child2->child3.... and so on. I'm just figuring out C and I'm confused to why my code is stopping midway. It runs for an iteration or two and then stalls out. Can someone explain why?
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
void myHandler1 () {
if(N >= 2 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill((getpid()+1),SIGUSR1);
}
else if(N >= 2 && numOfCycles == 0) {
exit(1);
}
else if(N == 1 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill(startProcess,SIGUSR1);
}
else if(N == 1 && numOfCycles == 0) {
exit(1);
}
else {
printf("Cycle Complete\n");
exit(1);
}
}
void main(int arg, char ** argv) {
struct sigaction temp, vitas, arctic;
sigemptyset(&killSet);
sigaddset(&killSet,SIGUSR1);
N = atoi(argv[1]);
pid_t process1;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
temp.sa_handler = myHandler1;
temp.sa_flags = SA_RESTART;
// vitas.sa_handler = myHandler2;
// vitas.sa_flags = SA_NODEFER;
//
// arctic.sa_handler = myHandler3;
// arctic.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &temp, NULL);
if (N > 1 ) {
process1 = fork();
if(process1 == 0) {
if(N > 2) {
printf("I am a child with PID=%d, PPID=%d, N =%d\n",getpid(),getppid(),N);
}
N--;
char narg = N+'0';
char *pnarg = &narg;
if(startProcess == 0) {
char nstartProcess[6];
startProcess=getppid();
sprintf(nstartProcess,"%d",startProcess);
char *pstartProcess = &nstartProcess[0];
execl("circle",argv[0],pnarg,pstartProcess,argv[3],NULL);
}
else{
if(N == 1){
printf("I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
printf("\nSignal Passing start\n\n");
kill(startProcess, SIGUSR1);
while(1) {
sigsuspend(&killSet);
}
}
else {
execl("circle",argv[0],pnarg,argv[2],argv[3],NULL);
}
}
}
else {
printf("I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
wait(NULL);
while(1) {
sigsuspend(&killSet);
}
}
}
}
stalls out. Can someone explain why?
The final child is not woken up from sigsuspend(&killSet) because you did sigaddset(&killSet,SIGUSR1); - you seem to have thought you have to add the signal to be waited for to the set, but on the contrary the signals in the given set are blocked from delivery. So just drop the sigaddset call.
To add to #Armali and as the sigset was not the only point to consider, it's seems more simple to provide an implementation with a far more simple handler and which avoid fork+exec, you'll found explanations in the comments. I'm not sur i'have understood what is your intent, from the comments i guess that you are looking to launch N processus with the last one sending cycles time SIGUSR1 to the parent, each child processus sending SIGUSR1 to their parent on receipt. Correct me if i'm wrong.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
// Two counters for the signal handler
int numSignals=0;
int numSignalsTotal=0;
// A simple handler that do nothing else that incrementing values in the process.
// To use a SIGINFO handler : void myHandler1 (int signal, siginfo_t *info, void *ucontext) {
void myHandler1 (int signal) {
numSignals++;
numSignalsTotal++;
}
void main(int arg, char ** argv) {
struct sigaction temp;
// As Armali pointed that, here you should not add SIGUSR1 to the sigset a you want
// to suspend your process and waiting for it.
sigemptyset(&killSet);
N = atoi(argv[1]);
pid_t process1 = 0;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
// A more complete initialization here, you need to include SIGUSR1 here to associate it
// to your handler. It seems you doesn't need specific flag like SA_RESTART for it here,
// as the handler code doesn't require that.
temp.sa_handler = myHandler1;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to set handler ...");
exit(1);
}
// Instead of a mix of fork + exec, it is more simple to keep one process and fork it for each new process.
// Here, we fork at least once, the parent process will alaways be "PARENT" and have a 0 startProcess,
// the child processes will fork themselves, the parent process is their and the new forked one will be
// the next child.
while (startProcess == 0 || N > 1 ) {
process1 = fork();
// To follow the forks : printf(" Fork pid=%d %s %s %s %s\n", process1, argv[0],argv[1],argv[2],argv[3]);
if(process1 != 0 && startProcess == 0) {
// If fork() gives us a pid and we have startProcess 0, then we are the "PARENT" process.
// The only thing we have to do is waiting for signals from our childs, if there is childs.
printf(" I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
// If there's no child, we simply quit the loop.
if (N == 1) break;
// For reference, "PARENT" output what is its first child.
printf(" -> child = %d\n" , process1);
// Here, while we have cycles, we wait for signals
while(numOfCycles > 0) {
// If you use a handler, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that "PARENT" caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> PARENT : N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// We substract that from our cycles and reset numSignals
numOfCycles-=numSignals; numSignals=0;
}
// If we are here, no more cycles, so we output on STDOUT a summary of "PARENT" processing
printf(" PARENT : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// Before leaving, "PARENT" should wait for its potential remaining childs to exit
printf(" PARENT waiting for child to terminate.\n");
if (wait(NULL) == -1) {
perror("ERR: PARENt failed to wait for childs termination...");
exit(1);
}
// We quit the loop, so we exit
break;
} else {
// If only one process (N=1) was asked, nothing more to do for the fork, we quit the loop then exit
if (N == 1 && startProcess == 0) break;
// We get the parent process pid in startProcess, as we are a child process
startProcess = getppid();
// If we are the forked process, we decrement N, it will "our" N as child
if (N > 1 && process1 == 0) {
N--;
}
if(process1 == 0) {
// If we are the forked process, we simply state our identity on STDOUT, the final child should be the one with N=1
if (N > 1) {
printf(" I am a child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
} else {
printf(" I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
}
if (N == 1) {
// If we are the final child, we simply have to send SIGUSR1 signals to our parent process for the number of cycles,
// after that we simply quit the loop and exit, no more forks are required.
while(numOfCycles > 0) {
printf("\n Cycle %d, first Signal start to %d\n\n", numOfCycles--, startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: LAST CHILD : Failed to send USR1...");
exit(1);
}
}
break;
}
// Note that if we are NOT the final child, we have to go through the loop to fork a new process for the next child.
} else {
if (N > 1) {
// If we are here, we are the forked process for a child and we are not the final child.
// So we do our payload, waiting for SIGUSR1 signals from our child and sending SIGUSR1 to our parent for the
// required number of cycles.
while(numOfCycles > 0) {
// If you use a handle, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that this child caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> CHILD: N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// For each receveid signals from our child, we send one to our parent
while (numSignals > 0) {
printf("\n Signal Passing start to %d\n\n", startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: CHILD : Failed to send USR1...");
exit(1);
}
// We decrement accordingly our number of cycles and signals
numOfCycles--;
numSignals--;
}
}
// If we are here, no more cycles, so we output on STDOUT a summary of the child processing
printf(" CHILD : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// We quit the loop, so we exit, then terminate our child
break;
}
}
}
}
// We should always restore signal handler to default when we exit.
temp.sa_handler = SIG_DFL;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to restore SIGUSR1 ...");
exit(1);
}
// We output on STDOUT the related PID at each process termination.
printf(" End of PID %d\n",getpid());
}

Reinstalling set signals in C

I'm trying to handle multiple signals with one signal handler, the expected result is for ctrlc to exit the child process and also exit the parent process while ctrlz prints a random number everytime ctrlz is pressed but it doesn't seem to work after the first signal is handled.The other part of the code is a child process that loops until ctrl-c is called.
This is the code.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <time.h>
#include <string.h>
int sig_ctrlc = 0;
int sig_ctrlz = 0;
//main signal handler to handle all signals
void SIGhandler(int sig) {
switch (sig) {
case SIGINT:
sig_ctrlc = SIGINT;
break;
case SIGTSTP:
sig_ctrlz = SIGTSTP;
break;
case SIGCHLD:
default: break;
}
}
int main() {
int fd[2]; //to store the two ends of the pipe
char get_inode[] = "ls -il STATUS.TXT";
FILE *fp;
FILE *log;
FILE *command;
time_t t;
time(&t);
int rv = 0;
log = fopen("file_log.txt", "w");
struct sigaction act;
memset (&act, 0, sizeof(struct sigaction));
act.sa_handler = SIGhandler;
//if pipe can't be created
if (pipe(fd) < 0) {
fprintf(log, "Pipe error");
}
int pid = fork();
switch(pid) {
case -1:
fprintf(stderr, "fork failed\n");
exit(1);
case 0:
/*child process */
// maps STDOUT to the writing end of the pipe
// if (dup2(fd[1], STDOUT_FILENO) == -1) {
// fprintf(log, "error in mapping stdout to the writing pipe\n");
// }
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTSTP, &act, NULL);
for (size_t i = 1;; i++) {
/* code */
printf(" running in child\n");
sleep(1);
if (sig_ctrlc != 0) {
printf("ctrlc handled\n");
printf("exiting...\n");
sig_ctrlc = 0;
break;
}
if (sig_ctrlz != 0) {
printf("ctlrz handled.\n");
/* random generator, the problem with this is it runs with time if ctrlz
is handled within a second it returns the same number
*/
srand(time(0));
int rand_num;
rand_num = rand() % (50 - 10 + 1) + 10;
printf("random number: %d\n", rand_num);
sig_ctrlz = 0;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTSTP, &act, NULL);
}
}
default:
/* parent process */
close(fd[1]);
//maps STDIN to the reading end of the pipe
// if (dup2(fd[0], STDIN_FILENO) < 0) {
// fprintf(log, "can't redirect");
// exit(1);
// }
// //checks for fopen not working and writes to STATUS.TXT with a redirect
// if ((fp = freopen("STATUS.TXT", "w", stdout)) != NULL) {
// printf("start time of program: %s\n", ctime(&t));
// printf("Parent process ID: %d\n", getppid());
// printf("Child process ID: %d\n", getpid());
//
// //gets inode information sends the command to and receives the info from the terminal
// command = popen(get_inode, "w");
// fprintf(command, "STATUS.TXT");
// fclose(command);
//
//// map STDOUT to the status file
// if(freopen("STATUS.TXT", "a+ ", stdout) == NULL) {
// fp = fopen("file_log.txt","w");
// fprintf(log, "can't map STATUS.TXT to stdout\n");
// exit(1);
// }
//
printf("parent has started\n");
wait(NULL);
time(&t);
printf("PARENT: My child's termination status is: %d at: %s\n", WEXITSTATUS(rv), ctime(&t));
// fprintf(fp, "PARENT: My child's termination status is: %d at: %s\n", WEXITSTATUS(rv), ctime(&t));
// fclose(fp);
// fclose(log);
sigaction(SIGINT, &act, NULL);
for (size_t i = 1;; i++) {
/* code */
printf("PARENT: in parent function\n");
sleep(1);
if (sig_ctrlc != 0)
exit(0);
}
}
return 0;
}
There are some good comments on the original post that help make minor fixes. I think there is also an issue of the static variables sig_ctrlc and sig_ctrlz maybe not being async-signal safe. Other than that though, I think your signal handling setup should work in a case where you repeatedly send SIGTSTP and then SIGINT after. I think how you are going about testing your program may be the issue.
Based on some clues you've given:
"ctrlz is pressed but it doesn't seem to work after the first signal is handled"
"doesn't handle both ctrlc and ctrlz after the first ctrlz"
It leads me to believe that what you are experiencing is actually the terminal's job control getting in your way. This sequence of events may explain it:
parent (process A) is started in terminal foreground in group %1
child (process B) is forked and also in terminal foreground in group %1
signal handlers are set up within child
in an attempt to signal the child, press ctrl-z to send SIGTSTP
owning terminal (grandparent of child (process B) in this case) receives the request
owning terminal broadcasts the signal to all processes in the foreground group
owning terminal removes group %1 from foreground
parent (process A) receives SIGTSTP and is suspended (default action)
child (process B) receives SIGTSTP and the signal handler is invoked
the random number is generated and printed on next iteration of child loop
subsequent attempts to signal the child via ctrl-z or ctrl-c are not forwarded to the child (or parent) by the terminal because nothing is in the terminal foreground
If that was indeed the case, at that point, you should be able to bring the processes back to the foreground by manually typing in fg and hitting enter. You could then try and signal again. However, a better way to test a program like this would be to run it in one terminal, then send the signals via kill(...) using their pid's from another terminal.
One extra note: unlike signal(...), sigaction(...) does not require "re-installation" after each disposition. A good explanation by Jonathan here https://stackoverflow.com/a/232711/7148416

I am wondering about how to kill the processes

I create child using the fork and I try to kill the generated child every 3 seconds. I also try to kill my parents using "raise or kill".
I don't know how to do to kill parent processor.
When I run my code except kill parent, unlike my expectations, so many child kill come out.
that's the code :
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main()
{
int ch[3];
int i;
for (i = 0; i < 3; i++) {
ch[i] = fork();
if (ch[i] == 0){
printf("child[%d]=%d\n",i,getpid());
exit(0); }
}
for(i = 0; i<3; i++) {
sleep(3);
kill(ch[i],SIGKILL);
printf("Killch[%d]=%d\n",i,ch[i]);
}
/* KILL or raise() parent kill */
}
How can I correct this code?
sleep() is not correct solution to collect child status, use wait() or waitpid() in parent.
when parent is in sleep
for(i = 0; i<3; i++) {
sleep(3);
kill(ch[i],SIGKILL);
printf("Killch[%d]=%d\n",i,ch[i]);
}
in your code child is not waiting for parent to kill ? child is killed by itself by exit(0) statement.
You(child) need to send it's exit status to parent and parent's need to collect the child's status using wait() or waitpid() and then kill ?
If you want to observe that whether parent is killing child or not, use delay in child and observe.
"I try to kill the generated child " I ? assuming parent,Here is my code
int a[3];
int temp[3]; //to set flag=1 , when child completes instruction and become zombie
//collect status in wait() in parent, so no need to further process in my_isr
void my_isr(int n) //if child has not completed instruction, i.e not removed by wait() in parent
{ //then remove it using my_isr
printf("in isr..\n");
static int i;
for(;i<3;i++)
if((temp[i]!=1) )//if first child "not turned into zombie and removed by parent" then kill it
{
printf("child %d killed \n",i+1);
kill(a[i],SIGKILL);
}
else
{
printf("zombie child %d has been terminated normally \n",i+1);
}
}
int main()
{
if( (a[0]=fork()) == 0)
{
int r;
srand(getpid());
r=rand()%10+1;
printf("child %d is going for sleep of %d sec\n",getpid(),r);
sleep(r);
exit(1);
}
else
{
if( (a[1]=fork()) == 0)
{
int r;
srand(getpid());
r=rand()%10+1;
printf("child %d is going for sleep of %d sec\n",getpid(),r);
sleep(r);
exit(2);
}
else
{
if( (a[3]=fork()) == 0)
{
int r;
srand(getpid());
r=rand()%10+1;
printf("in child %d is going for sleep of %d sec\n",getpid(),r);
sleep(r);
exit(3);
}
else
{
int s;
printf("in parent : %d \n",getpid());
signal(SIGALRM,my_isr);
//setting timer to tell child's that you need to completes within this duration
alarm(5);
while(wait(&s) != -1)//when there is no child left , wait returns -1
{
if( s>>8 == 1 )
temp[0]=1; //set the flag when exit status is received
else if( s>>8 == 2)
temp[1]=1; //set the flag when child completed work before
else if( s>>8 ==3)
temp[2]=1; //set the flags when zombies are removed
}
}
}
}
return 0;
}
I hope it help's you.

Inform parent process about child get signal after signal handler in child process is served

Hi currently I am collecting backtrace of child process in signal handler of child process . Then planning to send collected backtrace to parent process using message queue .
My problem is when child process get any signal. child signal handler runs but informs parent process that child exited normally instead of child get signal.
below is my code
void childProcess()
{
int h =0 ;
for(h=0;h<10;h++)
{
printf("child for loop running %d\n",h);
//sleep(1);
int q = 1/0; // generate floating point exception
}
exit(0);
}
void signalhandler(int signum, siginfo_t *si, void *arg)
{
printf("signal received %s\n",strsignal(signum));
printf("%d\n",signum);
void *array[100];
int size = 100;
int addrLen = backtrace(&array,size);
char ** sym = backtrace_symbols(&array,addrLen);
int j = 0;
printf("Test crashed due to %s\n",strsignal(signum));
for(j=0;j<addrLen;j++)
{
printf("%u : %s\n",array[j],sym[j]);
}
raise(signum);
exit(signum);
}
void registerSignals()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = signalhandler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
}
int main()
{
//while(1)
{
pid_t pid;
pid = fork();
if(pid == 0)
{
// child
printf("child process id is %d\n",getpid());
registerSignals();
childProcess();
}
else
{
printf("parent process id is %d\n",getpid());
// parent
int iStatus;
pid_t childPID = waitpid(pid,&iStatus,0);
printf("iStatus is %d\n",WIFEXITED(iStatus));
if(childPID == -1)
{
printf("wait pid failed\n");
}
else if(WIFEXITED(iStatus)==1)
{
printf("child exited normally!\n");
}
else if (WIFSIGNALED(iStatus)==1)
{
printf("child process terminated abnormally !!\n");
int iSignalnumber = 0;
// to fetch the signal number
iSignalnumber = WTERMSIG(iStatus);
printf("child process terminated due to %s\n",strsignal(iSignalnumber));
// to check core file is generated or not
if(WCOREDUMP(iStatus)==1)
{
printf("core file is generated \n");
}
else
{
printf("core file is not generated \n");
}
}
int h ;
for(h = 0; h<10;h++)
{
printf("parent executing : %d\n",h);
}
}
printf("while loop executing with pid : %d \n", getpid());
sleep(1);
}
}
My requirement is after signal handler is served in child process the
parent should print "child process terminated abnormally !!" but I am
getting "child exited normally!" message
From wait()'s Linux docs:
WIFEXITED(wstatus)
returns true if the child terminated normally, that is, by
calling exit(3) or _exit(2), or by returning from main().
The child signal handler ends the process using exit(), so everything works a specified.
Remove the call to exit() from the signal handler to get the expected result.
The call to raise() inside the signal handler most likely leads to recursive calls, so remove is as well.

Hanging loop with sleep()

I'm trying to learn how to handle signals. In my program I have an array of pids of earlier created subprocesess. No I want to every couple seconds send a sigtstp signal to one of them. He just have to send sigchld to parent process and exit. Parent process should print an exit code of exited process and create next one in the place of exit one. Everything works fine in first loop but it hangs in second. So on output get:
loop
slept
forking
in to array
loop
Zakonczyl sie potomek 3934 z kodem 0.
So it's seems that sleep works in first loop but not in second. Or just main process didn't get back control after handling signal but this should't happen. So I have no idea whats may be wrong here.
while(1) {
printf("loop\n");
sleep(5);
printf("slept\n");
int r = rand() % n;
if(kill(process_tab[r],SIGTSTP) < 0) {
printf("Error while sending sigtstp signal.\n");
} else {
printf("forking\n");
if((child = fork()) < 0) {
printf("Fork failed.\n");
} else if(child == 0) {//to sie dzieje w procesie
if(signal(SIGTSTP,&catch_sigtstp)) {
printf("Error while setting signal handler.\n");
_exit(EXIT_FAILURE);
}
while(1) {
}
} else { //to sie dzieje w parencie
process_tab[r] = child;
printf("in to array\n");
}
}
}
And here are handlers.
void catch_sigtstp(int signal) {
kill(ppid,SIGCHLD);
_exit(EXIT_SUCCESS);
}
void catch_sigchld (int signal) {
int status;
pid_t child = wait(&status);
printf("Zakonczyl sie potomek %d z kodem %d.\n",child,status);
}
Add fflush after printf.
printf("Something\n");
fflush(stdout);
Otherwise you may not get the output as stdio is buffered by default.
Edit: Issues of handler
It is pretty unsafe to use printf function in signal handler, as it is not reentrant. Also, the catch_sigchild function can be modified:
void catch_sigchld (int signal) {
int status;
pid_t child;
while ((child = waitpid(-1, &status, WNOHANG)) > 0)
{
// may be something else?
// ...printf("Zakonczyl sie potomek %d z kodem %d.\n",child,status);
}
}
The reason is that one signal can be delivered for multiple dead children.
Edit: blocking signal when printing.
To avoid deadlock inside stdio, you should block the signal:
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHILD);
...
sigprocmask(SIG_BLOCK, &set, NULL);
printf("my output");
sigprocmask(SIG_UNBLOCK, &set, NULL);
...
Edit: as #Barmar has pointed, you parent process will receive SIGCHILD signal twice: once from your child'd signal handler, and one from OS.
To fix, it might be sufficient to remove your own signal source:
void catch_sigtstp(int signal) {
// kill(ppid,SIGCHLD); //< This one causes two signals per one child
_exit(EXIT_SUCCESS);
}

Resources