Этот вопрос задан на 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
Я использовал ядро 2.6.28, которое довольно старое. Флаг low_latency не нужен в новых ядрах. Водитель прекратил использовать delayed_work при передаче данных с драйвера низкого уровня в драйвер линии. https://github.com/torvalds/linux/commit/f23eb2b2b28547fc70df82dd5049eb39bec5ba12 – joshuanapoli
Хотя кажется излишним, флаг low_latency все еще присутствует в последнем ядре Linux. Он по-прежнему выглядит опасным для использования со многими низкоуровневыми драйверами. – joshuanapoli