Why can't I catch SIGCHLD every time after fork? - c

I am trying to create 4 child processes and until the children die, parent should wait. I wrote a program but when I run this code, 1 out of 10, it can't catch the SIGCHLD from every child and my program goes to infinite loop after. It happens really rare but still..
Could you tell me why and how can I fix it?
Here is my code.
sig_atomic_t child_exit_status;
sig_atomic_t child_numbers = 0;
void clean_up(int signal_number, siginfo_t * info, void* context)
{
//printf("SIGCHILD from %d calling\n", info->si_pid);
waitpid(info->si_pid, &child_exit_status, 0);
child_numbers++;
}
int main(int argc, char **argv)
{
// SIGCHLD catcher
struct sigaction sigchld_action;
memset(&sigchld_action, 0, sizeof(sigchld_action));
sigchld_action.sa_sigaction = &clean_up;
sigchld_action.sa_flags = SA_SIGINFO;
sigaction(SIGCHLD, &sigchld_action, NULL);
int pid1, pid2, pid3, pid4;
printf("pid : %d\n", getpid());
pid1 = fork();
//child1
if(pid1 == 0)
{
printf("child1 %d, parent %d\n", getpid(), getppid());
}
else
{
pid2 = fork();
//child2
if(pid2 == 0)
{
printf("child2 %d, parent %d\n", getpid(), getppid());
}
else
{
pid3 = fork();
//child3
if(pid3 == 0)
{
printf("child3 %d, parent %d\n", getpid(), getppid());
}
else
{
pid4 = fork();
//child4
if(pid4 == 0)
{
printf("child4 %d, parent %d\n", getpid(), getppid());
}
else
{
while(child_numbers < 4)
{
}
printf("i got the signals.");
}
}
}
}
return 0;
}
I tried something new but it also doesn't work..
void clean_up(int signal_number, siginfo_t * info, void* context)
{
printf("SIGCHILD from %d calling\n", info->si_pid);
while (1)
{
int status;
pid_t pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
{
break;
}
else
{
waitpid(pid, &status, 0);
break;
}
}
child_numbers++;
}

Related

why child can't send signal to parent

parent:
volatile int signalval = 0;
void signal_handle_c(int sig_num)
{
printf("child SIGUSR1 ok\n");
signalval = 1;
};
int main(int argc,char**argv){
struct sigaction act, oldact;
act.sa_handler = signal_handle_c;
act.sa_flags = SA_NOMASK;//SA_ONESHOT |
pid_t pid=fork();
if (pid < 0)
printf("error in fork!");
else if (pid == 0) {
printf("exec child!%s\n",argv[1]);
int res = execl(argv[1], "testc", NULL);
printf("res=%d", res);
}
else {
sleep(3);
sigaction(SIGUSR1, &act, &oldact);
printf("now parent\n");
}
waitpid(pid,NULL,0);
return 0;
}
child:
volatile int signal_pipe_end = 0;
void signal_handle_c(int sig_num)
{
printf("child IGUSR1 ok\n");
signal_pipe_end = 1;
};
int main(int argc, char *argv[])
{
printf("now child run!");
while (1)
{
printf("now child send siganl\n");
kill(getpid(), SIGUSR1);
sleep(1);
}
}
parent try to receive the SIGUSR1 signal from child.but none!
run result:
exec child!./testc
now child run!now child
now parent
i hope can printf "child SIGUSR1 ok".
why child "kill" send signal fail.

Why the child process will not exit normally?

Why is the following program will not work properly?
int cnt = 0;
void deal(int sig) {
++cnt;
}
int main() {
signal(SIGUSR1, deal);
pid_t child = fork();
if (child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
raise(SIGSTOP);
freopen("ab.out", "w", stdout);
printf("child : %d\n", cnt);
} else {
int app_status, app_sig, fd;
struct user_regs_struct app_reg;
struct rusage app_ruse;
waitpid(child, &app_status, 0);
printf("father: waitpid: %d\n", app_status);
while (1) {
ptrace(PTRACE_SYSCALL, child, NULL, NULL);
wait4(child, &app_status, 0, &app_ruse);
if (WIFEXITED(app_status)) {
printf("father: child exit normally, pid - %d\n", child);
break;
}
if (WIFSIGNALED(app_status) || (WIFSTOPPED(app_status)
&& WSTOPSIG(app_status) != SIGTRAP)) {
....
break;
}
ptrace(PTRACE_GETREGS, child, NULL, &app_reg);
if (app_reg.orig_rax == SYS_open && (fd = app_reg.rax) >= 0) {
kill(child, SIGUSR1);
}
}
}
return 0;
}
When run the program, got follow result
Why did the child process exit directly after receiving the signal?
The full code can got here.
https://pastebin.ubuntu.com/p/FddVZpfGH7/

Creating shared memory in C

