¿Por qué el controller 8250 UART no activa TTY si hay más de 256 caracteres pendientes?

¿Cuál es la motivación de esta condición if en void serial8250_tx_chars(struct uart_8250_port *up) ?

 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); 

Ha estado allí desde Linux 1.1.13 (mayo de 1994) y se repite en la mayoría de los controlleres UART.

Antecedentes: Linux personalizado 3.4.91, sistema incorporado en ARMv7, el puerto UART 0 está configurado para 38400 baudios, 16 bytes FIFO para i / o. Nada de esto puede cambiarse en nuestra configuration.

Al imprimir muy fuertemente en la console a través de UART, el buffer interno de 4kB ( UART_XMIT_SIZE ) se llena y luego detiene el process del espacio de usuario hasta que se vacía el buffer (¡lo que demora un segundo a 38400 baudios!). Entonces este comportamiento se repite. Esto se debe a que la function n_tty_write() pone a dormir cuando el búfer está lleno y no se despierta durante mucho time debido a la condición cuestionable anterior.

Lo encontraría más natural y eficiente si este cheque simplemente se eliminara. Luego, los printfs llenan el búfer lo más rápido que pueden y luego continúan a la velocidad a la que se vacía el búfer , en lugar del procesamiento de ráfaga que estoy observando.

Funciona bien en mi entorno, pero seguramente me falta algo o no entiendo nada. Debe haber una razón para la implementación actual. ¿Hay algún efecto secundario si elimino esa condición?

Como una pregunta complementaria: ¿hay opciones de configuration para ajustar este comportamiento, por ejemplo, para que printf siempre regrese inmediatamente y descarte la salida si el buffer está lleno?

Es una medida de eficiencia. La CPU funciona mucho más rápido que el serial port, y si el núcleo deja que el process del espacio de usuario se ejecute cada vez que hay un poco de espacio en el búfer, terminará haciendo un viaje al espacio de usuario y de vuelta por cada byte de datos. Eso es un desperdicio de time de CPU:

 $ time dd if=/dev/zero of=/dev/null bs=1 count=10000000 10000000+0 records in 10000000+0 records out 10000000 bytes (10 MB, 9.5 MiB) copied, 5.95145 s, 1.7 MB/s real 0m5.954s user 0m1.960s sys 0m3.992s $ time dd if=/dev/zero of=/dev/null bs=1000 count=10000 10000+0 records in 10000+0 records out 10000000 bytes (10 MB, 9.5 MiB) copied, 0.011041 s, 906 MB/s real 0m0.014s user 0m0.000s sys 0m0.012s 

La testing anterior ni siquiera está leyendo y escribiendo un dispositivo real: la diferencia de time total es la frecuencia con la que el sistema está rebotando entre el espacio de usuario y el espacio del núcleo.

Si el espacio de usuario no desea ser retenido, puede usar E / S sin locking, o puede marcar usar una llamada de select() para ver si hay espacio para escribir en el dispositivo … y si no lo está, puede volcar el rest en un buffer propio y continuar el procesamiento. Es cierto que eso complica las cosas, ya que ahora tienes un búfer que tienes que tirar … pero si usas stdio, eso es generalmente cierto de todos modos.