Цикл IO :: Select как-то удерживает дочерний элемент от выхода? - PullRequest
1 голос
/ 21 сентября 2019

У меня есть цикл perl IO :: Select для запуска команды (без stdin) и сохранения ее вывода в различные журналы.

Это прекрасно работало в течение ряда лет, но внезапно оно плохо себя ведетс одной конкретной командой.Команда выполняется до конца и правильно завершается, если она запускается из командной строки, но когда я запускаю ее из этого кода Perl, то после того, как это сделано (как видно из журналов), дочерний процесс не завершится, и он просто будет находиться взависшее состояние.У меня нет прав доступа к системам, на которых это происходит, поэтому я не вижу точно, что застряло.

Код по сути:

    # Start process
    open(local *nostdin, '<', '/dev/null') or die $!;
    my $pid = open3('<&nostdin',
       my $outH = gensym(),
       my $errH = gensym(),
       $command
    );

    # Setup select
    my $sel = IO::Select->new();
    $sel->add($outH);
    $sel->add($errH);

    # Select loop
    while (my @ready = $sel->can_read()) {
        foreach my $handle (@ready) {
            my $bytesRead = sysread($handle, my $buf='', 1024);
            if ($bytesRead <= 0) {
                warn("Error reading command out $!\n  Command: $command\n") if $bytesRead;
                $sel->remove($handle);
                next;
            }
            if ($handle==$outH) {
                syswrite(SYSOUT,$buf) if $stdoutOpen;
                syswrite(SYSLOG,$buf) if $logOpen;
            }
            if ($handle==$errH) {
                syswrite(SYSERR,$buf) if $stderrOpen;
                syswrite(SYSLOG,$buf) if $logOpen;
            }
        }
    }

Есть ли что-нибудь, что яможет быть не так?И даже если есть ошибка, как цикл ввода-вывода perl может удерживать дочерний процесс от его выхода?Кажется, что когда ребенок выходит, он закрывает все свои операции ввода-вывода, и мы заканчиваем этот цикл (как всегда было с этим кодом).


Я провел несколько тестов с использованием waitPidи некоторый вывод, и похоже, что $ outH закрывается, но $ errH никогда не имеет никаких данных и никогда не закрывается, и тогда я вижу из waitPid, что дочерний процесс имеет выход.

Итак, я открываю два канала,для ребенка и ребенка ошибаться.Дочерний объект использует выходной канал, а не канал ошибок.Затем дочерний элемент закрывает выходной канал и выходит, каким-то образом этот выход не закрывает канал ошибок.Как это происходит?Это что-то, что ребенок мог даже сделать нарочно?

...