¿Cómo se implementan los canales de E / S en el kernel de Linux?

8

stdin, stdout, stderr son algunos enteros que se indexan en una estructura de datos que 'sabe' qué canales de E / S se utilizarán para el proceso. Entiendo que esta estructura de datos es única para cada proceso. ¿Los canales de E / S no son más que algunas estructuras de matriz de datos con asignación dinámica de memoria?

KawaiKx
fuente
por canales de E / S, ¿quiere decir corrientes o tuberías? Además, esto probablemente varía según el núcleo. probablemente deba preguntar acerca de un núcleo específico.
Strugee
1
@strugee Estoy hablando del kernel de Linux. Me refería a transmisiones por canales de E / S. ¿Cómo se implementan estas transmisiones en Linux? alguna matriz o algo?
KawaiKx

Respuestas:

14

En Unix-como sistemas operativos, los flujos de entrada, salida y error estándar se identifican con los descriptores de archivo 0, 1, 2. En Linux, estos son visibles bajo el procsistema de archivos en /proc/[pid]/fs/{0,1,2}. Estos archivos son en realidad enlaces simbólicos a un dispositivo pseudoterminal en el /dev/ptsdirectorio.

Un pseudoterminal (PTY) es un par de dispositivos virtuales, un pseudoterminal master (PTM) y un pseudoterminal slave (PTS) (colectivamente denominado un par pseudoterminal ), que proporcionan un canal IPC, algo así como un tubo bidireccional entre un programa que espera para conectarse a un dispositivo terminal y a un programa de controlador que utiliza el pseudoterminal para enviar información y recibir información del programa anterior.

Un punto clave es que el esclavo pseudoterminal aparece como un terminal normal, por ejemplo, se puede alternar entre el modo no canónico y el canónico (el valor predeterminado), en el que interpreta ciertos caracteres de entrada, como generar una SIGINTseñal cuando un carácter de interrupción (normalmente generado presionando Ctrl+ Cen el teclado) se escribe en el maestro pseudoterminal o provoca que el siguiente read()regrese 0cuando se encuentra un carácter de fin de archivo (normalmente generado por Ctrl+ D). Otras operaciones compatibles con los terminales están activando o desactivando los ecos, configurando el grupo de procesos en primer plano, etc.

Los pseudoterminales tienen varios usos:

  • Permiten programas como sshoperar programas orientados a terminal en otro host conectado a través de una red. Un programa orientado a terminal puede ser cualquier programa, que normalmente se ejecutaría en una sesión de terminal interactiva. La entrada, salida y error estándar de un programa de este tipo no se pueden conectar directamente a un zócalo, ya que los zócalos no son compatibles con la funcionalidad relacionada con el terminal mencionada anteriormente.

  • Permiten programas como expectmanejar un programa interactivo orientado a terminal desde un script.

  • Los utilizan los emuladores de terminal, como xtermpara proporcionar funcionalidad relacionada con el terminal.

  • Son utilizados por programas como screenpara multiplexar una sola terminal física entre múltiples procesos.

  • Son utilizados por programas como scriptpara registrar todas las entradas y salidas que ocurren durante una sesión de shell.

Los PTY de estilo Unix98 , utilizados en Linux, se configuran de la siguiente manera:

  • El programa controlador abre el multiplexor maestro pseudo-terminal dev/ptmxen el cual recibe un descriptor de archivo para un PTM, y se crea un dispositivo PTS en el /dev/ptsdirectorio. Cada descriptor de archivo obtenido al abrir /dev/ptmxes un PTM independiente con su propio PTS asociado.

  • El controlador programa las llamadas fork()para crear un proceso secundario, que a su vez realiza los siguientes pasos:

    • El niño llama setsid()para comenzar una nueva sesión, de la cual el niño es el líder de la sesión. Esto también hace que el niño pierda su terminal de control .

    • El niño procede a abrir el dispositivo PTS que corresponde al PTM creado por el programa del controlador. Como el niño es un líder de sesión, pero no tiene un terminal de control, el PTS se convierte en el terminal de control del niño.

    • El niño utiliza dup()para duplicar el descriptor de archivo para el dispositivo esclavo en su entrada, salida y error estándar.

    • Por último, el niño llama exec()para iniciar el programa orientado a terminal que se va a conectar al dispositivo pseudoterminal.

En este punto, cualquier cosa que el programa del controlador escriba en el PTM, aparece como entrada al programa orientado a la terminal en el PTS, y viceversa.

Cuando se opera en modo canónico, la entrada al PTS se almacena línea por línea. En otras palabras, al igual que con los terminales regulares, la lectura del programa de un PTS recibe una línea de entrada solo cuando se escribe un carácter de nueva línea en el PTM. Cuando se agota la capacidad de almacenamiento en búfer, se write()bloquean más llamadas hasta que se haya consumido parte de la entrada.

En el núcleo de Linux, los archivos relacionados con las llamadas al sistema open(), read(), write() stat()etc se implementan en la capa virtual del sistema de archivos (VFS), que proporciona una interfaz de sistema de archivos uniforme para los programas de espacio de usuario. El VFS permite que diferentes implementaciones de sistemas de archivos coexistan dentro del núcleo. Cuando los programas de espacio de usuario llaman a las llamadas del sistema antes mencionadas, el VFS redirige la llamada a la implementación apropiada del sistema de archivos.

Los dispositivos PTS bajo /dev/ptsson administrados por la devptsimplementación del sistema de archivos definida en /fs/devpts/inode.c, mientras que el controlador TTY que proporciona el ptmxdispositivo de estilo Unix98 se define en drivers/tty/pty.c.

El almacenamiento en búfer entre dispositivos TTY y disciplinas de línea TTY , como pseudoterminales, proporciona una estructura de búfer mantenida para cada dispositivo tty, definida eninclude/linux/tty.h

Antes de la versión 3.7 del kernel, el búfer era un búfer invertido :

#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];
};

La estructura contenía almacenamiento dividido en dos tampones de igual tamaño. Los tampones estaban numerados 0(primera mitad de char_buf/flag_buf) y 1(segunda mitad). El controlador almacenó datos en el búfer identificado por buf_num. El otro amortiguador podría ser vaciado a la disciplina de línea.

El búfer se 'volcó' al alternar buf_numentre 0y 1. Cuando se buf_nummodificó char_buf_ptry flag_buf_ptr se estableció en el comienzo del búfer identificado por buf_numy countse estableció en 0.

Desde la versión 3.7 del núcleo, los buffers de volteo TTY se han reemplazado por objetos asignados a través de kmalloc()organizados en anillos . En una situación normal para un puerto serie controlado por IRQ a velocidades típicas, su comportamiento es prácticamente el mismo que con el antiguo búfer de volteo; dos buffers terminan asignados y el kernel cambia entre ellos como antes. Sin embargo, cuando hay retrasos o aumenta la velocidad, la nueva implementación del búfer funciona mejor ya que el grupo de búferes puede crecer un poco.

Thomas Nyman
fuente
Respuestas tan bien informadas como estas son extremadamente difíciles de obtener.
étale-cohomology
-1

De las páginas del manual para cualquiera de las tres explica la respuesta:

   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
fuente
Esta respuesta describe la implementación de stdin, stdouty stderrdesde el punto de vista de la biblioteca C, pero la pregunta es explícitamente sobre la implementación del núcleo. Traté de explicar el punto de vista del núcleo en mi respuesta .
Thomas Nyman