5

説明しない理由により、FreeBSD 8.1 の Python スレッドからサブプロセス内で「top -m io -d 2 10」のバリアントを実行する必要があります。問題は、時々 SIGTTOU が生成され (私がまだ解読していない特定のコード依存の条件下で)、top とスレッドが完全に停止するように見えることです。また、SIGTTOU が生成されていないように見えますが、いずれにせよトップまたはスレッドがスタックします。

top からの出力は、システムの上位 10 プロセスの IO 統計の 2 つのセットを生成する必要があります。最初のセットは「絶対」数であり、2 番目のセットは最後のセットからの統計の増分差 (1 秒前) です。出力をリダイレクトするかどうかに関係なく、ターミナルまたはシェル スクリプト内でこのコマンドを実行すると、正常に動作します。

問題が発生すると、'top' は出力の最初のセットを書き込んだように見えますが、2 番目のセットを出力する前に SIGTTOU をハング/受信します。以下のサンプル コードでは、1 セットのプロセス統計のみが出力ファイルに書き込まれます。

truss top -d 2「truss」の下で python スクリプトを実行している SIGTTOU シグナルを発見しましたが、以下のように単に実行するとシグナルが生成されてハングするため、「truss」と「top」自体の間の相互作用が混乱を招く可能性があるようです。

...
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 スレッドが呼び出すシェル スクリプト内で「top」を実行したり、スレッドを使用する代わりに os.fork() に頼ったりするなど、やや奇妙なことをせずに、この問題を回避するにはどうすればよいですか?根本的な原因は何ですか?

4

3 に答える 3

1

SIGTTOUプロセスが制御端末を変更しようとするときに使用されます。

実装がジョブ制御をサポートしている場合、特に明記されていない限り、バックグラウンド プロセス グループ内のプロセスは、端末制御機能 (termios(3C) を参照) の使用が制限されます。これらの機能を実行しようとすると、プロセスグループにシグナル SIGTTOU が送信されます。呼び出しプロセスがシグナル SIGTTOU を無視するかブロックする場合、制御機能を実行しようとするとシグナル SIGTTOU は送信されません。

(端末アクセス制御より)

これは何を意味するのでしょうか?これは、トップがターミナルについて何かを変更しようとしていて、それができないと言われていることを意味します。デフォルトのアクションSIGTTOUは、プロセスの実行を停止することです (ハングアップと呼びます)。

あなたがしようとすることができるのはfork()、それを制御端末のない独自のプロセスグループに入れることです。これによりtop、呼び出したいものは何でも呼び出すことができるはずです。また、制御端末がないため、まったく効果がありません。

ただし、 top は非対話的に呼び出されることを意図したものではありませんでした. を使用して同じ情報を取得することはできませんpsか?


このブログ投稿: http://www.technovelty.org/tips/sigttou-and-switching-to-canonical-mode.htmlも、何が起こっているかを明確に説明しています。それが役に立てば幸い。

于 2012-11-01T16:20:42.443 に答える
1

top で -b オプションを使用してみましたか? これは、バッチジョブとダム端末を対象としており、シグナルをトリガーする何をしていても、実行しないように top に指示する場合があります...

于 2013-04-10T23:08:28.143 に答える