How can I make a "binary process tree"? - c

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);
}
}
}

Related

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

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++;
}

How to make multiple child proccess pause until a signal is sent

I have a program with three child processes all doing the exact same thing with a fourth child process told send signals while the main function waits until the three child processes are complete. I am using an alarm signal as well as two user signals to make the child process send output to a different terminal. I'm using the pause function to wait for a signal but the second I start the program it completes, not waiting at all. Am I using pause correctly?
int alarmR =0;
int SNMPR =0;
int reconR=0;
int child_pid[4];
char strD[100];
FILE *fpt[4];
void Alarmhandler(int sig);
void Reconfigure(int sig);
void SNMPhandler(int sig);
int which(int wait_ret, int child_proc[], int p);
void IT1(void);
void IT2(void);
void IT3(void);
void command(void);
void command(void)
{
signal(SIGALRM,Alarmhandler);
signal(SIGUSR1,Reconfigure );
signal(SIGUSR2,SNMPhandler );
char text;
int n;
printf("please enter a command from the following list\n");
printf("\tsn:Send a SNMP request\n\trn:Send a reconfiguration");
printf("script\n\tkn: shutdown process\n");
scanf("%c%d",&text,&n);
if(text == 'k')
{
printf("Terminated IT service %d\n",n);
n = n-1;
kill(child_pid[n],1);
}
else if(text=='s')
{
n = n-1;
kill(child_pid[n],SIGUSR2);
}
else if(text=='r')
{
n = n-1;
kill(child_pid[n],SIGUSR1);
}
}
void Alarmhandler(int sig)
{
alarmR =1;
}
void Reconfigure(int sig)
{
reconR =1;
}
void SNMPhandler(int sig)
{
SNMPR =1;
}
int which(int wait_ret, int child_proc[], int p)
{
int i;
for (i = 0; i < p; i++)
if (child_proc[i] == wait_ret)
return i;
return -1;
}
int main(int argc, char *argv[])
{
int ttyindex;
// int Terminal[4];
int term_cnt = 0;
int wait_r,x;
int process = 0;
int child_proc[4];
int es[3];
if(argc != 5) {
printf("Usage: ./lab7 1 2 3 4\n");
exit(1);
}
for(term_cnt =0; term_cnt <4;term_cnt ++)
{
ttyindex = -1;
ttyindex = atoi(argv[term_cnt+1]);
if (ttyindex < 1) {
printf("invalid terminal number %s\n", argv[term_cnt+1]);
exit(1);
}
sprintf(strD, "/dev/pts/%d", ttyindex);
child_proc[process] = fork();
if (child_proc[process] != 0)
{
// parent process
process++;
child_proc[process] = fork();
if (child_proc[process] != 0)
{
// parent process
process++;
child_proc[process] = fork();
if (child_proc[process] != 0)
{
// parent process
process++;
child_proc[process] = fork();
if(child_proc[process] !=0)
{
wait_r = wait(NULL);
x =which(wait_r, child_proc, process);
printf("Waited for %d (child %d) to finish.\n", wait_r,x);
if(WIFEXITED(wait_r))
{
es[x] = WEXITSTATUS(wait_r);
}
wait_r = wait(NULL);
x =which(wait_r, child_proc, process);
printf("Waited for %d (child %d) to finish.\n", wait_r,x);
if(WIFEXITED(wait_r))
{
es[x] = WEXITSTATUS(wait_r);
}
wait_r = wait(NULL);
x =which(wait_r, child_proc, process);
printf("Waited for %d (child %d) to finish.\n", wait_r,x);
if(WIFEXITED(wait_r))
{
es[x] = WEXITSTATUS(wait_r);
}
for(x = 0; x <3;x++)
{
if(es[x] == 0)
{
printf("\nJob well done IT specialist %d",(x+1));
printf(" Prepare for new attacks!\n");
}
else if(es[x] == 1)
{
printf("\nIT service %d compromised",(x+1));
printf(" , we are going out of business!\n");
}
else
{
printf("\nCall HR, we need a new");
printf(" cybersecurity expert for service");
printf(" %d\n",(x+1));
}
}
}
else
{
child_pid[3] = getpid();
command();
}
}
else
{
child_pid[2]=getpid();
IT3();
}
}
else
{
child_pid[1] = getpid();
IT2();
}
}
else
{
child_pid[0] = getpid();
IT1();
}
}
void IT1(void)
{
printf("i live");
signal(SIGALRM,Alarmhandler);
signal(SIGUSR1,Reconfigure );
signal(SIGUSR2,SNMPhandler );
clock_t start=0, end=0;
static int check = 0;
static int recona =0;
double t= 0;
int threat= 1;
srand48(time(NULL));
fprintf(fpt[1],"This is IT service 1\n");
while(1)
{
printf("%d %d %d",reconR,alarmR,SNMPR);
pause();
// alarm(1);
if(reconR == 1)
{
reconR =0;
if(recona >0)
{
fprintf(fpt[1],"Cannot reconfigure more than once.you are fired!");
exit(1);
}
if(threat < 16)
{
fprintf(fpt[1],"Threat level is not critical.you are fired");
exit(1);
}
fprintf(fpt[1],"Reconfiguring system to thwart attack-this may take a few seconds\n");
recona++;
}
if(alarmR == 1 )
{
if(check >0)
{
t =((double)(end - start))/CLOCKS_PER_SEC;
}
alarmR = 0;
if(recona >0)
{
threat --;
}
else
{
if (drand48() < 0.5)
{
threat++;
}
else if (threat > 1 && drand48() < 0.6)
{
threat--;
}
}
if(t <5)
{
fprintf(fpt[1],"Next report available in %f seconds\n",(5-t));
}
if(threat >15)
{
fprintf(fpt[1],"Intruder! Data stolen...");
exit(1);
}
else if(threat < 10 && recona >0)
{
fprintf(fpt[1],"Attack averted. Mission Complete");
exit(0);
}
}
if(SNMPR == 1)
{
if(check == 2)
{
end = clock();
t = ((double)(end - start))/CLOCKS_PER_SEC;
}
SNMPR = 0;
check = 1;
if(t <5)
{
fprintf(fpt[1],"Load to high. Threat is increased");
threat++;
t = 0;
}
else{
if(threat >=10)
fprintf(fpt[1],"Threat level is red\n");
else if(threat <10 && threat >=5)
fprintf(fpt[1],"Threat level is orange\n");
else
fprintf(fpt[1],"Threat level is green\n");
}
if(check ==1)
{
start = clock();
check = 2;
}
}
}
}
you can use the sigsuspend() system call to make a process wait for a signal, and kill() for sending signal to a process or process group.I hope by using both of these system calls, you can code your desired task.
you are putting a wait() on a process which has no child here
wait_r = wait(NULL);
This causes that wait() return immediately with error ECHILD and terminates the fourth child process. It's termination raises SIGCHLD causes pause() to return.

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;
}

