Using waitpid to run process in background?
Asked Answered
M

2

10

I am trying to mimic the bash feature of running process in the background if "&" is found at the end of the command. I have the following function...and I don't think it's doing what I want it to do

int execute(char* args[],int background,int *cstatus){
    pid_t   child;
    pid_t   ch;                         /*Pid of child returned by wait*/
    if ((child = fork()) == 0){                 /*Child Process*/
        execvp(args[0],args);       
        fprintf(stderr, "RSI: %s: command not found\n",args[0]); /*If execvp failes*/
        exit(1);

    }else{          /*Parent process*/
        if (child== (pid_t)(-1)) {
            fprintf(stderr,"Fork failed\n"); exit(1);
        }else{
            if (background==0){             /*If not running in background..wait for process to finish*/
                ch = wait(cstatus);
            }else{
                printf("%ld Started\n",(long)getpid());
        /*  printf("Parent: Child %ld exited with status = %ld\n", (long) ch, (long)cstatus);
    */  }}
    }
return 0;
}
int wait_and_poll(int *cstatus){
    pid_t status;
    status = waitpid(-1,cstatus,WNOHANG);
    if (status>0){
        fprintf(stdout,"%ld Terminated.\n",(long) status);
    }
return 0;
}

If i just run "ls -l " it works as expected..but if I want to run ls in the background..and have the program keep accepting new commands I call the function with background flag set as 1 and I want it to run the process in the background, tell me that it has created the process..and then prompt to accept next command.

Muricate answered 27/1, 2013 at 14:29 Comment(0)
F
7

I don't think waitpid(-1, &cstatus, WNOHANG); does what you think it does. You need to check its return value. If it is > 0, that's the PID of the child process that has exited. If it's 0 or -1, no child process has changed state.

You can just call waitpid(-1, &cstatus, WNOHANG); before and/or after each command you run. Call it in a loop to catch more than one child exit.

You can also handle SIGCHILD. Your process will receive this signal immediately after a child exit, which is good if you want to report child process termination immediately, without waiting for user's input.

Figured answered 27/1, 2013 at 14:50 Comment(5)
If i have more than 1 background process running, do I Need to store their pid's and loop through them with waitpid ?Muricate
Absolutely not. Call waitpid(-1, &cstatus, WNOHANG). This will give all the information you need.Figured
I updated the code, now I call the wait_and_poll method before and after the execute method. However the status is never > 0 it's always -1 or 0 for me? even after I close the program I started in the background..or use Kill on it.Muricate
I'm not sure why this could happen. If waitpid returns -1, what is the value of errno? Are you sure there are no calls to wait and friends elsewhere?Figured
I have a little example program that works with waitpid exactly as it should, see pastebin.Figured
U
3

That is simple. Consider you have a process P with id pid.

If you want it to run in the background(which can be recognized by & at the end of your input string to the shell/program ), you should do this

//some code
id=fork();
if(id==0)
{
//child does work here
}
else
{
//Parent does work here
if(!strcmp(last string,"&")==0)waitpid(id,&status,0);
}

Thus the parent does not wait if you request for background execution, else it waits.

Uraninite answered 27/1, 2013 at 15:10 Comment(2)
But, jobs functionality doesn't work for this solution.Intrauterine
But this creates zombie child process which might be a problemCoricoriaceous

© 2022 - 2024 — McMap. All rights reserved.