Infinite Loop waiting a process on C - c

I'm trying to make a main process wait for the completion of the process instructed by waitpid, but right on the call to waitpid, an infinite loop occurs.
It seems that the process referenced by waitpid never ends.
This process is always an execlp to unix command, as wc, rev, cat ...
If I comment the code concerning waitpid, unix command ends perfectly.
Deputy code for the call to the mandate and the wait:
int pid;
int estado_proceso;
for(pid=0;pid<numFiltros;pid++)
{
fprintf(stderr,"A esperar a %d\n", pids[pid]);
if (waitpid(pids[pid],&estado_proceso,0) >= 0)
imprimir_estado(filtros[pid], estado_proceso);
else
{
fprintf(stderr,"Error al esperar proceso %d\n",pid);
exit(1);
}
}
fprintf(stderr,"A ejecutar comando \n");
execlp(filtro,filtro, NULL);
fprintf(stderr,"Error al ejecutar el mandato '%s'\n",filtro);
exit(1);
Edit:
Fork and Pid obtain code:
switch(pid = fork())
{
/* Error en el Fork */
case -1:
fprintf (stderr,"Error al crear proceso %d\n", pid);
exit(1);
/* Father Process*/
default:
pids[i-1] = pid;
On Main:
pids = (pid_t*) malloc (sizeof(pid_t)*numFiltros);
Where "numFiltros" is the number of unix commands like wc, cat, rev...
Any idea?
Thanks a lot!

Try using wait instead of explicit waitpid, that is, try replacing your waiting code with
int pid;
int estado_proceso;
while((pid = wait(&estado_proceso)) >= 0) {
if(pid > 0) {
fprintf(stderr, "Process with PID %d terminated.\n", pid);
imprimir_estado(pid, estado_proceso);
}
}

Related

Signal Handler Behavior

I have just some questions about the system calls signal, kill and the signal handler.
I have this code:
int figlio=-1;
int main(int argc,char* argv[])
int pid1,pid2,dormi,numero;
float reciproco;
signal(SIGUSR1,gestore);
signal(SIGUSR2,gestore);
numero=atoi(argv[1]);
printf("Numero %d\n\n",numero);
fflush(stdout);
pid1=fork();
if(pid1>0) //PADRE
{
pid2=fork();
if(numero%2 == 0)
kill(pid1,SIGUSR1);
else
kill(pid2,SIGUSR2);
wait(NULL);
wait(NULL);
}
if(pid1 == 0) //FIGLIO1
{
//sleep(1);
printf("%d\n",figlio);
if(figlio == 1)
{
numero=numero*numero*numero;
fflush(stdout);
printf("Ho eseguito il cubo %d\n",numero);
}
else
{
pause();
if(figlio == 1) //Se il gestore di SIGUSR1 è partito
{
fflush(stdout);
printf("Ciao dal figlio 1\n");
}
}
printf("Figlio1 termina\n\n");
exit(0);
}
if(pid2 == 0) //FIGLIO2
{
if(figlio == 2)
{
dormi=numero;
reciproco=(float)numero;
reciproco=1/reciproco;
fflush(stdout);
printf("Ho eseguito il reciproco %f\n",reciproco);
sleep(dormi);
fflush(stdout);
printf("Mando un segnale a mio fratello %d\n",pid1);
kill(pid1,SIGUSR1);
}
else
printf("Arrivederci e grazie\n");
printf("Figlio2 termina\n\n");
exit(0);
}
return 0;
}
void gestore(int signo)
{
if(signo == SIGUSR1)
figlio=1;
else
figlio=2;
}
1) I don't understand why the first printf in the first child, return -1 without a sleep(1) before...seems that the handler is executed after the beginning of the child.
2) When there is a kill to a child, after this, the scheduler works on the child or continue on the father?
3) The handler is executed when the kill is sent or when the scheduler works on the child?
After the fork(), the parent and child processes are in a race. There is no guarantee the parent will have a chance to issue the call to kill() to the child before the child reaches the printf() call.
If there are multiple processors, both processes can be running simultaneously. Otherwise, if the child is not currently running, Linux will set some internal state that the signal should be delivered to the child process when it next runs, and it will mark the process as runnable if it is not already.
If the child is currently running, the signal gets processed immediately. Otherwise, it is processed when the child next runs. The handler is run as a result of processing the signal.

exit() the program from parent before child process has terminated

