我刚刚完成了我的 shell 解释器,但我认为我的管道实现是错误的。
它正在工作,像ls | cat -e
工作这样的基本东西,但segmentation fault
如果文件描述符超过 60 ko,我害怕可能性。当我做一个超过 60 ko 的文件的 cat 时,我也发现了一个无限循环。例如,如果 do a cat 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);
}
Run Code Online (Sandbox Code Playgroud)
shell 管道的部分想法是所涉及的进程并发运行(或可能会运行)。您提供的代码通过wait()
在启动下一个子进程之前对每个子进程进行 ing 来主动防止这种情况发生。除其他事项外,这会冒着在准备好耗尽它之前填充(操作系统级)管道缓冲区的风险。这将陷入僵局,或者,如果幸运的话,会产生错误。
在较高级别,该过程应如下所示:
C
最初是管道第一段的命令,并设置fd0
为STDIN_FILENO
pipe()
,并设置fd1
为该管道的写端;fd1
为STDOUT_FILENO
fork()
在其中运行 command 的子项C
。在里面:
fd0
与STDIN_FILENO
then不同dup2()
fd0
on STDIN_FILENO
and closefd0
fd1
与STDOUT_FILENO
then不同dup2()
fd1
on STDOUT_FILENO
and closefd1
C
fd0
不同于STDIN_FILENO
则关闭fd0
fd1
不同于STDOUT_FILENO
则关闭fd1
C
为下一个命令fd0
为上面步骤(2)中管道的读取端wait()
或waitpid()
所有子进程请注意,对于包含任意正数命令(包括 1)的管道,这同样适用。