2013-03-19 1 views
4

Можно ли использовать режим low_latency tty с последовательными портами Linux? Функция tty_flip_buffer_push документирована, что она «не должна вызываться из контекста IRQ, если установлен параметр port-> low_latency». Тем не менее, многие драйверы последовательного порта низкого уровня называют это из ISR независимо от того, установлен ли флаг. Например, mpc52xx driver calls flip buffer безоговорочно после каждого чтения из своего FIFO.Безопасен ли режим низкой латентности для использования с последовательными портами Linux?

Последствием буфера с низкой задержкой в ​​ISR является то, что драйвер линейной дисциплины вводится в контексте IRQ. Моя цель - получить латентность в миллисекундах или менее, считая с высокоскоростного последовательного порта mpc52xx. Установка low_latency подтверждает цель задержки, но также нарушает задокументированное предварительное условие для tty_flip_buffer_push.

+0

Я использовал ядро ​​2.6.28, которое довольно старое. Флаг low_latency не нужен в новых ядрах. Водитель прекратил использовать delayed_work при передаче данных с драйвера низкого уровня в драйвер линии. https://github.com/torvalds/linux/commit/f23eb2b2b28547fc70df82dd5049eb39bec5ba12 – joshuanapoli

+0

Хотя кажется излишним, флаг low_latency все еще присутствует в последнем ядре Linux. Он по-прежнему выглядит опасным для использования со многими низкоуровневыми драйверами. – joshuanapoli

ответ

3

Этот вопрос задан на linux-serial on Fri, 19 Aug 2011.

Нет, низкая латентность в целом небезопасна.

Однако в частном случае 3.10.5 low_latency является безопасным.

Комментарии выше tty_flip_buffer_push чтения:

"Эта функция не должна вызываться из контекста, если IRQ port-> low_latency установлен."

Однако код (3.10.5, драйверы/TTY/tty_buffer.c) противоречит этому:

void tty_flip_buffer_push(struct tty_port *port) 
{ 
    struct tty_bufhead *buf = &port->buf; 
    unsigned long flags; 

    spin_lock_irqsave(&buf->lock, flags); 
    if (buf->tail != NULL) 
      buf->tail->commit = buf->tail->used; 
    spin_unlock_irqrestore(&buf->lock, flags); 

    if (port->low_latency) 
      flush_to_ldisc(&buf->work); 
    else 
      schedule_work(&buf->work); 
} 
EXPORT_SYMBOL(tty_flip_buffer_push); 

Использование spin_lock_irqsave/spin_unlock_irqrestore делает этот код безопасным для вызова из контекста прерывания.

Существует тест для low_latency, и, если он установлен, flush_to_ldisc вызывается непосредственно. Это немедленно сбрасывает буфер переворота в линейную дисциплину за счет большей обработки прерываний. Процедура flush_to_ldisc также кодируется для обеспечения безопасности в контексте прерывания. Я предполагаю, что более ранняя версия была небезопасной.

Если low_latency is не комплект, то schedule_work называется. Вызов schedule_work - это классический способ вызова обработчика «нижняя половина» из «верхней половины» в контексте прерывания. Это приводит к вызову flush_to_ldisc из обработчика «нижняя половина» при следующем такте.

Глядя немного глубже, как комментарий, так и тест, похоже, находятся в оригинале Алана Кокса e0495736 совершение tty_buffer.c. Этот коммит был переписыванием более раннего кода, поэтому кажется, что в свое время не было теста. Тот, кто добавил тест и исправил flush_to_ldisc, чтобы быть уверенным в прерывании, не потрудился исправить комментарий.

Итак, всегда верьте коду, а не комментариям.

Однако, в том же коде в 3,12-гс * (по состоянию на 23 октября 2013 года), похоже, проблема была вновь открыта, когда spin_lock_irqsave годов в flush_to_ldisc были удалены, и были добавлены mutex_locks. То есть установка UPF_LOW_LATENCY в флажках serial_struct и вызов TIOCSSERIAL ioctl снова приведет к «планированию при атомарном».

Последнее обновление от Сопровождающего:

On 10/19/2013 07:16 PM, Jonathan Ben Avraham wrote: 
> Hi Peter, 
> "tty_flip_buffer_push" is called from IRQ handlers in most drivers/tty/serial UART drivers. 
> 
> "tty_flip_buffer_push" calls "flush_to_ldisc" if low_latency is set. 
> "flush_to_ldisc" calls "mutex_lock" in 3.12-rc5, which cannot be used in interrupt context. 
> 
> Does this mean that setting "low_latency" cannot be used safely in 3.12-rc5? 

Yes, I broke low_latency. 

Part of the problem is that the 3.11- use of low_latency was unsafe; too many shared 
data areas were simply accessed without appropriate safeguards. 

I'm working on fixing it but probably won't make it for 3.12 final. 

Regards, 
Peter Hurley 

Итак, похоже, что вы не должны зависеть от low_latency, если вы не уверены, что вы никогда не собираетесь менять свое ядро ​​от версии, которая поддерживает его.


обновление: 18 февраля 2014, ядро ​​3.13.2

Станислав Грушка писал:

Hi, 

setserial has low_latency option which should minimize receive latency 
(scheduler delay). AFAICT it is used if someone talk to external device 
via RS-485/RS-232 and need to have quick requests and responses . On 
kernel this feature was implemented by direct tty processing from 
interrupt context: 

void tty_flip_buffer_push(struct tty_port *port) 
{ 
    struct tty_bufhead *buf = &port->buf; 

    buf->tail->commit = buf->tail->used; 

    if (port->low_latency) 
      flush_to_ldisc(&buf->work); 
    else 
      schedule_work(&buf->work); 
} 

But after 3.12 tty locking changes, calling flush_to_ldisc() from 
interrupt context is a bug (we got scheduling while atomic bug report 
here: https://bugzilla.redhat.com/show_bug.cgi?id=1065087) 

I'm not sure how this should be solved. After Peter get rid all of those 
race condition in tty layer, we probably don't want go back to use 
spin_lock's there. Maybe we can create WQ_HIGHPRI workqueue and schedule 
flush_to_ldisc() work there. Or perhaps users that need to low latency, 
should switch to thread irq and prioritize serial irq to meat 
retirements. Anyway setserial low_latency is now broken and all who use 
this feature in the past can not do this any longer on 3.12+ kernels. 

Thoughts ? 

Stanislaw 
1

патч был разнесен LKML для решения этой проблемы. Он удаляет общий код для обработки low_latency, но сохраняет параметр для низкоуровневых драйверов.

http://www.kernelhub.org/?p=2&msg=419071

Я попытался принуждая low_latency на Linux 3.12 с последовательной консоли. Ядро было очень неустойчивым. Если preemption был включен, он будет висеть после нескольких минут использования.

Таким образом, ответ на этот вопрос заключается в том, чтобы держаться подальше.

Смежные вопросы