I created following method in C to create a shared memory segment to store counter value. But I can't store data in this segment.When I try to print the value of the counter it gives me a garbage value.Whats wrong with this code?
CreateCounter()
{
key = ftok(".",'B');
shmCntid = shmget(key,COUNTER_SIZE,IPC_CREAT|0666);
if(shmCntid == -1 )
{
perror("shmget");
exit(1);
}
else
{
printf("Creating new Sahred memory sement\n");
cntPtr = shmat(shmCntid,0,0);
if(cntPtr == -1 )
{
perror("shmat");
exit(1);
}
}
}
This method is called inside the main method as follows.
int *cntPtr;
int rowCnt;
sem_t s;
sem_t c;
sem_t r;
int main(int argc, int *argv[])
{
int pid, pid2, pid3, i;
CreateBuf1();
CreateBuf2();
CreateCounter();
GetInput(argv[1],*buf1Ptr);
sem_init(&c, 0, 1);
sem_init(&r, 0, 1);
sem_init(&s, 0, 1);
for( i = 0 ; i < 9; i++)
{
pid = fork();
if(pid < 0)
{
printf("Fork error !\n");
}
else if (pid == 0)
break;
}
if(pid < 0)
{
printf("Fork error !\n");
}
else if (pid == 0)
{
sem_wait(&r);
Grp1 (i,i);
cntPtr+=rowCnt;
sleep(1);
sem_post(&r);
sem_post(&c);
exit(0);
}
else
{
wait(NULL);
}
pid2 = fork();
if(pid2 < 0)
{
printf("Fork error !\n");
}
else if (pid2 == 0)
{
sem_wait(&c);
Grp2(9);
cntPtr+=colCnt;
sleep(1);
sem_post(&c);
exit(0);
}
else
{
wait(NULL);
}
// This space is to print the values..............
shmctl(shmBuf1id,IPC_RMID,0);
shmctl(shmBuf2id,IPC_RMID,0);
shmctl(shmCntid,IPC_RMID,0);
return 0;
}

Signal handlers not working across different process groups

I am using execp under a child created using fork for which I have set new process group and have set it has foreground process group using tcsetpgrp
Here is my code for main
int main()
{
signal(SIGINT,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
pid_t pid=fork();
if(pid==-1)
{
perror("Error in forking");
}
else if(pid == 0)
{
signal(SIGTTOU, SIG_IGN);
setpgid(getpid(),getpid());
//check denotes if process needs to be run in background or not
if(!check)
{
tcsetpgrp(STDOUT_FILENO,getpgid(getpid()));
tcsetpgrp(STDIN_FILENO,getpgid(getpid()));
}
signal(SIGTSTP, tstphandler);
signal(SIGINT,inthandler);
if(strlen(token)>0)
{
execer=execlp(token,token,args,(char*)NULL);
if (execer==-1)
{
printf("Error in execution);
}
exit(0);
}
}
else
{
//processes is a data structure which contains pid of
//processes and current status :- 0 = running in background
//, 1= dead , 2 = stopped in background , -1= in foreground.
if(check)
{
processes[pid_counter].pid=pid;
processes[pid_counter].dead=0;
}
if(!check && strlen(token)>0)
{
processes[pid_counter].pid=pid;
processes[pid_counter].dead=-1;
waitpid(pid,&status,0);
tcsetpgrp(STDOUT_FILENO,globalpgid);
tcsetpgrp(STDIN_FILENO,globalpgid);
processes[pid_counter].dead=1;
}
}
}
and these are my handlers
//SIGINT handler
void inthandler(int sig)
{
printf("int handler\n");
int i;
for(i=0;i<=pid_counter;i++)
{
if(processes[i].dead==-1)
{
kill(processes[i].pid,SIGKILL);
break;
}
}
}
//SIGTSTP handler
void tstphandler(int sig)
{
int i;
for(i=0;i<=pid_counter;i++)
{
if(processes[i].dead==-1)
{
processes[i].dead=2;
kill(processes[i].pid, SIGSTOP);
break;
}
}
tcsetpgrp(STDOUT_FILENO,globalpgid);
tcsetpgrp(STDIN_FILENO,globalpgid);
}
My problem is that these signal handlers are not being called from child processes. They are being called with their default action but not with my declared handler.

How can I make a "binary process tree"?

I have a number of process to create. Every son has to create two sons. I used a recursive solution, it works but the number of process created aren't what I want.
This is what I tried:
void generate_kid(int g, int res){
pid_t kid1, kid2;
int status1, status2;
if( res > 0 ){
if( kid1 = fork() ){
if( res > 0){
if( kid2 = fork() ){
}
else {
printf("I am %d, my father is %d\n",getpid(),getppid());
generate_kid(g,res/2-1);
}
}
}
else {
printf("I am %d, my father is %d\n",getpid(),getppid());
generate_kid(g,res/2-1);
}
}
waitpid(kid1,&status1,0);
waitpid(kid2,&status2,0);
}
Try this:
void generate_kid(int res){
pid_t kid1, kid2;
int status1, status2;
if( res > 0 ){
if ((kid1 = fork()) == 0) {
// child
printf("I am %d, my father is %d\n",getpid(),getppid());
// generate half remaining rounded up for odd processes
generate_kid((res-1)/2);
}
else if (kid1 > 0) {
// parent - create second child
if( res > 1){
if ((kid2 = fork()) == 0) {
// child 2
printf("I am %d, my father is %d\n",getpid(),getppid());
// generate half remaining processes
generate_kid((res-2)/2);
}
else if (kid2 > 0){
// parent 2
waitpid(kid2,&status2,0);
}
}
waitpid(kid1,&status1,0);
}
}
}

Resources