I have a C server. This server has to handle multiple connections and user's input (through a simple ncurses GUI). So I created two childs.
My problem comes when from the main menu of the user interface, I need to exit the program (then terminate the second child process -which handles the connections- from the first child process).
I'll try to explain myself with a little example:
int main(){
pid_t pid;
int status1, status2;
if((pid = fork()) < 0){
perror("main fork failure:");
exit(1);
}
if(pid == 0){
pid = fork();
if(pid == 0){
/*
some stuff the second child does while
the first child is already running
*/
}
/* this is the first child */
int choice;
choice = menu();
switch(choice){
case 1:
break;
case 2:
/*
HERE I have to exit (from the first child first,
and from the program then): how can I kill the
second child that is running to prevent
zombie processes?
*/
// kill() which pid?
exit(2);
break;
}
wait(&status2);
}
wait(&status1);
return 0;
}
So, how can I kill it if I don't know the second child pid from the first child?
In your code, you reuse the variable pid, but fortunately, the non-zero pid is the one you need to signal.
Hence:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
extern int menu(void);
static void wait_for_pid(int pid)
{
int status;
int corpse;
while ((corpse = wait(&status)) >= 0 && corpse != pid)
printf("Unexpected child %d exited with status 0x%.4X\n", corpse, status);
if (corpse == pid)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
else
printf("Child %d died without its death being tracked\n", pid);
}
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
perror("main fork failure:");
exit(1);
}
if (pid == 0)
{
if ((pid = fork()) < 0)
{
perror("child fork failure:");
exit(1);
}
if (pid == 0)
{
pause(); /* Do nothing until signalled */
exit(0);
}
/* this is the first child */
int choice = menu();
switch (choice)
{
case 1:
/* action 1 */
break;
case 2:
kill(pid, SIGTERM);
exit(2);
/*NOTREACHED*/
}
wait_for_pid(pid);
exit(0);
}
wait_for_pid(pid);
return 0;
}
The loop in the wait_for_pid() function should be overkill for the child, but the parent process could have children it doesn't know about under some circumstances — unlikely but not impossible circumstances.
The use of pause() in the second child is simply writing some code; it is not useful and would not therefore be what you'd write there. Writing the comment /* action 1 */ is likewise dummy code; you'd replace it with code that does something useful. I'd probably have functions to call for the first child and the second child, rather than embedding much code in main(). I assume that it's written as shown to create an MCVE (Minimal, Complete, Verifiable Example); thank you for keeping the code small.
The code above was untested because there was no menu() function. The code below has a menu function — not that it is very interactive.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
extern int menu(void);
int menu(void)
{
printf("Dozing...\n");
sleep(1);
printf("Menu option 2 chosen\n");
return 2;
}
static void wait_for_pid(int pid)
{
int status;
int corpse;
int curpid = getpid();
printf("%d: waiting for children to die\n", curpid);
while ((corpse = wait(&status)) >= 0 && corpse != pid)
printf("%d: Unexpected child %d exited with status 0x%.4X\n", curpid, corpse, status);
if (corpse == pid)
printf("%d: Child %d exited with status 0x%.4X\n", curpid, corpse, status);
else
printf("%d: Child %d died without its death being tracked\n", curpid, pid);
}
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
perror("main fork failure:");
exit(1);
}
if (pid == 0)
{
if ((pid = fork()) < 0)
{
perror("child fork failure:");
exit(1);
}
if (pid == 0)
{
printf("Second child (%d) - pausing\n", (int)getpid());
pause(); /* Do nothing until signalled */
printf("Second child (%d) - awake despite no signal handling\n", (int)getpid());
exit(0);
}
/* this is the first child */
printf("First child (%d) - menuing\n", (int)getpid());
int choice = menu();
switch (choice)
{
case 1:
/* action 1 */
break;
case 2:
printf("kill(%d, SIGTERM)\n", pid);
kill(pid, SIGTERM);
wait_for_pid(pid);
exit(2);
/*NOTREACHED*/
}
/* Reached on menu choices != 2 */
/* Probably needs a loop around the menu() - end loop before wait_for_pid() */
wait_for_pid(pid);
exit(0);
}
wait_for_pid(pid);
return 0;
}
When run, a sample output sequence was:
19489: waiting for children to die
First child (19490) - menuing
Dozing...
Second child (19491) - pausing
Menu option 2 chosen
kill(19491, SIGTERM)
19490: waiting for children to die
19490: Child 19491 exited with status 0x000F
19489: Child 19490 exited with status 0x0200
All of which looks as would be expected. You can see the death from SIGTERM in the status 0x000F (SIGTERM is normally 15, and is 15 on macOS Sierra, though AFAIK no standard demands that it is 15). You can see the first child exited normally with status 2 from the 0x0200. You can see that the parent started waiting before the children did anything. And you can see the debugging techniques — copious printing and including the PID most of the time.

Creating two pipes with three execlp small error somewhere C System Programming

