GIDForums  

Go Back   GIDForums > Computer Programming Forums > C Programming Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 20-Sep-2006, 10:22
groberts1980 groberts1980 is offline
New Member
 
Join Date: Sep 2006
Posts: 2
groberts1980 is on a distinguished road

wait() and waitpid() functions


This is my first post here, so hello everybody. I have a question about a C program I'm writing for an Operating Systems class. I basically need to write a little shell that will take commands (ls, ls -l, ./program.c, cat prog.c >text.txt, etc).

After fork() is called, I have an if and else to determine whether the parent or child is running. In the parent branch, I need it to wait for the child to finish if the user did not specify the & (background) argument.

I'm having trouble figuring out the wait() and waitpid() functions. Here is the a snippet of the code in question:

CPP / C++ / C Code:
cpid = fork();

if(cpid) { //parent
     if(param.Background == 0) {
          //use wait function here
     }
}
else {  //child
     execvp(param.FirstArg, param.ArgVector);
     return(0);
}

When I run the program, the parent does not wait for the child to complete. In the shell, I'm running a program called slow.c, that prints out the process id of itself 10 times, in one second intervals. Hence the name "slow." When it runs, the prompt for the parent comes right back up, when it should wait for slow to finish before coming back.

Any help on this would be most humbly appreciated.
Last edited by LuciWiz : 20-Sep-2006 at 15:15. Reason: Please insert your C/C++ code between [cpp] & [/cpp] tags
  #2  
Old 20-Sep-2006, 16:37
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,893
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: wait() and waitpid() functions


Quote:
Originally Posted by groberts1980
In the parent branch, I need it to wait for the child to finish

functions in the family execvp(), execl(), execv(), etc., never return unless there was an error. When you invoke execvp() it replaces the current process image with a new process, whose path is given in the first argument. But, and I hate to repeat myself, it never returns. See footnote.

For starters, you could consider:
CPP / C++ / C Code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    int i;
    pid_t cpid;
    pid_t child_pid;
    cpid = fork();

    switch (cpid) {
        case -1: printf("Fork failed; cpid == -1\n");
                 break;

        case 0: child_pid = getpid();
                for (i = 0; i < 10; i++) {
                    printf("%d: this is the child, pid = %d\n", i, child_pid);
                    sleep(1);
                }
                exit(0);

        default: printf("This is the parent: waiting for %d to finish\n", cpid);
                 waitpid(cpid, NULL, 0);
                 printf("Ttttthat's all, folks\n");
    }
    return 0;
}

Output:
Code:
0: this is the child, pid = 3562 This is the parent: waiting for 3562 to finish 1: this is the child, pid = 3562 2: this is the child, pid = 3562 3: this is the child, pid = 3562 4: this is the child, pid = 3562 5: this is the child, pid = 3562 6: this is the child, pid = 3562 7: this is the child, pid = 3562 8: this is the child, pid = 3562 9: this is the child, pid = 3562 Ttttthat's all, folks

I'm not sure exactly what you need, but if you want to put see the "sleep" stuff in a process invoked by the child:

CPP / C++ / C Code:
/* 
 * file slow.c 
 */

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t pid;
    int i;

    pid = getpid();
    for (i = 0; i < 10; i++) {
        printf("%d: This is slow --- pid = %d\n", i, pid);
        sleep(1);
    }
    return 0;
}

You could, maybe, do something like:

CPP / C++ / C Code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    int i;
    pid_t cpid;
    pid_t child_pid;
    cpid = fork();

    switch (cpid) {
        case -1: printf("Fork failed; cpid == -1\n");
                 break;

        case 0:  child_pid = getpid();
                 printf("This is the child: pid = %d\n", child_pid);
                 system("./slow");
                 exit(0);

        default: printf("This is the parent: waiting for %d to finish\n", cpid);
                 waitpid(cpid, NULL, 0);
                 printf("Ttttthat's all, folks\n");
    }
    return 0;
}

Output:
Code:
This is the child: pid = 3838 This is the parent: waiting for 3838 to finish 0: This is slow --- pid = 3839 1: This is slow --- pid = 3839 2: This is slow --- pid = 3839 3: This is slow --- pid = 3839 4: This is slow --- pid = 3839 5: This is slow --- pid = 3839 6: This is slow --- pid = 3839 7: This is slow --- pid = 3839 8: This is slow --- pid = 3839 9: This is slow --- pid = 3839 Ttttthat's all, folks

