fork,exec and wait and wait and wait and wait

fork,exec and wait and wait and wait and wait

Post by R. Compto » Fri, 03 Jul 1998 04:00:00



Hello,

Can somebody out there please de-mystify this for me?  I have a project (for
school) that involves spawning child processes.  It's a simple shell emulation
that accepts pipe and io redirection.  I've gotten it to work but the only
problem is that it's not the way the professor wants it to work.  He wants a
loop that forks and execs all commands that were parsed from the command line
THEN another loop that waits for each child process and closes everything up.

What I have working is ONE loop that forks, execs, waits, closes then starts
over.  Works seamlessly.  

I have been banging my head against a wall for days now trying to make it work
his way -- I'm beginning to wonder if it's even possible. I've e-mailed the prof
several times (with code)  every reply has failed to address the problem.  I
don't know if he is purposely sending me on wild-goose chases or if he's just
addle-minded.  I'm really getting tired of this -- I just failed a midterm in
another class due, in large part, to spending such an inordinate amount of time
on this project.

If someone out there could point me in the right direction, I would be ever so
grateful.

Here's the code that works:

struct command_rec {
        int fd[2] ;
        char** argvptr;

Quote:};

struct command_rec  commands[50];

...

/* code that gets input, parses command line, fills up
   commands[] and puts all the plumbing in place.  The
   fd array in the struct contains the file descriptors
   of any redirections that were requested.  If a particular
   command is supposed to read from stdin or write to stdout
   then the corresponding element in fd is -1.
*/
...

for (cnt = 0; cnt <= pipe_cnt; cnt++){  

        pid = fork();

        if (pid == 0){   /*  Child Process returning  */

                if ( commands[cnt].fd[OUT] != -1){
                        dup2(commands[cnt].fd[OUT], 1);
                        close(commands[cnt].fd[OUT]);
                }

                if ( commands[cnt].fd[IN] != -1){
                        dup2(commands[cnt].fd[IN], 0);
                        close(commands[cnt].fd[IN]);
                }

                execvp(commands[cnt].argvptr[0], commands[cnt].argvptr);
                perror("execvp");
                exit(1);
        }

        /* parent */
        close(commands[cnt].fd[IN]);  
        close(commands[cnt].fd[OUT]);
        wait(&status);
        /* NOTE: it doesn't seem to matter if the wait()
           comes before the close()'s -- it works either way */

Quote:}                      

Here's the code that goes down in flames:

/* spawn all processes at once THEN wait for each to complete */

for (cnt = 0; cnt <= pipe_cnt; cnt++){  

        pid = fork();

        if (pid == 0){   /*  Child Process returning  */

                if ( commands[cnt].fd[OUT] != -1){
                        dup2(commands[cnt].fd[OUT], 1)
                        close(commands[cnt].fd[OUT]);
                }

                if ( commands[cnt].fd[IN] != -1){
                        dup2(commands[cnt].fd[IN], 0)
                        close(commands[cnt].fd[IN]);
                }

                execvp(commands[cnt].argvptr[0], commands[cnt].argvptr);
                perror("execvp");
                exit(1);
        }

Quote:}            

/* parent */
for (cnt = 0; cnt <= pipe_cnt; cnt++){

        close(commands[cnt].fd[IN]);
        close(commands[cnt].fd[OUT]);
        wait(&status);

Quote:}

I've tried the above block in a multitude of ways:  wait before close, close()'s
in one loop, wait() in another loop etc.  Nothing works.  

My usual test is to give it ls | sort.  Sort just hangs, like it's expecting
more (an eof perhaps?) from ls.  I don't know what more to do.  There's
obviously some subtlety I'm missing.  It seems like those close() statments need
to be more closely tied to the child that is being waited for, but I don't know
how to accomplish this.

Any opinions very appreciated.

Thanks,

Rob

 
 
 

fork,exec and wait and wait and wait and wait

Post by Kenneth C Stah » Fri, 03 Jul 1998 04:00:00


I don't have time this evening to give a comprehensive answer, but the first thing
you should do is forget that you ever heard of the call to wait(). Use either
waitid() or waitpid(). With the latter you can pass a flag to not hang if the child
is still active.

