Thread: Help with forking processes

  1. #1
    Registered User
    Join Date
    Sep 2011
    Posts
    4

    Question Help with forking processes

    I am writing a program that emulates a shell. I am supposed to be able to background processes or run them in the foreground. I looked up some examples like this, however my program is freezing up when my parent process is (supposedly) waiting for the child. It always gets to the line
    Code:
    if(waitpid(pid, &status, 0) != pid)
    and just hangs there. I end up having to kill the program with CTRL + C. As a side note, can anybody explain to me how to background a process and how to wait for all of my child processes to be finished before the program exits on command?


    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include "parse.h"
    
    int main(void){
        int repeat = 1;
        char args[MAX_ARGS][CMD_LEN];
    
        while(repeat){
            fprintf(stdout, ":~$ ");
            
            Param_t *params = new_paramt();
            if(params == NULL){
                fprintf(stdout, "Memory allocation failed");
                exit(1);
            }
    
            init_args(args);
            char command[CMD_LEN];
            fgets(command, CMD_LEN, stdin);        
            format_args(command, params, args);
    
            if(!strcmp(params->program, EXIT)){
                repeat = 0;
            }
            else{
                pid_t pid;
                int status;
    
                pid = fork();
                if(pid == 0){
                    if(params->outputRedirect){
                        FILE *fout = freopen(params->outputRedirect, "w", stdout);
                        if(!(fout)){
                            fprintf(stdout, "Error! Output redirection failed.");
                        }
                    }
                    if(params->inputRedirect){
                        FILE *fin = freopen(params->outputRedirect, "r", stdin);
                        if(!(fin)){
                            fprintf(stdout, "Error! Input redirection failed.");
                        }
                    }
                    execvp(params->program, params->argumentVector);
                }
                else if(pid < 0){
                    fprintf(stdout, "Error! Process fork failed.");
                    status = -1;
                }
                else{
                    if(waitpid(pid, &status, 0) != pid){
                        status = -1;
                    }
                    return status;
                }
            }
            free_param_t(params);
        }
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    If waitpid() is appearing to hang, that means the child has not exited. To have a process run in the background, but still be able to reap children, look at the WNOHANG flag for waitpid().

    To wait for all children, you can just call wait() in a loop; or if you want to wait for specific children that you've forked (instead of any children), call waitpid() with the childrens' pids, in a loop.

  3. #3
    Registered User
    Join Date
    Sep 2011
    Posts
    4
    Quote Originally Posted by cas View Post
    If waitpid() is appearing to hang, that means the child has not exited. To have a process run in the background, but still be able to reap children, look at the WNOHANG flag for waitpid().
    I added the WNOHANG option earlier and when I step through the program in gdb the child process is never executed. The parent always comes up first, and in the case where WNOHANG is a parameter of waitpid(), status is returned inside of the parent process, and then the whole program finishes executing.


    Quote Originally Posted by cas View Post
    To wait for all children, you can just call wait() in a loop; or if you want to wait for specific children that you've forked (instead of any children), call waitpid() with the childrens' pids, in a loop
    If I call wait in a loop do I just call it until it returns an error?
    Code:
    while(wait(&status) != -1)

  4. #4
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Quote Originally Posted by Lubert View Post
    I added the WNOHANG option earlier and when I step through the program in gdb the child process is never executed. The parent always comes up first, and in the case where WNOHANG is a parameter of waitpid(), status is returned inside of the parent process, and then the whole program finishes executing.
    Are you sure gdb can follow children? And when you use WNOHANG, are you sure that it's actually reaping the child? That is, are you checking waitpid()'s return value?

    If fork() is not returning -1, then it's essentially impossible for a child process not to have been created.
    Quote Originally Posted by Lubert View Post
    If I call wait in a loop do I just call it until it returns an error?
    Code:
    while(wait(&status) != -1)
    Yes, more or less. You'll probably want to check errno and make sure that the -1 return value is because of ECHILD (no children available).

  5. #5
    Registered User
    Join Date
    Sep 2011
    Posts
    4
    Quote Originally Posted by cas View Post
    Are you sure gdb can follow children? And when you use WNOHANG, are you sure that it's actually reaping the child? That is, are you checking waitpid()'s return value?
    I didn't think that gdb might not be able to follow the child process...I guess I need to find a different way to debug.

    As for the reaping and checking of waitpid()'s return value, I am not sure...I am slightly confused now about what is happening and what needs to be done.

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    If you call waitpid() on a process, and set WNOHANG, waitpid() will return immediately if the process is not dead yet. Of course, it will return immediately if the process is dead, so how do you tell the difference? You check the return value. waitpid() returns 0 if the requested child is not dead. It returns the pid of the child that it successfully reaped, or -1 if there was some error.

    The point is, you can periodically call waitpid() with WNOHANG to see if children have died (say, every time the user enters some input); if no children are ready to be reaped, you won't cause the process to hang, but if children are ready, you'll be able to reap them so you avoid zombies.

  7. #7
    Registered User
    Join Date
    Sep 2011
    Posts
    4
    Alrighty. All of that makes sense. However, my still very big problem is that shell programs are never being run with execvp() in the child process. All of my arguments for execvp() look good when I am in gdb, but I don't get any output when I run "ls -al" or anything.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Forking child processes form parent to exec commands
    By Imanuel in forum C Programming
    Replies: 3
    Last Post: 08-02-2010, 09:03 AM
  2. Problem forking child processes
    By md5fungi in forum C++ Programming
    Replies: 0
    Last Post: 10-25-2009, 01:16 PM
  3. forking
    By Cmaniac in forum C Programming
    Replies: 6
    Last Post: 04-14-2007, 03:54 AM
  4. forking processes
    By osal in forum C++ Programming
    Replies: 3
    Last Post: 03-22-2005, 01:44 AM
  5. forking
    By saphiroth in forum C Programming
    Replies: 3
    Last Post: 01-28-2005, 03:42 PM

Tags for this Thread