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];Quote:};
...
/* 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:Quote:}
/* 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 */Quote:}
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()'sQuote:}
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