What I do when I have multiple children is build an array of child pids (actually
what I use is a list of classes in which I store other information as well) and
whenever you spawn a new child add the pid to the array. When a sigchld() is
detected, sweep through the entire array using a waitpid() call and set a status
variable to show that it is complete (this is where the class comes in - you can
store several things like the exit status, etc). Keep your SIGCHLD signal handler
purely reentrant. When you return to your main loop, sweep through the array again
and report on the success/fail status of the child and then go about the rest of the
work of the loop. When you have no more children to spawn, just keep checking the
children until they are all complete and then exit.

Of course, the devil is in the details. There is a lot of signal handling work here
and planning for the array may take some thought, but I've laid out pretty basic
idea of how a daemon might work (because that is where I learned how to do it).
Ken


> Hello,

> Can somebody out there please de-mystify this for me?  I have a project (for
> school) that involves spawning child processes.  It's a simple shell emulation
> that accepts pipe and io redirection.  I've gotten it to work but the only
> problem is that it's not the way the professor wants it to work.  He wants a
> loop that forks and execs all commands that were parsed from the command line
> THEN another loop that waits for each child process and closes everything up.

> What I have working is ONE loop that forks, execs, waits, closes then starts
> over.  Works seamlessly.

> I have been banging my head against a wall for days now trying to make it work
> his way -- I'm beginning to wonder if it's even possible. I've e-mailed the prof
> several times (with code)  every reply has failed to address the problem.  I
> don't know if he is purposely sending me on wild-goose chases or if he's just
> addle-minded.  I'm really getting tired of this -- I just failed a midterm in
> another class due, in large part, to spending such an inordinate amount of time
> on this project.

> If someone out there could point me in the right direction, I would be ever so
> grateful.

> Here's the code that works:

> struct command_rec {
>         int fd[2] ;
>         char** argvptr;
> };

> struct command_rec  commands[50];

> ...

> /* code that gets input, parses command line, fills up
>    commands[] and puts all the plumbing in place.  The
>    fd array in the struct contains the file descriptors
>    of any redirections that were requested.  If a particular
>    command is supposed to read from stdin or write to stdout
>    then the corresponding element in fd is -1.
> */
> ...

> for (cnt = 0; cnt <= pipe_cnt; cnt++){

>         pid = fork();

>         if (pid == 0){   /*  Child Process returning  */

>                 if ( commands[cnt].fd[OUT] != -1){
>                         dup2(commands[cnt].fd[OUT], 1);
>                         close(commands[cnt].fd[OUT]);
>                 }

>                 if ( commands[cnt].fd[IN] != -1){
>                         dup2(commands[cnt].fd[IN], 0);
>                         close(commands[cnt].fd[IN]);
>                 }

>                 execvp(commands[cnt].argvptr[0], commands[cnt].argvptr);
>                 perror("execvp");
>                 exit(1);
>         }

>         /* parent */
>         close(commands[cnt].fd[IN]);
>         close(commands[cnt].fd[OUT]);
>         wait(&status);
>         /* NOTE: it doesn't seem to matter if the wait()
>            comes before the close()'s -- it works either way */
> }

> Here's the code that goes down in flames:

> /* spawn all processes at once THEN wait for each to complete */

> for (cnt = 0; cnt <= pipe_cnt; cnt++){

>         pid = fork();

>         if (pid == 0){   /*  Child Process returning  */

>                 if ( commands[cnt].fd[OUT] != -1){
>                         dup2(commands[cnt].fd[OUT], 1)
>                         close(commands[cnt].fd[OUT]);
>                 }

>                 if ( commands[cnt].fd[IN] != -1){
>                         dup2(commands[cnt].fd[IN], 0)
>                         close(commands[cnt].fd[IN]);
>                 }

>                 execvp(commands[cnt].argvptr[0], commands[cnt].argvptr);
>                 perror("execvp");
>                 exit(1);
>         }
> }

> /* parent */
> for (cnt = 0; cnt <= pipe_cnt; cnt++){

>         close(commands[cnt].fd[IN]);
>         close(commands[cnt].fd[OUT]);
>         wait(&status);
> }

> I've tried the above block in a multitude of ways:  wait before close, close()'s
> in one loop, wait() in another loop etc.  Nothing works.

> My usual test is to give it ls | sort.  Sort just hangs, like it's expecting
> more (an eof perhaps?) from ls.  I don't know what more to do.  There's
> obviously some subtlety I'm missing.  It seems like those close() statments need
> to be more closely tied to the child that is being waited for, but I don't know
> how to accomplish this.

