【发布时间】: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