Abrindo blocos de pipe nomeados para sempre, se o pipe for excluído sem estar conectado

4

Como o título sugere, tente os seguintes comandos shell:

mkfifo /tmp/test.pipe

ls -1 /tmp > /tmp/test.pipe &

rm /tmp/test.pipe
mkfifo /tmp/test.pipe
cat /tmp/test.pipe &

jobs

O comando ls é apenas um exemplo e pode ser qualquer processo que queira gravar no pipe nomeado. O ponto aqui é que o processo bloqueará a tentativa de abrir o pipe para gravação. Agora, outro processo vem e remove o tubo. Um novo canal com o mesmo nome é criado e o processo cat (ou seja, qualquer processo que tente abri-lo para leitura) bloqueará a espera de outro processo para gravar no novo canal com o mesmo nome. Ambos os processos estão aguardando sua conexão de tubulação. Isso pode ser verificado listando o background jobs .

Não estou muito preocupado com o bloqueio cat (ou qualquer processo que esteja tentando ler do canal), porque, na verdade, o processo de leitura do pipe é, na verdade, o primeiro a substituí-lo. Na verdade, não me importo com os processos de leitura. O cat serve apenas meu exemplo para provar que, de fato, ambos os processos se referem ao mesmo nome do arquivo pipe, mas estão obviamente usando instâncias de pipe distintas. No entanto, observe que esse exemplo de deadlock também seria bloqueado no caso inverso, ou seja, um processo de leitura seria bloqueado para sempre se o pipe fosse excluído sem nunca ter sido aberto para gravação.

Meu foco está no processo de gravação de bloqueio (o ls no meu exemplo). Ele nunca tem a chance de perceber que o pipe original para o qual ele está tentando gravar foi substituído por um novo com o mesmo nome.

Existe alguma maneira do Linux para identificar tais situações, ou seja, uma situação em que um processo bloqueia a gravação de acesso a um pipe nomeado que não existe mais? Você pode assumir privilégios de root e que eu Conhecer os PIDs de todos os processos envolvidos. Em particular, conheço o processo de escrita que pode ou não ter ocorrido em tal situação. No entanto, eu não sei (que é o que eu quero descobrir), se o processo realmente se deparou com esse problema ou não , para que eu possa finalizá-lo. Como posso encontrar processos que estão bloqueando o acesso a um pipe nomeado que não existe fisicamente no sistema de arquivos?

Aparentemente, ls /proc/<PID>/fd não lista o descritor de arquivo para o acesso do processo a qualquer canal, exceto quando ambas as extremidades de um pipe estão conectadas, ou seja, ls /proc/<PID>/fd listará os descritores de arquivo em um canal apenas para ambos os processos após a chamada do sistema ter retornado com sucesso em ambas as suas extremidades. Como no meu exemplo há dois pipes half-connected distintos com o mesmo nome, nenhum deles é listado para nenhum dos processos.

    
por Robin479 06.01.2017 / 16:33

2 respostas

4

Como sugerido por Julie Pelletier , estou fazendo esta resposta sobre a solução alternativa que encontramos em nossa discussão.

Você não pode identificar facilmente situações de deadlock, conforme descrito na minha pergunta, mas você pode preventivamente desafogar o pipe nomeado como uma solução alternativa antes que alguém o exclua (se você realmente não puder evitar essa exclusão, como No meu caso). Esta ventilação deve permitir que qualquer escritor bloqueie atualmente a tentativa de abrir o pipe, para ter sucesso com a operação de abertura, mas falhar durante a operação de gravação real (-> tubo quebrado). O fracasso pode ser melhor que um impasse. Para não correr imediatamente para o próximo impasse, você deve mover o tubo antes de ventá-lo e apagá-lo depois.

# rename the pipe, i.e. move it out of the way
mv -f /tmp/test.pipe /tmp/test.pipe~ 2>/dev/null

# vent the pipe, i.e. shortly open it for reading but don't read from it.
# call the subshell dd and empty echo calls in the background to avoid 
# deadlocking on redundant venting.
(dd if=/tmp/test.pipe~ count=0 2>/dev/null & echo -n "" >/tmp/test.pipe~ &)

# delete the old pipe
rm -f /tmp/test.pipe~

Se você souber qual programa executa a exclusão com falha, convém agrupar esse programa em um script pequeno, que faz a ventilação e ignora a exclusão.

    
por 09.01.2017 / 10:49
1

Isso tem uma condição de interrupção, pois lança o dd no segundo plano enquanto aguarda o eco no primeiro plano.

Isso pode ser evitado jogando a chamada de eco para o plano de fundo também:

(dd if = / tmp / test.pipe ~ count = 0 2 > / dev / null & echo -n "" > /tmp/test.pipe~ &)

    
por 27.10.2017 / 22:32