> Any opinions very appreciated.

> Thanks,

> Rob

  vcard.vcf
< 1K Download

 
 
 

fork,exec and wait and wait and wait and wait

Post by Steve Rountre » Sun, 05 Jul 1998 04:00:00


  Simply increment a counter of the number of child processes that have been
forked/execed.  Set up a signal handler to catch SIGCLD.  Upon the receipt of
each SIGCLD you decrement the counter and issue a wait call.  When your counter
reaches zero then you are done.  

  Steve


> Can somebody out there please de-mystify this for me?  I have a project (for
> school) that involves spawning child processes.  It's a simple shell emulation
> that accepts pipe and io redirection.  I've gotten it to work but the only
> problem is that it's not the way the professor wants it to work.  He wants a
> loop that forks and execs all commands that were parsed from the command line
> THEN another loop that waits for each child process and closes everything up.

 
 
 

fork,exec and wait and wait and wait and wait

Post by Marcelo Meir » Tue, 07 Jul 1998 04:00:00


A word of advise:

 You *MUST* check if the fork() was sucessfull (it returns -1 when it
fails). If your fork() fails, than the wait() will hang, and probably so
will your pipe. Check if your pid == -1 and if so, perror().

 Usually in academic systems the sysadm put some heavy restrictions in
user's max number of processes, CPU usage, IPC machanisms, etc. When I
took my OS course, my whole class almost got C's because of the machine
limits. The T.A. had no clue of the problem, as usual. The perror() in
my program saved the semester.

  wait() should work fine. Using waitpid() might give you some more
control over what's going on, and therefore can be quite useful w/
debugging. Checking return codes and using a combination of waitpid()
and printf() will enlighten will quite a bit. Once again, wait() will do
the job, and you won't have to worry about SIGCHLD etc, because that's
what wait*() does.

  Beware you have no guarantees of what's the order that the child
processes will be executed and terminated. The piping might force some
order, but I'd keep an eye open for that.


> Here's the code that goes down in flames:

> /* spawn all processes at once THEN wait for each to complete */

> for (cnt = 0; cnt <= pipe_cnt; cnt++){

>         pid = fork();

>         if (pid == 0){   /*  Child Process returning  */

>                 if ( commands[cnt].fd[OUT] != -1){
>                         dup2(commands[cnt].fd[OUT], 1)
>                         close(commands[cnt].fd[OUT]);
>                 }
>                 if ( commands[cnt].fd[IN] != -1){
>                         dup2(commands[cnt].fd[IN], 0)
>                         close(commands[cnt].fd[IN]);
>                 }
>                 execvp(commands[cnt].argvptr[0], commands[cnt].argvptr);
>                 perror("execvp");
>                 exit(1);
>         }
> }

> /* parent */
> for (cnt = 0; cnt <= pipe_cnt; cnt++){

>         close(commands[cnt].fd[IN]);
>         close(commands[cnt].fd[OUT]);
>         wait(&status);
> }

----------------
Marcelo L. Meira, Programmer

e-mail: marcelo.meira at waii dot com
Western Geophysical - (713) 689-2679

"UNIX _IS_ user friendly; it's just picky about who its friends are."

 
 
 

1. Telnet wait & wait & wait &....

Ok, when I telnet to my Linux box from my Wintendo 95 machine, it claims

it connects, but then waits for about 3 or 4 minutes.  The tcpd.conf man

page claims that this is because of RFC 931 lookups, which are
compile-time arguements.

The question is, is there any easy way to disable this, and if I have to

recompile, exactly what needs to be recompiled (tcpd, I assume).

    -Al Roeder

2. Is Solaris 10 a joke or crap?

3. Matrox Mystique ands X.

4. pkgadd changed behaviour with respect to symlinked items

5. Talk waits and waits for invitation (2nd)

6. Writing to HPFS

7. ?? Modem sends ~15 chars, wait 30s, 15 chars, wait 30s...??

8. Problems in a RH6.0 with SBPCI128

9. wait or not to wait, that is my question

10. --wait and --random-wait ?

11. I Can't Wait; I Can't Wait!

12. wait. wait pid

13. Talk waits and waits for invitation