BASH: Fifo troubles - parece seletivo sobre entrada

3

Então eu estou tendo um problema com um serviço BASH no Debian 7 que eu tenho trabalhado por um bom tempo e que aleatoriamente começou a ter problemas com seu fifo, ou assim parece. Ele é baseado no tipo de seu exemplo clássico de uso do fifo e funcionou bem durante meses, mas de repente, hoje, começou a me causar problemas. Parece que sempre que coisas assim acontecem, é sempre algo completamente diferente do que eu concluí originalmente, então vou apresentar o que eu tenho e talvez alguém possa apontar para mim a parte óbvia que eu não estou vendo.

Como eu disse, meu código para leitura / escrita de um pipe nomeado é meio padrão. Eu fiz uma versão fervida (linhas de 150ish) que eu pensei em apresentar mas, é claro, funcionou bem e eu não tenho idéia do porquê. Então aqui está a versão superconduzida para referência:

#--------------------------------Writer Script--------------------------------------#
#!/bin/bash

fifoIn=".../path/fifoIn"

#Read user input
IFS='' #Changed IFS so that spaces aren't trimmed from input
while true; do
    read -e line
    printf "%b\n" "$line" >&4
done 4>"$fifoIn"

exit 0

#--------------------------------Reader Script--------------------------------------#
#!/bin/bash

fifoIn=".../path/fifoIn"
LogFile=".../path/srvc.log"
[ -d ".../path" ] || mkdir -p ".../path"
[ -e "$fifoIn" ] || mkfifo "$fifoIn"

printf "%b\n" "Flushing input pipe" >> "$LogFile"
dd if="$fifoIn" iflag=nonblock of=/dev/null >/dev/null 2>&1

while true; do
    if read -t 0.1 -a str; then
        printf "\n%s\n" "<${str[*]}>"
        case "${str[0]}" in
            "foo")
                printf '%b\n' "You said foo..."
                ;;
            "bar")
                printf '%b\n' "You said bar..."
                ;;
            "")
                ;;
            *)
                printf "%b\n" "${str[*]}:"
                printf "%b\n" "Uhhuh..."
                ;;
        esac
    fi
done <"$fifoIn" >> "$LogFile" 2>&1 3>"$fifoIn"

Então você pega 'script de leitura' e o executa como um daemon, então fale com ele por echo ing ou printf ing ou use o script writer para enviar mensagens para o pipe nomeado, fifoIn . Isso funcionou muito bem desde o início, mas hoje ficou estranho.

Por algum motivo, começou a escolher quem poderia escrever (ou pelo menos parecia que poderia escrever) para o canal. Eu não vi nenhum erro, mas eu tentaria enviar texto para o pipe e nada aconteceria no lado do serviço. Eu tenho tarefas agendadas configuradas para gravar no pipe e elas não passariam por nenhum problema enquanto eu echo ing de um terminal não receberia nada. Nem mesmo erros ou permissões negaram mensagens. As tarefas agendadas são configuradas para serem o mesmo usuário do meu terminal, então não acho que isso seja uma permissão.

Parece que toda vez que eu apaguei o fifo e reiniciei o serviço, eu consegui algumas mensagens inseridas pelo terminal normalmente, mas nem sempre, que pareciam bloquear ou parar de funcionar depois que uma mensagem originada pelo cron era enviado para o serviço. Eu não seria mais capaz de enviar mensagens através do pipe, mas as mensagens originadas no cron continuariam a passar muito bem!

Eu fiz algumas pesquisas e me deparei com o comando strace . Eu tentei fazer algo como strace printf '%b\n' "foo" >> .../path/fifoIn , peguei um monte de coisas de chamadas de sistema de diagnóstico que eu realmente não entendi, mas parece que tudo deu certo porque não havia nada como Hey! right here! something broke right here!! e acabou com:

...
write(1, "foo\n", 4)
close(1)
...

que eu estou supondo é uma coisa boa. Agora, o mais engraçado, a mensagem passou e o daemon leu como esperado! Eu removi o strace dessa linha exata e, novamente, sem dados.

Então, todos vocês que sabem muito mais sobre as operações e as chamadas do sistema do que eu, o que acontece de forma diferente quando você tem strace como prefácio e quando não tem? O que geralmente pode escovar um tubo sem ter sido fechado para leitura? Quaisquer outros leads que você possa pegar porque eu estou perdido.

UPDATE

@Gilles, acho que você está fazendo algo sugerindo outros processos tentando ler o mesmo canal e causando problemas ... Eu escrevi uma nova função que chama algumas instâncias de mutt que parecem ter alguma associação com fifoIn por algum motivo. Eu não estou muito certo de como ler a saída de lsof , mas ele lê isso depois que eu executo essa função (e conseqüentemente estouro do meu cachimbo):

COMMAND     PID   TID        USER   FD      TYPE DEVICE SIZE/OFF     NODE NAME
mutt      13874           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13874           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13897           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13897           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13932           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13932           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13971           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13971           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14012           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14012           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14051           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14051           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14096           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14096           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14124           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14124           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
srvc      14298           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
srvc      14298           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
lsof      15587           uname    1w     FIFO    0,8      0t0   176516 pipe
lsof      15587           uname    5w     FIFO    0,8      0t0   176524 pipe
lsof      15587           uname    6r     FIFO    0,8      0t0   176525 pipe
grep      15588           uname    0r     FIFO    0,8      0t0   176516 pipe
lsof      15589           uname    4r     FIFO    0,8      0t0   176524 pipe
lsof      15589           uname    7w     FIFO    0,8      0t0   176525 pipe

Eu estou supondo que eu tenha omitido as chamadas do mutt (que acabam sendo executadas em subshells), mas elas estão trancando no FD herdado por causa do que eu fiz de errado com o comando. Eu diria que essa é a resposta e eu vou tirar daqui! Se você postar uma 'resposta', eu ficaria feliz em selecioná-la!

    
por Justin Frahm 26.05.2015 / 11:01

1 resposta

1

It, for some reason, started getting choosey about who could write (or at least it seemed to be who could write) to the pipe. I didn't see any errors, but I would try to send text to the pipe and nothing would happen on the service side.

Se o seu programa costumava funcionar e o mesmo programa não funciona, verifique se o ambiente pode ter mudado.

Os sintomas são consistentes com vários leitores no canal e observando apenas um dos leitores. Quando vários processos estão lendo de um pipe, os dados podem ir para qualquer um dos processos.

Você está usando um pipe nomeado com um nome fixo. As chances são de que você tenha uma instância perdida da parte do leitor do seu programa em algum lugar.

Você pode verificar quais processos têm o pipe nomeado aberto com lsof :

lsof .../path/fifoIn

Se não houver um gravador no pipe, talvez haja leitores bloqueados em uma chamada open - abrindo um bloco de pipe nomeado até que um gravador esteja presente. lsof não relata isso, pois o pipe ainda não está aberto. Não sei como localizar processos que estão bloqueados em uma chamada open . Você pode fazer com que a chamada open retorne em todos os processos, abrindo-a para gravação:

sleep 99999999 >.../path/fifoIn &
lsof .../path/fifoIn

Tenha em mente que os arquivos abertos são herdados por subprocessos. Se o programa iniciar outros programas em segundo plano enquanto estiver aberto, esses programas ainda poderão ter o canal aberto para leitura. Você pode querer fechar o pipe:

while … do
  subprocess_that_does_not_need_the_pipe </dev/null
done <.../path/fifoIn

ou

while … do
  subprocess_that_does_not_need_the_pipe 0<&3
done 3<&0 <.../path/fifoIn
    
por 30.05.2015 / 01:46