我刚刚完成了我的shell解释器,但我认为我的管道实现是错误的。
它正在工作,基本的东西如ls | cat -e
有效,但如果文件描述符超过60 ko,我害怕segmentation fault
种可能性。
当我做一个长度超过60 ko的文件时,我发现了一个无限循环。例如,如果做一只猫foo | cat -e
,其中foo是一个长文件,则会发生无限循环。
或其他例子我cat /dev/urandom | cat -e
它不会向我显示任何显示,因此它首先执行cat /dev/urandom
然后cat -e
。
这是我的代码:
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);
}
答案 0 :(得分:4)
shell管道的部分想法是所涉及的进程同时运行(或可能运行)。您提供的代码会在启动下一个子进程之前通过wait()
每个子进程来阻止这种情况发生。除此之外,它还存在填充(操作系统级别)管道缓冲区的风险,因为它已准备好排空它。那将会陷入僵局,或者,如果你很幸运,会产生错误。
在高级别,程序应如下所示:
C
最初成为管道第一段的命令,并将fd0
设置为STDIN_FILENO
pipe()
,并将fd1
设置为该管道的写入结尾; fd1
设为STDOUT_FILENO
fork()
要运行命令C
的子项。在里面:
fd0
与STDIN_FILENO
不同,dup2()
fd0
与STDIN_FILENO
不同,则关闭fd0
} fd1
与STDOUT_FILENO
不同,dup2()
fd1
与STDOUT_FILENO
不同,则关闭fd1
} C
fd0
与STDIN_FILENO
不同,则关闭fd0
fd1
与STDOUT_FILENO
不同,则关闭fd1
C
设为下一个命令fd0
设置为上面wait()
或waitpid()
请注意,对于包含任意正数命令的管道(包括1),它同样适用。