【问题标题】:Why does calling the timeout program from a bash script cause tcsetattr to hang?为什么从 bash 脚本调用超时程序会导致 tcsetattr 挂起?
【发布时间】:2017-01-31 02:50:47
【问题描述】:

由于某种原因调用超时程序,将内部具有 tcsetattr 的程序作为参数,从 bash 脚本导致 tcsetattr 挂起。在终端中直接在 bash 脚本之外调用它不会导致它挂起。为什么会这样?查看https://github.com/coreutils/coreutils/blob/master/src/timeout.c,似乎超时不会与任何文件描述符混淆。看起来它被设置为忽略两个信号,但这在这里不应该相关。

以下是一个最小的测试用例:

short.c

#include <stdio.h>
#include <termios.h>
#include <string.h>

int main() {
        struct termios tty;
        tcgetattr(0, &tty);
        fprintf(stderr, "Before tcsetattr");
        tcsetattr(0, TCSANOW, &tty);
        fprintf(stderr, "After tcsetattr");
}

simple_check.sh

#!/bin/bash
timeout 5 ./a.out < /dev/tty
echo $?

Bash 输出

$ gcc short.c
$ bash simple_check.sh
Before tcsetattr
124 # Note this should output `After tcsetattr` if it was 'working'
$ timeout 5 ./a.out < /dev/tty
Before tcsetattr
After tcsetattr

可能有用的信息

$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.1 LTS
Release:    16.04
Codename:   xenial

【问题讨论】:

  • 在我的 Ubuntu 12.04 系统上运行没有任何问题。
  • bash simple_check.sh 输出 tcsetattr 之前 tcsetattr 之后? @codeforester
  • 确实挂了!很抱歉造成混乱。
  • 莫名其妙的哈哈?
  • 因为timeout(没有--foreground标志)创建了一个新的进程组,a.out的进程组ID(getpgrp())将不匹配它的终端组IDtcgetpgrp()) , a.out 是一个后台进程。当后台进程向控制终端发出tcsetattr() 时,它会被SIGTTOU 信号停止。为避免这种情况,请运行timeout --foreground 5 ./a.out(用于单个进程)或timeout 5 setsid ./a.out(进程组,但没有控制终端)。

标签: c linux bash shell timeout


【解决方案1】:

--foreground 超时选项可以避免这个问题吗? 这将停止将超时(和孩子)放入他们自己的程序组中。

【讨论】:

  • RHEL 6 的超时没有 --foreground 选项。还有其他解决方法吗?
猜你喜欢
  • 2022-11-10
  • 1970-01-01
  • 2010-09-16
  • 2013-04-19
  • 2014-07-05
  • 2015-03-02
  • 2014-04-07
  • 1970-01-01
  • 2013-09-28
相关资源
最近更新 更多