2012-03-22 1 views
5

FreeBSD 8.1のPythonスレッドのサブプロセス内で 'top -m io -d 2 10'の亜種を実行する必要があります。問題は、時にはSIGTTOUが(コード解読されていない特定のコード依存条件のもとで)生成され、トップとスレッドを完全に停止させるようです。それ以外の時は、SIGTTOUは作成されていないようですが、とにかく上やスレッドが詰まってしまいます。スレッドで 'top'を実行するとSIGTTOUが生成されます

トップからの出力では、システム上の上位10個のプロセスの2つのIO統計が生成されます。最初のセットは「絶対」番号で、2番目のセットは最後のセット以降の統計の増分差です2番目に早い。出力をリダイレクトするかどうかにかかわらず、ターミナル上またはシェルスクリプト内でこのコマンドを実行すると正常に動作します。

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

単にtruss top -d 2を実行すると、以下のように、信号やハングを生成するので、私は「トラス」の下でPythonスクリプトを実行しているSIGTTOU信号を発見したが、「トラス」と「トップ」の間の相互作用は、自身が交絡問題であってもよいことらしいです:ここでは

... 
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を生じなかったが、トップハングアップでした。トラスは示しています

.... 
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にして、シェル= Trueの場合、シェルは= Falseを使用して、すべての場所に{、errは、外で} STDをリダイレクトどれもが思わ.Popen()で「トップ」を実行してみましたこの最終結果を変更します。私は、 '/ bin/sh -c'コマンドをサブプロセスを通して実行しても、 '役に立たない'ように 'top'を実行しようとしました。

私のPythonスレッドが呼び出すシェルスクリプト内で 'top'を実行したり、スレッドを使用する代わりにos.fork()を使用するような半奇妙なことをしないで、どうすればこの問題を回避できますか?原因?

答えて

1

SIGTTOUは、プロセスが制御端末変更しようとするときに使用される:実装はジョブ制御をサポートしている場合、特に断りのない限り、

を、バックグラウンドプロセスグループ内のプロセスは、端末の利用に制限されています-control-functions(termios(3C)を参照してください)。これらの機能を実行しようとすると、プロセスグループにシグナルSIGTTOUが送信されます。呼び出し元プロセスがシグナルSIGTTOUを無視またはブロックする場合、シグナルSIGTTOUを送信せずに制御機能を実行しようとします。(Terminal access controlから)

これは何を意味するのでしょうか?これは、トップが端末に関する何かを変更しようとしていることを意味し、それができないと言われています。SIGTTOUのデフォルトアクションは、プロセスの実行を停止することです。

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

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


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

+0

(私は今、あなたのホストOS上で動作を確認するためにはFreeBSD 8.1ホストへのアクセスを持っていないn.b.の謝罪。)。今日まで、私はまだトップが端末について何を修正しようとしているのか(または理由)よく分からない。残念ながら私はこれをレガシーシステムに取り組んでいるので、実際には自分のコードで 'top'の生の出力を生成する必要があります。私はこれを回避するために、Pythonの 'pty'ライブラリを使用し、その内部を実行しました。しかし、これは他の技術的困難のために、出力からANSIシーケンスを最小限に解析して取り除くことも必要としました。 (でも今は動作します!):) – Anthem

0

トップに-bオプションを使用してみましたか?これは、バッチジョブとダム端末のためのもので、何をしていても、信号をトリガしていても何もしないことを伝えるかもしれません...

2

私はこの質問は少し古いですが、エラーには、私は汚れにこれをデバッグしたいと思います。

根本原因:あなたのPythonインタプリタはあなたがth = Thread(target=run)topはそれが端末を使用すべきではない知らない/語られていない呼び出したときに、バックグラウンドスレッドを作成するために、フォークされているため、あなたのSIGTTOUが発生しています。 topは、TTY設定でこの動作が発生しないようにすると、バックグラウンドプロセスとして、気が散ってきて端末に書き込む(またはエミュレーションモードを変更する)ため、信号が表示されています。

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')フラグを追加

man sttyは、より簡潔に、私は希望よりも、これを説明しますあなたのサブプロセス呼び出しはtopです。


推敲:グループごとつだけプロセスがフォアグラウンド、残りにすることができ、背景に残り - フォアグラウンドプロセスがTTYからI/Oを処理し、残りは背景として残っている必要がありますプロセスが実行されると、ジョブ制御シグナルがスローされ始めます(SIGTTIN/SIGTTOUなど)。あなたのPythonスクリプトの実行中

、私は次のことが起こると信じて:しないtop一方

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. 

$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をチェックアウトし、私は次の喫煙銃を発見しましたそれがバックグラウンドプロセスで実行されていることを知っています(ファイルハンドリングはPythonコンテキストマネージャーで行われています)。非対話モードを指定していない場合は、ttyを自由に使用できることを前提としています。 sコマンドが処理されて画面を更新しようとしたときにtopがSTDINとSIGTTOU信号を受け取った場合、SIGTTINはシグナルを出します。 shell=True検証を追加する

あなたのアイデア:

FreeBSDのトップ実装、対話的ではないと呼ばれるときに何が起こるかの違いから特に興味深いの

この理論はまだsets the child process of 'top' to the PID of the shell that subprocess.Popen(..) spawnsであり、これはまだ背景にあるPythonスレッド。私はそれ以来、発見したものと一致

関連する問題