Results are from Linux Fedora Core 5.

Regards,

Dave

Footnote:

"Well, did he ever return?
No, he never returned and his fate is still unknown. "
Charlie on the MTA
---Jacqueline Steiner and Bess Lomax
Sung by the Kingston Trio, 1959

"Was it really 1959??? Sometimes it seems like yesterday. Where does the time go?"
---davekw7x
  #3  
Old 20-Sep-2006, 17:34
groberts1980 groberts1980 is offline
New Member
 
Join Date: Sep 2006
Posts: 2
groberts1980 is on a distinguished road

Re: wait() and waitpid() functions


So because it does not return from execvp, I do not need a return statement?

We have to use exec, cannot use system() calls.

I'm running it like this, and it still is not waiting. When the program first runs, it takes a line of input and passes it into a function, which fills up the param struct. If the input contains <text.txt, it assigns "param->Input = text.txt". If they put a & argument at the end of the line of input, it sets param->Background = 1.

If the parent runs, and does not have to wait for the child (& operator in child), it should go back and print the prompt, waiting for more input.

CPP / C++ / C Code:
cpid = fork();
			
switch (cpid)
{
     case -1: 
          printf("Fork failed; cpid == -1\n");
          break;

     case 0: //child
          if(param.Input != NULL) //redirect input 
          {
               fp = freopen(param.Input,"r",stdin);
          }
          if(param.Output != NULL) //redirect output 
          {
                fp = freopen(param.Output,"w",stdout);
          }
          execvp(param.FirstArg, param.ArgVector);
          break;

     default: //parent
          if(param.Background)
          {
               waitpid(cpid,NULL,0);
          }
          break;
}
  #4  
Old 20-Sep-2006, 18:57
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,893
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: wait() and waitpid() functions


Quote:
Originally Posted by groberts1980
So because it does not return from execvp, I do not need a return statement?
The only time it returns is if there is an error. Therefore, I would usually expect something like:

CPP / C++ / C Code:
        execvp(*args, args);
        perror(*args);
        exit(1);
Quote:
Originally Posted by groberts1980
We have to use exec, cannot use system() calls.
That was just an illustration, where I used system() instead of the execvp that you had indicated. Playing with simple stuff like this might give you a better feel for the whole forking process. (It does for me.)

Quote:
Originally Posted by groberts1980

When the program first runs, it takes a line of input and passes it into a function, which fills up the param struct.

That sounds OK for starters.

Quote:
Originally Posted by groberts1980

If the input contains <text.txt, it assigns "param->Input = text.txt". If they put a & argument at the end of the line of input, it sets param->Background = 1.

If the parent runs, and does not have to wait for the child (& operator in child), it should go back and print the prompt, waiting for more input.

But your problem was when it does have to wait, right?

I would think of it like this:

Code:
loop get line parse line into arguments execute the command end loop

I would think that the big loop would be in main(), and I would have a separate function for parsing, and another function to execute the command after the command line had been parsed into arguments.

If you are going to call execvp(), you need the args as an array of pointers to char. I assume that is in your struct, somehow. So the execute() function looks something like the main() from my previous example. Here's an execute() function whose arguments are already in the form you need to call execvp.
The child calls exevp() and for this one, the parent always waits for the child to finish. You can easily fix it for the background situation where you don't want to wait.
CPP / C++ / C Code:
/*
 * execute--spawn a child process and execute the program.
 */
int execute(char **args)
{
    pid_t cpid;

    cpid = fork();

    switch (cpid) {
        case -1: perror("fork");
                 break; /* maybe you want to return something indicating error */

        case 0: execvp(*args, args); /* this is the child */
                perror(*args);
                exit(1); /* major system error: fuggedaboudit */

        default: waitpid(cpid, NULL, 0); /* TODO: parent shouldn't wait if it's background */
                 
    }
    return 0; /* or whatever value your main() program would like to see */
}

Of course, you might have a parameter that determines whether to wait. (Or, better yet, your parameter might be your struct, and inside the execute() function it would figure out what the arguments to execvp are and whether to wait. There might be more error checking and reporting also.

I hope this helps.

Regards,

Dave
 
 

Recent GIDBlogToyota - 2008 November Promotion by Nihal

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 07:56.


vBulletin, Copyright © 2000 - 2009, Jelsoft Enterprises Ltd.