Reputation: 1352
I just finished my shell interpretor but I think my pipe implementation is wrong.
It's working, basic things like ls | cat -e
works but I am afraid of segmentation fault
possibilities if the file descriptor is over 60 ko.
I found also a infinite loop when I do a cat of a file which is longer than 60 ko. For exemple if a do a cat foo | cat -e
where foo is a long file, infinite loop happen.
Or other exemple when I do cat /dev/urandom | cat -e
it don't show me any display so it execute first cat /dev/urandom
and then cat -e
.
This is my code :
int son(int *fd_in, int p[2], t_list *cmd, char **env)
{
(void)env;
dup2(*fd_in, 0);
if (cmd->act != ENDACT && cmd->act != LEFT && cmd->act != DLEFT)
dup2(p[1], 1);
close(p[0]);
execve(cmd->av[0], cmd->av, NULL);
return (-1);
}
t_list *execute_pipe(t_list *cmd, int *fd_in)
{
int p[2];
pid_t pid;
*fd_in = 0;
while (cmd->act != -1)
{
pipe(p);
if ((pid = fork()) == -1)
return (NULL);
else if (pid == 0)
son(fd_in, p, cmd, NULL);
else
{
wait(NULL);
close(p[1]);
*fd_in = p[0];
if (cmd->act != PIPE)
return (cmd);
cmd = cmd->next;
}
}
return (cmd);
}
Upvotes: 3
Views: 3151
Reputation: 181724
Part of the idea of a shell pipeline is that the processes involved run concurrently (or may do). The code you presented actively prevents that from happening by wait()
ing on each child process before launching the next one. Among other things, that runs the risk of filling the (OS-level) pipe's buffer before there's anything ready to drain it. That will deadlock or, if you're lucky, generate an error.
At a high level, the procedure should look like this:
C
initially be the command for the first segment of the pipe, and set fd0
to be STDIN_FILENO
pipe()
, and set fd1
to be the write end of that pipe;fd1
to be STDOUT_FILENO
fork()
a child in which to run command C
. In it:
fd0
is different from STDIN_FILENO
then dup2()
fd0
onto STDIN_FILENO
and close fd0
fd1
is different from STDOUT_FILENO
then dup2()
fd1
onto STDOUT_FILENO
and close fd1
C
fd0
is different from STDIN_FILENO
then close fd0
fd1
is different from STDOUT_FILENO
then close fd1
C
to be the next commandfd0
to be the read end of the pipe from step (2), abovewait()
or waitpid()
for all the child processesNote that that works equally well for a pipeline containing any positive number of commands, including 1.
Upvotes: 5