I'm trying to create three child processes and two pipes that will execute three execlp(). When my program runs, however, the output is not what I expect.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid = getpid();
printf("STARTING PROCESSXXX %d\n",pid);
int c1Toc2[2];
int c2Toc3[2];
if(pipe(c1Toc2) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
if(pipe(c2Toc3) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
int rValue = fork();
if(rValue == -1)
{
perror("Child_1");
}
else if (rValue == 0)
{
printf("CHILD 1: ");
printf("PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);
dup2(c1Toc2[1], STDOUT_FILENO);
close(c1Toc2[0]);
close(c2Toc3[0]);
execlp("ps", "ps", "-ef", NULL);
exit(0);
}
rValue = fork();
if(rValue == -1)
{
perror("Child_2");
}
else if (rValue == 0)
{
printf("CHILD 2: ");
printf("PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n",
(long) getpid(), (long) getppid(), rValue);
dup2(c1Toc2[0], STDIN_FILENO);
close(c1Toc2[1]);
dup2(c2Toc3[1], STDOUT_FILENO);
close(c2Toc3[0]);
printf("CHILD 2 : goodbye\n");
execlp("grep","grep","root",NULL);
printf("CHILD 2 : goodbye\n");
exit(0);
}
rValue = fork();
if(rValue == -1)
{
perror("Child_3");
}
else if (rValue == 0)
{
printf("CHILD 3: ");
printf("PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n",
(long) getpid(), (long) getppid(), rValue);
dup2(c2Toc3[0], STDIN_FILENO);
close(c2Toc3[1]);
close(c2Toc3[0]);
printf("CHILD 3 : \n");
execlp("sort","sort","-n", "-k4",NULL);
printf("CHILD 3 : goodbye\n");
exit(0);
}
close(c1Toc2[1]);
close(c1Toc2[0]);
close(c2Toc3[1]);
close(c2Toc3[0]);
// Add the code for the two children here
sleep(3);
printf("PARENT: PROCESS Waiting on children to complete\n");
printf("Final Print Statement before exit\n");
exit(0);
}
The problem is that you didn't close the pipe file descriptors in the children and so, because you dup'ed them over to STDOUT_FILENO (e.g. - grep child), even though the program was done its regular output it didn't fully exit and post an EOF to the next child process (i.e. - sort) and so those children hung around waiting forever.
I'm not entirely sure why your grep process refused to exit like normal because it does seem that the ps child exits, which should post an EOF to the grep child's stdin.
Here's a version that does what you want:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid = getpid();
printf("PARENT: STARTING PROCESSXXX %d\n",pid);
int c1Toc2[2];
int c2Toc3[2];
if (pipe(c1Toc2) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
if (pipe(c2Toc3) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
int rValue = fork();
if (rValue == -1)
{
perror("Child_1");
exit(EXIT_FAILURE);
}
else if (rValue == 0)
{
printf("CHILD 1: PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);
dup2(c1Toc2[1], STDOUT_FILENO);
close(c1Toc2[0]);
close(c1Toc2[1]);
close(c2Toc3[0]);
close(c2Toc3[1]);
execlp("ps", "ps", "-ef", NULL);
perror("CHILD 1: execlp");
exit(EXIT_FAILURE);
}
rValue = fork();
if (rValue == -1)
{
perror("Child_2");
exit(EXIT_FAILURE);
}
else if (rValue == 0)
{
printf("CHILD 2: PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);
dup2(c1Toc2[0], STDIN_FILENO);
dup2(c2Toc3[1], STDOUT_FILENO);
close(c1Toc2[0]);
close(c1Toc2[1]);
close(c2Toc3[0]);
close(c2Toc3[1]);
execlp("grep","grep","root",NULL);
perror("CHILD 2: execlp");
exit(EXIT_FAILURE);
}
rValue = fork();
if (rValue == -1)
{
perror("Child_3");
exit(EXIT_FAILURE);
}
else if (rValue == 0)
{
printf("CHILD 3: PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);
dup2(c2Toc3[0], STDIN_FILENO);
close(c1Toc2[0]);
close(c1Toc2[1]);
close(c2Toc3[0]);
close(c2Toc3[1]);
execlp("sort","sort","-n", "-k4",NULL);
perror("CHILD 3: execlp");
exit(EXIT_FAILURE);
}
close(c1Toc2[0]);
close(c1Toc2[1]);
close(c2Toc3[0]);
close(c2Toc3[1]);
printf("PARENT: PROCESS Waiting on children to complete\n");
sleep(3);
printf("PARENT: Final Print Statement before exit\n");
return 0;
}
Your code looks more or less right, but it does seem to reflect an imperfect understanding of fork / exec and child process management.
For one thing, note that the exec-family functions, including execlp(), do not return except on failure. Your code seems to assume otherwise. In particular, the child processes will not print "goodbye" messages after calling execlp() unless the execlp() call fails. You should handle the (failure) case in which execlp() does return, but normally you would do so with error-handling / error-reporting code.
Also, each process, including the parent, should close those file descriptors it isn't going to use. That includes closing a FD after duplicating it onto one of the standard file numbers, and closing all file descriptors intended exclusively for other processes. You miss several of those:
Child 1 fails to close file descriptors c1Toc2[1] (after duplicating it) and c2Toc3[1].
Child 2 fails to close file descriptors c1Toc2[0] and c2Toc3[1] (after duplicating them).
Furthermore, it is pointless for the parent process to sleep() to wait on its children. If it wanted to ensure that they completed and/or to obtain their exit statuses, then it should use wait() or waitpid(). If it were not going to exit immediately after, then it should definitely use one of those functions, else the child processes will hang around as zombie processes until the parent exits. No amount of sleep() is sufficient to ensure that the child processes finish. If you don't care about any of those things, on the other hand, then you can just let the parent exit. There's no special advantage in that case to keeping it around.
I don't know whether any of those explains the unexpected behavior you see, because you haven't explained what that is.

Why are my child background process (fork-execvp) die instatly, but work well while in the foreground?

I'm doing a homework assigment (the regular "write your own unix shell in c" assigment)
and cant make my child process run in the background properly, the are KILLED right before calling execvp
my intuition tells me the problem is in the signal handler or the usage of return in the parent process after fork().
This is how I've implemented it (just for the background process) :
void ExeExternal(char *args[MAX], char* cmd,ExecutionMode ExeMode) {
int pID;
switch(pID = fork())
{
case -1:
// Add your code here (error)
/*
your code
*/
perror("fail to fork in : ExeExternal(...)\n");
exit(-1);
case 0 :
// Child Process
signal(SIGTSTP, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGCONT, SIG_DFL);
usleep(20000);
setpgrp();
printf("trying to execvp\n");
int run_result=execvp(args[0],args);
if(run_result==-1)
{
perror("execvp(...) result in execvp\n");
exit(-1);
}
break; //wont reach this part ever!
default://the parent. pID holds child's pID
setpgid(pID, pID); //note, this is also done in the child
if(ExeMode==BACKGROUND) //no need to WAIT()
{
return;
}
}
}
and this is my signal handler (registered in my main() with signal(SIGCHLD,handle_sigchld)
void handle_sigchld(int sig) {
pid_t pid;
int status;
pid=waitpid(WAIT_ANY,&status,WUNTRACED | WNOHANG);
if (pid >0)
{
if(WIFEXITED(status)) //if terminated normally, return or exit
{
printf("\n[%d] %d Done \n", ID, pid); //‪[1‬] ‫‪a.out‬‬ ‫‪:‬‬ ‫‪12340‬‬ ‫‪214‬‬ ‫‪secs‬‬
}
else if (WIFSIGNALED(status)) //killed with SIGINT
{
printf("handle_sigchld:[%d] pid %d KILLED\n",ID,pid);
}
else if (WIFSTOPPED(status)) //suspended with SIGCONT
{
printf("\n[%d] %s %d %d secs (stopped)\n", ID, value,pid,time);
}
}
}
I've tried to plant some prinft's and my child seems to be killed right before executing execvp(...)
Ive tried to print the args[0] and args[1] and it exited there, so it looks like it falls upon accessing them,
also - is that the right way to use return ? ive tried to replace it with waitpid(pid,status,WNOHANG) but it didnt helped
ANY help is greatly appreciated! even just a hint in the right direction

C pipe() and fork()

I have a problem with a simple program im making with fork and pipes for learning purpose. I want a child that send the ppid to the parent to output the value of ppid and do this twice. However,the result is two ppid output are the same.Why?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd[2]; /* for the pipe */
int n,pid,ppid,val;
int p[5],q[5];
if (pipe(fd) < 0) {
printf("Pipe creation error\n");
exit(1);
}
for(val=0;val<2;val++){
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) { /* child */
ppid = getpid();
printf("child %d pid:%d \n",val+1,ppid);
write(fd[1], &ppid, sizeof(ppid));
sleep(1);
close(fd[1]);
} else { /* parent */
//printf("Parent: pid: ");
close(fd[1]);
printf("%d \n",val+1);
sleep(1);
n = read(fd[0], &ppid ,sizeof(ppid));
printf("%d \n",ppid);
// fflush(stdout);
close(fd[0]);
wait(NULL);
// printf("<parent> I have completed!\n");
exit(0);
}
}
}
There may be potential problem in the program design. Since the parent waits for the child
in the first iteration, the child executes the for loop for val=1 and spawns another process
through fork. Eventually there are three process of which two of them will have the same pid
as one of them is executing the for twice.

Resources