Use loop to fork varying number of children

Most of the examples I come across show how to fork, like this one:
main()
{
int pid;
pid = fork();
// child
if (pid == 0)
{
...
}
// Parent
else if (pID > 0)
{
...
}
}
Some show how to fork 2 children, like so
pid = fork();
// Child
if ( pid==0 )
{
...
}
// Parent
else if ( pid>0 )
{
pid=fork();
// Second child
if ( pid==0 ){
...
}
}
And here is my attempt to fork 5 children...
pid = fork();
// Child
if ( pid==0 )
{
...
}
// Parent
else if ( pid>0 )
{
pid=fork();
// Second child
if ( pid==0 ){
...
}
// Parent
else if ( pid>0 )
{
pid=fork();
// Third child
if ( pid==0 ){
...
}
// Parent
else if ( pid>0 )
{
pid=fork();
// Fourth child
if ( pid==0 ){
...
}
// Parent
else if ( pid>0 )
{
pid=fork();
// Fifth child
if ( pid==0 ){
...
}
}
}
}
}
Question:
My point is that this is insanity. Is there a cleaner way to loop through and create a varying number of children (ie. specified via a command line argument)?
NOTE:
It is vitally important that the children distinguish themselves apart (ie. write "hi, I am child number 6"...) as my job involves each process signalling a different computer. Currently I am doing so using semaphores and an array of target computers. What I would rather want is increasing indeces 1..N for the processes.
Use a for loop. Each process will get it's own copy of the loop variable.
int pid;
int numKids = 5;
int procNum;
for(procNum = 0; procNum < numKids; procNum++) {
// Note: haven't included error handling...
pid = fork();
if (pid == 0) {
break;
}
}
if (pid == 0) {
// child specific stuff. procNum is set to the "child number"
}
else {
// parent stuff
}

