Reputation: 73
I am practicing programming with unix signals and I am new to it, so I wrote following program: http://wklej.org/id/2253905/ , that i am compiling in following way: gcc -Wall -o signals signals.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
void child_work(int l);
void create_children(int n, int l);
void parent_work(int k, int p);
int sethandler( void (*f)(int), int sigNo);
void child_handler(int sig);
void parent_handler(int sig);
void sigchld_handler(int sig);
void usage(void);
volatile sig_atomic_t last_signal = 0;
int sethandler( void (*f)(int), int sigNo)
{
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = f;
if (-1==sigaction(sigNo, &act, NULL))
return -1;
return 0;
}
void sigchld_handler(int sig) {
pid_t pid;
for(;;)
{
pid=waitpid(0, NULL, WNOHANG);
if(pid==0) return;
if(pid<=0)
{
if(errno==ECHILD)
{
printf("[%d] No more children parent quits.",getpid());
exit(EXIT_SUCCESS);
}
perror("waitpid:");
exit(EXIT_FAILURE);
}
}
}
void child_handler(int sig)
{
printf("[%d] received signal %d\n", getpid(), sig);
last_signal = sig;
if(last_signal==SIGUSR1)
if(0==kill(0,SIGUSR2))
printf("[%d] SENDING signal %d\n", getpid(), SIGUSR2);
else
perror("kill:");
}
void parent_handler(int sig) {
printf("[%d] received signal %d\n", getpid(), sig);
last_signal = sig;
}
void child_work(int t)
{
int s;
srand(getpid());
s=rand()%(t-1)+2;
struct timespec tt, tn = {s,0};
for(tt=tn;nanosleep(&tt,&tt);)
if(EINTR!=errno)
perror("nanosleep:");
printf("[%d] dies",getpid());
exit(EXIT_SUCCESS);
}
void create_children(int n, int t)
{
while (n-->0)
{
switch (fork())
{
case 0:
if(sethandler(child_handler,SIGUSR1))
{
perror("Seting child SIGUSR1:");
exit(EXIT_FAILURE);
}
if(sethandler(child_handler,SIGUSR2))
{
perror("Seting child SIGUSR2:");
exit(EXIT_FAILURE);
}
child_work(t);
exit(EXIT_SUCCESS);
case -1:
perror("Fork:");
exit(EXIT_FAILURE);
}
}
}
void usage(void){
fprintf(stderr,"USAGE: signals n t\n");
fprintf(stderr,"n - number of children > 0\n");
fprintf(stderr,"t - max lifetime of child process\n");
}
int main(int argc, char** argv)
{
int n,t;
//int childcount;
if(argc!=3)
{
usage();
return EXIT_FAILURE;
}
n = atoi(argv[1]);
t = atoi(argv[2]);
if (n<=0 || t<=1) {
usage();
return EXIT_FAILURE;
}
if(sethandler(SIG_IGN,SIGUSR1))
{
perror("Seting parent SIGUSR1:");
exit(EXIT_FAILURE);
}
if(sethandler(parent_handler,SIGUSR2))
{
perror("Seting parent SIGUSR2:");
exit(EXIT_FAILURE);
}
if(sethandler(sigchld_handler,SIGCHLD))
{
perror("Seting parent SIGCHLD:");
exit(EXIT_FAILURE);
}
create_children(n, t);
struct timespec tt, tn = {1,0};
while(1)
{
for(tt=tn;nanosleep(&tt,&tt);)
if(EINTR!=errno) perror("nanosleep:");
if(0==kill(0,SIGUSR1))
printf("[%d] SENDING signal %d\n", getpid(), SIGUSR1);
else
perror("kill:");
}
return EXIT_SUCCESS;
}
and when i run it ./program 3 3 (it spawns 3 children) i get weird output like:
[2835] dies[2836] dies[2834] dies[2836] dies[2836] received signal 10
[2836] received signal 12
[2836] SENDING signal 12
[2835] dies
as you can see [2835] and [2836] die 2 times and I am just wondering why it behaves like this? Thank you in advance for your help.
Upvotes: 2
Views: 51
Reputation: 3147
Using printf()
in signal handler function leads to undefined behavior.
I was not able to reproduce your bug with my Debian 8.3 Virtual Machine. Behavior will depend on operating system.
Check here Async-signal-safe functions
Upvotes: 1