Como os canais de E / S são implementados no kernel do Linux?

8

stdin, stdout, stderr são alguns números inteiros que indexam em uma estrutura de dados que 'sabe' quais canais de E / S devem ser usados ​​para o processo. Entendo que essa estrutura de dados é exclusiva para todos os processos. Os canais de E / S são nada além de algumas estruturas de matriz de dados com alocação dinâmica de memória?

KawaiKx
fonte
por canais de E / S, você quer dizer fluxos ou tubulações? Além disso, isso provavelmente varia de acordo com o kernel. você provavelmente precisará perguntar sobre um kernel específico.
strugee
1
@ strugee Estou falando do kernel do Linux. Eu quis dizer fluxos por canais de E / S. Como esses fluxos são implementados no linux? alguma matriz ou algo assim?
KawaiKx

Respostas:

14

Em Unix-like sistemas operacionais, os fluxos de entrada, saída e erro padrão são identificados pelos descritores de arquivos 0, 1, 2. No Linux, eles são visíveis no procsistema de arquivos em /proc/[pid]/fs/{0,1,2}. Na verdade, esses arquivos são links simbólicos para um dispositivo pseudoterminal no /dev/ptsdiretório

Um pseudoterminal (PTY) é um par de dispositivos virtuais, um mestre pseudoterminal (PTM) e um escravo pseudoterminal (PTS) (coletivamente chamado de par pseudoterminal ), que fornecem um canal IPC, semelhante a um canal bidirecional entre um programa que espera estar conectado a um dispositivo terminal e a um programa de driver que use o pseudoterminal para enviar e receber informações do programa anterior.

Um ponto importante é que o escravo pseudo-terminal aparece como um terminal comum, por exemplo, pode ser alternado entre os modos não-canônico e canônico (o padrão), no qual interpreta certos caracteres de entrada, como gerar um SIGINTsinal quando um caractere de interrupção (normalmente gerado pressionando Ctrl+ Cno teclado) é gravado no mestre pseudoterminal ou fazendo com que o próximo read()retorne 0quando um caractere de fim de arquivo (normalmente gerado por Ctrl+ D) é encontrado. Outras operações suportadas pelos terminais estão ativando ou desativando o eco, definindo o grupo de processos em primeiro plano etc.

Os pseudoterminais têm vários usos:

  • Eles permitem que programas gostem sshde operar programas orientados a terminal em outro host conectado via rede. Um programa orientado ao terminal pode ser qualquer programa que normalmente seria executado em uma sessão interativa do terminal. A entrada, saída e erro padrão de tal programa não podem ser conectados diretamente ao soquete, pois os soquetes não suportam a funcionalidade relacionada ao terminal acima mencionada.

  • Eles permitem programas como expectdirigir um programa interativo orientado ao terminal a partir de um script.

  • Eles são usados ​​por emuladores de terminal, como xtermpara fornecer funcionalidade relacionada ao terminal.

  • Eles são usados ​​por programas como screenmultiplexar um único terminal físico entre vários processos.

  • Eles são usados ​​por programas como scriptpara gravar todas as entradas e saídas que ocorrem durante uma sessão de shell.

PTYs no estilo Unix98 , usados ​​no Linux, são configurados da seguinte maneira:

  • O programa do driver abre o multiplexador mestre do pseudo-terminal em dev/ptmx, no qual recebe um descritor de arquivo para um PTM, e um dispositivo PTS é criado no /dev/ptsdiretório Cada descritor de arquivo obtido pela abertura /dev/ptmxé um PTM independente com seu próprio PTS associado.

  • Os programas do driver chamam fork()para criar um processo filho, que por sua vez executa as seguintes etapas:

    • A criança chama setsid()para iniciar uma nova sessão, da qual a criança é líder da sessão. Isso também faz com que a criança perca seu terminal de controle .

    • A criança continua a abrir o dispositivo PTS que corresponde ao PTM criado pelo programa do driver. Como a criança é líder de sessão, mas não possui terminal de controle, o PTS se torna o terminal de controle da criança.

    • A criança usa dup()para duplicar o descritor de arquivo para o dispositivo escravo nele, entrada, saída e erro padrão.

    • Por fim, a criança chama exec()para iniciar o programa orientado ao terminal que deve ser conectado ao dispositivo pseudoterminal.

Nesse momento, tudo o que o programa do driver grava no PTM aparece como entrada para o programa orientado ao terminal no PTS e vice-versa.