Linux Shell Pipeline Execution

I am trying to implement a basic linux shell with support for pipelining. However, my code seems to hang or just not execute programs and I can't figure out why.
if (list_empty(&job_list))
job_index = 1;
bool dopipe = false;
if (list_size(&pipeline->commands) > 1)
dopipe = true;
esh_signal_sethandler(SIGCHLD, signal_handler);
esh_signal_block(SIGCHLD);
setpgid(0, 0);
pipeline->pgrp = getpgid(0);
pipeline->jid = job_index++;
list_push_back(&job_list, &pipeline->elem);
bool background = pipeline->bg_job;
pid_t pid;
if ( (pid = fork()) == 0)
{
//Child
if (pipeline->bg_job)
setpgid(0, 0);
int oldpipe[2];
int newpipe[2];
int count = 0;
int size = list_size(&pipeline->commands);
struct list_elem * current_job;
printf("SIZE: %zu\n", list_size(&pipeline->commands));
for (current_job = list_begin(&pipeline->commands); current_job != list_tail(&pipeline->commands); current_job = list_next(current_job))
{
if (count < size)
pipe(newpipe);
pid_t fpid = fork();
printf("fpid: %d\n", (int)fpid);
if (fpid == 0)
{
//Child
printf("Executing Child\n");
if (count > 0)
{
//prev command exists
dup2(oldpipe[0], 0);
close(oldpipe[0]);
close(oldpipe[1]);
}
if (count < size - 1)
{
//next command exists
close(newpipe[0]);
dup2(newpipe[1], 1);
close(newpipe[1]);
}
esh_command* cmd = list_entry(current_job, struct esh_command, elem);
printf("Running: %s %s\n", cmd->argv[0], cmd->argv[1]);
if (execvp(cmd->argv[0], cmd->argv) < 0)
esh_sys_fatal_error("Program Does Not Exist\n");
}
else
{
//Parent
//*
int status = 0;
if (waitpid(fpid, &status, 0) < 0)
esh_sys_fatal_error("Could not fork pipe\n");
//*/
printf("Parent\n");
if (count > 0)
{
//prev command exists
close(oldpipe[0]);
close(oldpipe[1]);
}
if (count < size - 1)
{
//next command exists
oldpipe[0] = newpipe[0];
oldpipe[1] = newpipe[1];
}
printf("End of Parent\n");
}
count++;
}
if (size > 1)
{
close(oldpipe[0]);
close(oldpipe[1]);
}
printf("Finished Pipeline\n");
exit(3);
}
else
{
//*
int status = 0;
commands->pid = pid;
//Parent
if (!background)
{
pipeline->status = FOREGROUND;
if (waitpid(pid, &status, 0) < 0)
printf("waitpid ERROR\n");
list_remove(&pipeline->elem);
}
else
pipeline->status = BACKGROUND;
//*/
}
esh_signal_unblock(SIGCHLD);
I am fairly certain the error has to do with either the piping, or the forking of child processes in the loop.

Resources