De acordo com pipe(7)
:
Se todos os descritores de arquivo referentes à extremidade de leitura de um pipe tiverem sido fechados, então a
write(2)
fará com que umSIGPIPE
sinal seja gerado para o processo de chamada. Se o processo de chamada estiver ignorando esse sinal,write(2)
falhará com o erroEPIPE
.
Por que o Unix precisa ter o SIGPIPE
sinal quando write()
pode simplesmente retornar EPIPE
diretamente? Meu entendimento é que os sinais são destinados a coisas que são inerentemente assíncronas (por exemplo, encerramento de um filho, interrupção terminal). Mas SIGPIPE
só é gerado como o resultado imediato de uma chamada to write()
; nesse caso, ele sempre pode simplesmente retornar EPIPE
to to caller para indicar o erro ao chamador.
Por que foi considerado necessário ter SIGPIPE
além de EPIPE
?
Alguns programadores não se preocupam em verificar erros. Alguns programas geram grandes quantidades de saída com
printf
(ou, talvez,write
) sem verificar o retorno de um erro. Tal programa poderia ser executado inutilmente até a conclusão, com a saída indo para o balde de bits, se estiver gravando em um canal quebrado.SIGPIPE força o encerramento de tal programa (assumindo que ele não capte ou ignore o sinal).
Isso remonta aos primeiros dias do Unix. Douglas McIlroy , que era o chefe do departamento do Bell Labs onde o Unix foi criado, e que havia trabalhado em outros sistemas incluindo o Multics, estava muito interessado em ter formas úteis de combinar programas. Conforme descrito em A Criação do Sistema Operacional UNIX — Conectando fluxos como uma mangueira de jardim :
Em A Research UNIX Reader: Annotated Trechos from the Programmer's Manual, 1971-1986 , McIlroy explica que
Portanto, a ideia dos pipelines veio primeiro, e a
pipe
chamada do sistema foi uma forma de implementá-la. Pipelines apareceram no Unix v3. Antes disso, encadear programas exigia o uso de um arquivo temporário para a saída do primeiro programa, passando-o como entrada para o segundo programa e, finalmente, removendo o arquivo temporário.Agora, se a sua filosofia de programas é que eles se destinam a consumir entradas e produzir saídas, o que você faz se a saída de um programa parar de ser consumida? O programa não é mais útil, então você o mata. Daí o que evoluiu para o sinal SIGPIPE. Como alguns programas têm um comportamento útil que vai além de gravar conteúdo na saída padrão, eles podem solicitar que não sejam eliminados se a saída padrão desaparecer. Esses programas observam um erro EPIPE. Mas como os pipes são uma ferramenta fundamental, ser morto é o comportamento padrão.
EPIPE é um erro de gravação dentro da banda que ocorre no desligamento ordenado do canal. O processo normalmente não morre com isso e continua, esperançosamente depois de lidar com o erro e antes de tentar gravar mais dados. Se ele ignorar o erro em vez de tratá-lo e continuar gravando no canal de desligamento, ele receberá um SIGPIPE e morrerá.
Além disso, SIGPIPE é, como você diz, um sinal assíncrono que normalmente ocorre quando o tubo é encerrado repentinamente sem um desligamento completo. Por exemplo, se o processo na outra extremidade do tubo sair sem ler os dados já em andamento, após a gravação desses dados já ter retornado. Se o SIGPIPE não estiver preso, normalmente faz com que o processo de recebimento seja eliminado.
Um caso de uso típico seria um processo que gera dados que são enviados para menos. Se você pressionar
q
menos, o processo de geração obterá um SIGPIPE.