在C

时间:2015-05-12 12:24:36

标签: c linux unix

我刚刚完成了我的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);
}

1 个答案:

答案 0 :(得分:4)

shell管道的部分想法是所涉及的进程同时运行(或可能运行)。您提供的代码会在启动下一个子进程之前通过wait()每个子进程来阻止这种情况发生。除此之外,它还存在填充(操作系统级别)管道缓冲区的风险,因为它已准备好排空它。那将会陷入僵局,或者,如果你很幸运,会产生错误。

在高级别,程序应如下所示:

  1. [shell] C最初成为管道第一段的命令,并将fd0设置为STDIN_FILENO
  2. [shell] 准备输出文件描述符:
    1. 如果有任何后续命令,请创建pipe(),并将fd1设置为该管道的写入结尾;
    2. 否则,请将fd1设为STDOUT_FILENO
  3. [shell] fork()要运行命令C的子项。在里面:
    1. [儿童] 如果fd0STDIN_FILENO不同,dup2() fd0STDIN_FILENO不同,则关闭fd0 }
    2. [儿童] 如果fd1STDOUT_FILENO不同,dup2() fd1STDOUT_FILENO不同,则关闭fd1 }
    3. [儿童] 执行命令C
  4. [shell] 如果fd0STDIN_FILENO不同,则关闭fd0
  5. [shell] 如果fd1STDOUT_FILENO不同,则关闭fd1
  6. [shell] 如果管道中还有其他命令,那么
    1. C设为下一个命令
    2. fd0设置为上面
    3. 步骤(2)中管道的读取端
    4. 转到步骤2(准备输出文件描述符)
  7. [shell] (此时,管道中的所有流程都已启动。)所有子流程的wait()waitpid()
  8. 请注意,对于包含任意正数命令的管道(包括1),它同样适用。

相关问题