It is currently Tue, 17 May 2022 01:47:45 GMT



 
Author Message
 fork,exec and wait and wait and wait and wait

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



 Mon, 18 Dec 2000 03:00:00 GMT   
 fork,exec and wait and wait and wait and wait

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

  vcard.vcf
< 1K Download


 Mon, 18 Dec 2000 03:00:00 GMT   
 fork,exec and wait and wait and wait and wait

  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



 Wed, 20 Dec 2000 03:00:00 GMT   
 fork,exec and wait and wait and wait and wait

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.

----------------
Marcelo L. Meira, Programmer
spam bait: postmaster@localhost
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."



 Fri, 22 Dec 2000 03:00:00 GMT   
 
   [ 4 post ] 

Similar Threads

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

2. Talk waits and waits for invitation

3. wait. wait pid

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

5. fork(), exec() and wait() woes

6. *A fork/exec/wait question

7. Need help with fork/exec/wait

8. Basic theory: implemetation of fork, exec, wait ...


 
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software