Я написал довольно большую программу, которая выполняет команды на множестве удаленных хостов, но столкнулся с серьезной проблемой, и не знаю, как ее исправить.
После долгих попыток мне удалось извлечь минимальный код, чтобы надежно воспроизвести проблему на моей машине:
use warnings;
use strict;
use threads;
use threads::shared;
use Data::Dumper;
use POSIX ":sys_wait_h";
use Net::OpenSSH;
use Time::HiRes qw( usleep );
my @LIST=qw(host038b host039a host039b host040a host040b host041a host041b host043a
host043b host044a host044b host045a host045b host046a host046b host047a host047b host049a
host049b host050a host050b host054a host054b host055a host055b host056a host056b host057a
host057b host058a host059a host059b host060a host060b host062a host062b host063a host068a
host068b host069a host069b host071a host071b host072a host073a host073b host075a host075b
host078a host078b host082a host082b host087a host087b host089a host089b host090a host090b
host091a host091b host092a host092b host096a host096b host097a host097b host098a host099a
host099b host100a);
my ($SSH, $CPID, %PIDS, @DONE);
sub _testthread {
# Read stdout pipe
my $SCROUT=shift;
while (<$SCROUT>) {
print $_; # I normally write that to a logfile
}
return (0);
}
foreach (@LIST) {
$SSH->{$_}=Net::OpenSSH->new($_, async => 1,
master_opts => [ -o => "PasswordAuthentication=no"]);
}
$SIG{CHLD} = sub { my $WPID;
push (@DONE, { 'PID' => $WPID, 'RC' => $?, 'ERR' => $!}) while (($WPID = waitpid(-1, WNOHANG)) > 0) };
foreach (@LIST) {
my ($SCRFH, $SCROUT, undef, $CPID) = $SSH->{$_}->open_ex({stdin_pipe => 1,
stdout_pipe => 1}, '/bin/bash -s');
$PIDS{$CPID}='ACTIVE';
threads->new('_testthread', $SCROUT);
print $SCRFH "sleep 2\n";
print $SCRFH "echo test `hostname`\n";
print $SCRFH "exit 0\n";
close $SCRFH;
usleep 10000;
}
while (grep(/^ACTIVE/, values(%PIDS)) > 0) {
print Dumper \%PIDS;
while (@DONE) {
my $DONE = shift (@DONE);
$PIDS{$DONE->{PID}}='DONE';
}
sleep 1;
}
$_->join foreach (threads->list);
С предустановленным perl 5.10 в большинстве случаев происходит ошибка сегментации, даже при удалении некоторых более сложных конструкций перенаправления вывода open_ex в файловый дескриптор. С недавно скомпилированным perl 5.18.2 этот скрипт большую часть времени зависает на неопределенный срок, потому что он, кажется, не получает каждый SIG{CHLD}, даже несмотря на то, что я использую безопасную сигнализацию (насколько я понимаю).
Чтобы воспроизвести проблему, кажутся необходимыми следующие вещи:
- Достаточное количество хостов в @LIST
- позволяя open_ex (или производным методам Net::OpenSSH) разветвляться
- предоставление дескриптора файла STDOUT этого форка потоку
- используя обработчик сигнала для SIG{CHLD}
Поскольку моя большая программа, использующая эту структуру, в основном непригодна для использования, я был бы очень рад, если бы кто-нибудь помог мне найти решение, возможно, альтернативу.
Спасибо и привет,
Маззе
SIGCHLD
может прийти в любой поток. Таким образом, ваш скрипт отправляет результатыwaitpid
вызовов, разделенных на@DONE
клоны. Что касается 5.10, segfault указывает на ошибку в Perl или в модуле потоков. - person salva   schedule 08.04.2014@DONE
как общий, чтобы действительно исключить его. - person salva   schedule 08.04.2014parsub
действия. См. Часто задаваемые вопросы о sudo. - person salva   schedule 08.04.2014open2
, который является ярлыком дляopen_ex({stdin_pipe => 1, stdout_pipe => 1}, ...)
. Например:my ($in, $out, $pid) = $ssh->open2("bash -s");
- person salva   schedule 08.04.2014