Eu tenho lido sobre como os pipes são implementados no kernel do Linux e queria validar meu entendimento. Se estiver incorreto, a resposta com a explicação correta será selecionada.
- O Linux possui um VFS chamado pipefs montado no kernel (não no espaço do usuário)
- O pipefs possui um único super bloco e é montado em sua própria raiz (
pipe:
), ao lado de/
- pipefs não podem ser visualizados diretamente ao contrário da maioria dos sistemas de arquivos
- A entrada para pipefs é via
pipe(2)
syscall - O
pipe(2)
syscall usado pelos shells para canalizar com o|
operador (ou manualmente de qualquer outro processo) cria um novo arquivo nos pipefs que se comporta praticamente como um arquivo normal - O arquivo no lado esquerdo do operador de
stdout
canal é redirecionado para o arquivo temporário criado nos pipefs - O arquivo no lado direito do operador do tubo está
stdin
definido como o arquivo em pipefs - pipefs é armazenado na memória e, através de alguma mágica do kernel, não deve ser paginado
Esta é a explicação de como os tubos (por exemplo ls -la | less
) funcionam praticamente corretos?
Uma coisa que não entendo é como algo como o bash definiria um processo ' stdin
ou stdout
para o descritor de arquivo retornado por pipe(2)
. Ainda não consegui encontrar nada sobre isso.
pipe()
chamada do kernel, juntamente com o mecanismo que a suporta (pipefs
, etc), é um nível muito mais baixo do que o|
operador oferecido no seu shell. O último é geralmente implementado usando o primeiro, mas não precisa ser.|
operador está apenas chamandopipe(2)
como um processo como o bash.Respostas:
Sua análise até o momento é geralmente correta. A maneira como um shell pode definir o stdin de um processo para um descritor de canal pode ser (pseudocódigo):
fonte
dup2
chamada é necessária e você não pode apenas atribuir diretamente o descritor de pipe ao stdin?pipe()
. Adup2()
chamada permite que o chamador copie o descritor de arquivo para um valor numérico específico (necessário porque 0, 1, 2 são stdin, stdout, stderr). Esse é o equivalente do kernel de "atribuir diretamente ao stdin". Observe que a variável global da biblioteca de tempo de execução Cstdin
é aFILE *
, que não está relacionada ao kernel (embora tenha sido inicializada para ser conectada ao descritor 0).dup2
chamada não mudap[1]
. Em vez disso, ele cria as duas alçasp[1]
e0
aponta para o mesmo objeto do kernel (o pipe). Como o processo filho não precisa de dois identificadores stdin (e não saberia qual é o identificador numerado dep[1]
qualquer maneira), elep[1]
foi fechado antesexec
.