perl を使用してタイムアウトの代わりを作成しようとしています (centos5 で必要)
ここにスクリプト:
#!/usr/bin/perl
use strict;
my $pid=$$;
my $timeout=shift;
my @args=@ARGV;
eval {
local $SIG{ALRM} = sub {
print "Timed OUT!\n";
exit 142;
kill 9,$pid;
};
alarm($timeout);
system(@args);
};
exit $?;
それをテストしている間、私は見つけました:
ここは大丈夫
time /tmp/timeout 3 sleep 6
Timed OUT!
real 0m3.007s
user 0m0.000s
sys 0m0.004s
しかし、ここではすべて悪い
time echo `/tmp/timeout 3 sleep 6`
Timed OUT!
real 0m6.009s
user 0m0.000s
sys 0m0.004s
私がテストした私のdebianシステムで/usr/bin/timeout
:
time echo `/usr/bin/timeout 3 sleep 6`
real 0m3.004s
user 0m0.000s
sys 0m0.000s
だから質問
- なぜ perl スクリプトの動作がおかしいのでしょうか?
- バイナリタイムアウトと同じように動作する、perl でタイムアウトを書き込む実際の方法はありますか?
私が知っていることに注意してください。/usr/share/doc/bash-3.2/scripts/timeout
また、それが私のperlアプローチと同じように機能することもわかりました
また、このスクリプトの対象となるサーバーに CPAN からモジュールをインストールできないことにも注意してください。
私は試してみましexec()
たが、その場合はサブで信号を処理しません。
UPD
@rhj のスクリプトを使用 (少し修正する必要がありました)
#!/usr/bin/perl
use strict;
use warnings;
my $PID=$$;
my $timeout=shift;
my @args=@ARGV;
my $pid = fork();
defined $pid or die "fork: $!";
$pid == 0 && exec(@args);
my $timed_out = 0;
$SIG{ALRM} = sub { $timed_out = 1; die; };
alarm $timeout;
eval { waitpid $pid, 0 };
alarm 0;
if ($timed_out) {
print "Timed out!\n";
kill 9, $pid;
kill 9, $PID;
}
elsif ($@) {
warn "error: $@\n";
}
上記のテストには合格しますが、外部スクリプトを呼び出す場合は失敗します。
run_script
#!/bin/sh
sleep 6
test.sh
#!/bin/sh
a=`./timeout.pl 2 ./run_script.sh`
出力
$ time ./test.sh
real 0m6.020s
user 0m0.004s
sys 0m0.008s