- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
出于我不会深入探讨的原因,我需要在 FreeBSD 8.1 上的 Python 线程的子进程中运行“top -m io -d 2 10”的变体。问题是,似乎有时会生成 SIGTTOU(在我尚未破译的某些代码相关条件下),从而完全停止 top 和线程。其他时候,似乎没有产生 SIGTTOU,但 top 或线程仍然卡住了。
top 的输出应该为系统上的前 10 个进程生成两组 IO 统计信息,其中第一组是“绝对”数字,第二组是统计信息自上一组以来的增量差异,一秒更早。在终端或 shell 脚本中运行此命令,无论是否重定向输出,都可以正常工作。
出现问题时,“top”似乎写入了第一组输出,但在它可以输出第二组之前挂起/接收 SIGTTOU。在下面的示例代码中,只有一组进程统计信息被写入输出文件。
我发现 SIGTTOU 信号在“truss”下运行 python 脚本,但似乎“truss”和“top”之间的交互本身可能是一个令人困惑的问题,因为只需运行 truss top -d 2
产生信号并挂起,如下所示:
...
ioctl(1,TIOCGETA,0xffffe460) = 0 (0x0)
ioctl(1,TIOCGETA,0xc6b138) = 0 (0x0)
ioctl(1,TIOCGETA,0xffffe410) = 0 (0x0)
ioctl(1,TIOCGWINSZ,0xffffe460) = 0 (0x0)
ioctl(1,TIOCGWINSZ,0xffffe930) = 0 (0x0)
ioctl(1,TIOCGETA,0x50e560) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGINT|SIGQUIT|SIGTSTP,0x0) = 0 (0x0)
ioctl(1,TIOCGETA,0x50e560) = 0 (0x0)
SIGNAL 22 (SIGTTOU)
这是一个重现挂起和/或 SIGTTOU 的示例 Python 脚本:
import subprocess
from threading import Thread
def run():
with open("top.log", "wb") as f:
subprocess.Popen(("/usr/bin/top", "-m", "io", "-d", "2", "10"), stdout=f, stderr=f, stdin=subprocess.PIPE).communicate()
if __name__ == "__main__":
th = Thread(target=run)
print "Starting"
th.start()
th.join()
在我最后一次运行时,这个示例程序没有产生 SIGTTOU,但 top 确实挂了。桁架显示:
....
open("/usr/local/lib/python2.7/lib-tk/_heapq.pyc",O_RDONLY,0666) ERR#2 'No such file or directory'
stat("/usr/local/lib/python2.7/lib-dynload/_heapq",0x7fffffffa500) ERR#2 'No such file or directory'
open("/usr/local/lib/python2.7/lib-dynload/_heapq.so",O_RDONLY,0666) = 5 (0x5)
fstat(5,{ mode=-rwxr-xr-x ,inode=238187,size=22293,blksize=16384 }) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
open("/usr/local/lib/python2.7/lib-dynload/_heapq.so",O_RDONLY,057) = 6 (0x6)
fstat(6,{ mode=-rwxr-xr-x ,inode=238187,size=22293,blksize=16384 }) = 0 (0x0)
pread(0x6,0x80074c2e0,0x1000,0x0,0xffff800800653120,0x8080808080808080) = 4096 (0x1000)
mmap(0x0,1069056,PROT_NONE,MAP_PRIVATE|MAP_ANON|MAP_NOCORE,-1,0x0) = 34389442560 (0x801c54000)
mmap(0x801c54000,12288,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_FIXED|MAP_NOCORE,6,0x0) = 34389442560 (0x801c54000)
mmap(0x801d56000,12288,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,6,0x2000) = 34390499328 (0x801d56000)
mmap(0x0,36864,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34366377984 (0x800655000)
close(6) = 0 (0x0)
mmap(0x0,832,PROT_READ|PROT_WRITE,MAP_ANON,-1,0x0) = 34366414848 (0x80065e000)
munmap(0x80065e000,832) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
close(5) = 0 (0x0)
close(4) = 0 (0x0)
close(3) = 0 (0x0)
close(2) = 0 (0x0)
fstat(1,{ mode=crw------- ,inode=102,size=0,blksize=4096 }) = 0 (0x0)
ioctl(1,TIOCGETA,0xffffe400) = 0 (0x0)
Starting
write(1,"Starting\n",9) = 9 (0x9)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGKILL|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
_umtx_op(0x7fffffffe1d8,0x3,0x1,0x0,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGABRT|SIGEMT|SIGKILL|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2) = 0 (0x0)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGABRT|SIGEMT|SIGKILL|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2) = 0 (0x0)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
mmap(0x7fffffbde000,135168,PROT_READ|PROT_WRITE,MAP_STACK,-1,0x0) = 140737484021760 (0x7fffffbde000)
mprotect(0x7fffffbde000,4096,PROT_NONE) = 0 (0x0)
thr_new(0x7fffffffe220,0x68,0x800a9f4c0,0x186fc,0xffffffff,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
mmap(0x0,2097152,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34390511616 (0x801d59000)
mmap(0x801f59000,684032,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34392608768 (0x801f59000)
munmap(0x801d59000,684032) = 0 (0x0)
_umtx_op(0x8010127f8,0x10,0x1,0x0,0x0,0x0) = 0 (0x0)
_umtx_op(0x800e0b438,0xf,0x0,0x0,0x0,0x0) = 0 (0x0)
_umtx_op(0x800e0b438,0x10,0x1,0x0,0x0,0x0) = 0 (0x0)
_umtx_op(0x800e0b438,0x10,0x1,0x0,0x0,0x0) = 0 (0x0)
_umtx_op(0x800e0b438,0x10,0x1,0x0,0x0,0x8080808080808080) = 0 (0x0)
open("top.log",O_WRONLY|O_CREAT|O_TRUNC,0666) = 2 (0x2)
fstat(2,{ mode=-rw-r--r-- ,inode=70860,size=0,blksize=16384 }) = 0 (0x0)
pipe(0x7fffffbfd910) = 0 (0x0)
pipe(0x7fffffbfd870) = 0 (0x0)
fcntl(6,F_GETFD,) = 0 (0x0)
fcntl(6,F_SETFD,FD_CLOEXEC) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGABRT|SIGEMT|SIGKILL|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2) = 0 (0x0)
fork() = 21503 (0x53ff)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
close(6) = 0 (0x0)
close(3) = 0 (0x0)
read(5,0x801e31024,1048576) = 0 (0x0)
close(5) = 0 (0x0)
fcntl(4,F_GETFL,) = 2 (0x2)
fstat(4,{ mode=p--------- ,inode=0,size=0,blksize=4096 }) = 0 (0x0)
close(4) = 0 (0x0)
我查看了 SIGTTOU 并找到了对 TOSTOP termios 标志的引用,我在主线程、子线程和调用 Python 的环境中摆弄它,但都无济于事。这是一个教育过程,但我还没有做到。
我已经运行测试以确保最上面的进程是在 Python 进程的进程组中创建的,并且似乎停留在该进程组中(基于 SIGTTOU 文档,如果不是,这就是 SIGTTOU 的原因),这看起来不错:PGRP 最终与 Python PID/PGRP 相同。
我已经尝试使用 subprocess.check_output 和 .Popen() 使用 shell=True、shell=False 运行“top”,并在所有地方重定向 std{out,err,in},似乎没有一个改变这个最终结果。我尝试使用通过子进程执行的“/bin/sh -c”命令运行“top”,但也无济于事。
如果不做一些半奇怪的事情,比如在我的 Python 线程调用的 shell 脚本中运行“top”,或者求助于 os.fork() 而不是使用线程,我该如何解决这个问题,根本原因是什么?
最佳答案
我意识到这个问题有点老了,但如果你仍然遇到错误,我很乐意调试它。
根本原因:您的 SIGTTOU 发生是因为您的 Python 解释器在您调用 th = Thread(target=run)
和 时 fork 创建后台线程top
没有被告知/不知道它不应该使用终端。您看到信号是因为 top
变得活跃并尝试将终端写入(或更改其仿真模式)作为 background 进程,而您已禁止此行为发生在您的 TTY 设置。
man stty
比我更简洁地解释了这一点:
tostop (-tostop)
Send (do not send) SIGTTOU for background output. This causes back-
ground jobs to stop if they attempt terminal output.
解决方法:允许后台线程在脚本运行期间将输出扔到终端上 (stty -tostop; python my_script.py; stty tostop
) 或添加('-n'
) 标记到 top
的子进程调用。
详细说明:只有一个每个组的进程可以在前台,其余的留在后台——前台进程处理来自 tty 的 I/O,而其余部分必须保留为后台进程,否则您会看到作业控制信号开始被抛出(例如 SIGTTIN/SIGTTOU)。
在您的 Python 脚本执行期间,我相信会发生以下情况:
$SHELL #(controls TTY)
$ python my_script.py #(tcsetpgrp() is called to hand off control of TTY)
~~~ heck yeah, snake party ~~~
th = Thread(target=run) #(run target=proc in background)
print "Starting" #(still okay -- this gets handed up to the foreground interpreter)
th.start()
#(here be dragons, std i/o in background fork)
subprocess.Popen(("/usr/bin/top", "-m", "io", "-d", "2", "10").communicate()
我检查了 FreeBSD manual for its top implementation我发现了以下确凿的证据:
DESCRIPTION
Top displays the top processes on the system and periodically updates
this information...
Top makes a distinction between terminals that support advanced capa-
bilities and those that do not...If the output of top is redi-
rected to a file, it acts as if it were being run on a dumb terminal.
...
OPTIONS
-i Use "interactive" mode. In this mode, any input is immediately
read for processing. See the section on "Interactive Mode" for
an explanation of which keys perform what functions. After the
command is processed, the screen will immediately be updated,
even if the command was not understood. This mode is the
default when standard output is an intelligent terminal.
...
-n Use "non-interactive" mode. This is identical to "batch" mode.
虽然 top
不知道它正在后台进程中运行(文件处理正在使用您的 Python 上下文管理器完成)并且您没有指定非交互模式,但它假设它可以免费使用 tty——这意味着如果 top
在处理命令并尝试更新屏幕时获取任何 STDIN 和 SIGTTOU 信号,您可能会看到 SIGTTIN 信号。
对 FreeBSD 的顶级实现特别感兴趣的是,交互调用与非交互调用时发生的差异:
您添加 shell=True
的想法验证了这一理论 sets the child process of 'top' to the PID of the shell that subprocess.Popen(..)
spawns ,它仍然在后台 Python 线程中。
(n.b. 抱歉:我现在无法访问 FreeBSD 8.1 主机来验证您的主机操作系统上的行为。)
关于python - 在线程中运行 'top' 会产生 SIGTTOU,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9827820/
在下面的代码中,当我为子进程调用setpgid后,子进程应该位于其自己的进程组中(成为后台组),而父进程仍保留在前台组中。我使用 strace 来跟踪信号。 ls 进程成功写入 STDOUT,但没有出
出于我不会深入探讨的原因,我需要在 FreeBSD 8.1 上的 Python 线程的子进程中运行“top -m io -d 2 10”的变体。问题是,似乎有时会生成 SIGTTOU(在我尚未破译的某
我正在编写一个基本的 shell 作为类作业,它在 Linux 上运行良好,但当子进程在 OSX 上退出时,我在重新捕获终端控制时遇到问题。 我尝试调用 tcsetpgrp(STDERR_FILENO
我正在开发一个伪终端库。该代码是用 C 代码实现的,该代码由基于 Web 的终端使用。只要我不使用 sudo 或登录,代码就可以工作。 这是我在 Mac 上运行服务器时遇到的错误: sh-3.2$ s
我是一名优秀的程序员,十分优秀!