【问题标题】:Process Forks Shell, Then Entire Program Is Stopped?Process Forks Shell,然后整个程序停止?
【发布时间】:2020-06-10 16:23:04
【问题描述】:

我有一个从管道(2)的手册页复制的程序,经过修改,子进程从 shell 分叉,父进程从标准输入读取,将命令发送到子 shell 以执行。这适用于第一个命令,但在运行该命令后,我收到一条消息,表明程序已停止并返回到顶级 shell。

为什么会发生这种情况,我该如何阻止它?

信号(7)说:

   SIGTTIN      P1990      Stop    Terminal input for background process

但它不应该是后台进程,为什么它会停止?

接下来是带有完整源代码的终端会话,gcc -Wall 的结果,并尝试运行程序。如您所见,我给出命令“日期”,然后我被送回 到调用外壳,然后子外壳执行“日期”并出现输出,然后出现“退出”。 “fg”让我回到 pipe_shell 程序,“uptime”被发送到 shell 并运行,然后我可以做一个“echo”,然后我被送回顶级 shell,“exit”再次出现。

sh-5.0$ cat pipe_shell.c
/* pipe_shell.c - learn about pipes
 *
 * Modified from the man page for pipe(2).
 */

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int   pipefd[2];
    pid_t cpid;

    if (argc != 1) {
        fprintf(stderr, "Usage: %s\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (cpid == 0) { // Child reads from pipe

        close(pipefd[1]);              // Close unused write end of pipe
        close(STDIN_FILENO);           // shut off standard input
        dup2(pipefd[0], STDIN_FILENO); // pipe output is standard input
        close(pipefd[0]);              // close pipe output

        execl("/bin/bash", "bash",
              "--norc",
              "-i",
              (char *) 0);

        perror("exec");

    } else { // Parent writes to pipe
        close(pipefd[0]);    // Close unused read end

        char line[256];      // we take input from keyboard
        while ( fgets(line, 255, stdin) != NULL ) {
            write(pipefd[1], line, strlen(line));
        }

        close(pipefd[1]);    // Reader will see EOF
        wait(NULL);          // Wait for child
        exit(EXIT_SUCCESS);
    }
}
sh-5.0$ gcc -Wall pipe_shell.c -o pipe_shell
sh-5.0$ ./pipe_shell
bash-5.0$ date

date
[1]+  Stopped(SIGTTIN)        ./pipe_shell
sh-5.0$ Wed 10 Jun 2020 12:16:28 PM EDT
bash-5.0$ exit
There are stopped jobs.
sh-5.0$ fg
./pipe_shell
uptime
uptime
 12:16:52 up 154 days, 23:32,  5 users,  load average: 0.04, 0.05, 0.07
bash-5.0$ echo "foo"

[1]+  Stopped(SIGTTIN)        ./pipe_shell
echo "foo"
sh-5.0$ foo
bash-5.0$ exit
exit

【问题讨论】:

  • 你读过advanced linux programming然后syscalls(2)termios(3)signal(7)signal-safety(7)pipe(7)吗?你研究过源代码吗? zsh ?
  • 不,我继承了 12,000 行不太有效的代码,并被告知要修复它。我将问题追踪到一个执行类似操作的大块头,然后从手册页开始复制它。如果您能缩小我应该从哪里开始,我会非常乐意阅读所有这些内容。
  • 12000 行很小。您可以使用GDBstrace(1)ltrace(1)Clang analyzer 来了解它们。或许也写你自己的GCC plugin。预算几个月的工作。另请查看sash的源代码
  • 但是 StackOverflow 不是一个做我的工作的网站。在您的下一个问题中提供一些minimal reproducible example
  • 这是一个最小的可重现示例,这就是我包含它的原因。

标签: c linux bash fork exec


【解决方案1】:

尝试在没有bash-i 选项的情况下运行您的程序,尽管您不会看到提示。

过于简单的 SIGTTIN 问题与 read()、控制 tty 和进程组有关。有关详细信息,一个不错的起点是带有搜索词的 google.com:linux SIGTTIN;有一些文章深入研究了read/tty/pgrp。

要运行类似于您的小程序的交互式 shell 并可能解决您的大程序的问题,您可以使用主/从伪设备。有一个相关的库服务forkpty()。此外,还有一个名为 script 的 UNIX/linux 实用程序,它将交互式 shell 会话记录到常规文件中; script 的源代码是读写器进程、主/从伪设备和交互式外壳的一个很好的例子。

【讨论】:

  • 我知道script,但不知何故并没有把它当作一个例子。感谢您的建议;我要去看看更多的源代码。
猜你喜欢
  • 2012-07-17
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多