Ao operar no modo canônico, a entrada para o PTS é armazenada em buffer linha por linha. Em outras palavras, assim como nos terminais regulares, a leitura do programa de um PTS recebe uma linha de entrada somente quando um caractere de nova linha é gravado no PTM. Quando a capacidade do buffer estiver esgotada, outras write()chamadas serão bloqueadas até que parte da entrada tenha sido consumida.

No kernel Linux, as chamadas de sistema relacionado arquivo open(), read(), write() stat()etc. são implementados na camada Virtual sistema de arquivos (VFS), que fornece uma interface de sistema de arquivos uniforme para programas de espaço de usuário. O VFS permite que diferentes implementações do sistema de arquivos coexistam no kernel. Quando os programas de espaço do usuário chamam as chamadas de sistema mencionadas acima, o VFS redireciona a chamada para a implementação apropriada do sistema de arquivos.

Os dispositivos PTS abaixo /dev/ptssão gerenciados pela devptsimplementação do sistema de arquivos definida em /fs/devpts/inode.c, enquanto o driver TTY que fornece o ptmxdispositivo no estilo Unix98 é definido em drivers/tty/pty.c.

O buffer entre dispositivos TTY e as disciplinas de linha TTY , como pseudo-terminais, é fornecida uma estrutura de buffer mantida para cada dispositivo tty, definido eminclude/linux/tty.h

Antes da versão 3.7 do kernel, o buffer era um buffer flip :

#define TTY_FLIPBUF_SIZE 512

struct tty_flip_buffer {
        struct tq_struct tqueue;
        struct semaphore pty_sem;
        char             *char_buf_ptr;
        unsigned char    *flag_buf_ptr;
        int              count;
        int              buf_num;
        unsigned char    char_buf[2*TTY_FLIPBUF_SIZE];
        char             flag_buf[2*TTY_FLIPBUF_SIZE];
        unsigned char    slop[4];
};

A estrutura continha armazenamento dividido em dois buffers de tamanho igual. Os buffers foram numerados 0(primeira metade de char_buf/flag_buf) e 1(segunda metade). O driver armazenou dados no buffer identificado por buf_num. O outro buffer pode ser liberado para a disciplina de linha.

O buffer foi 'invertido' alternando buf_numentre 0e 1. Quando buf_numalterado, char_buf_ptre flag_buf_ptr foi definido como o início do buffer identificado por buf_num, e countfoi definido como 0.

Desde a versão 3.7 do kernel, os buffers flip TTY foram substituídos por objetos alocados por meio de kmalloc()anéis organizados . Em uma situação normal para uma porta serial acionada por IRQ em velocidades típicas, seu comportamento é praticamente o mesmo do antigo buffer de buffer; dois buffers acabam alocados e o kernel alterna entre eles como antes. No entanto, quando há atrasos ou a velocidade aumenta, a nova implementação do buffer tem um desempenho melhor, pois o buffer pool pode crescer um pouco.

Thomas Nyman
fonte
Respostas tão bem informadas como essas são extremamente difíceis de encontrar.
Étale-cohomology
-1

Nas páginas de manual de qualquer um dos três, explica a resposta:

   Under  normal circumstances every UNIX program has three streams opened
   for it when it starts up, one for input, one for output,  and  one  for
   printing diagnostic or error messages.  These are typically attached to
   the user's terminal but might instead  refer  to  files  or
   other  devices,  depending  on what the parent process chose to set up.

   The input stream is referred to as "standard input"; the output  stream
   is  referred  to as "standard output"; and the error stream is referred
   to as "standard error".  These terms are abbreviated to form  the  sym-
   bols used to refer to these files, namely stdin, stdout, and stderr.

   Each  of these symbols is a stdio(3) macro of type pointer to FILE, and
   can be used with functions like fprintf(3) or fread(3).

   Since FILEs are a buffering wrapper around UNIX file  descriptors,  the
   same  underlying  files  may  also  be accessed using the raw UNIX file
   interface, that is, the functions like read(2) and lseek(2).

   On program startup, the integer file descriptors  associated  with  the
   streams  stdin,  stdout, and stderr are 0, 1, and 2, respectively.  The
   preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are
   defined  with  these values in <unistd.h>.
Jeight
fonte
Esta resposta descreve a implementação de stdin, stdoute stderrdo ponto de vista da biblioteca C, mas a questão é explicitamente sobre a implementação do kernel. Eu tentei explicar o ponto de vista do kernel na minha resposta .
Thomas Nyman