这个问题是在linux-serial 于 2011 年 8 月 19 日星期五 http://thread.gmane.org/gmane.linux.serial/5797/focus=5803.
不,低延迟通常并不安全。
然而,在 3.10.5 的特殊情况下low_latency
是安全的。
上面的评论tty_flip_buffer_push
read:
“如果设置了 port->low_latency,则不得从 IRQ 上下文调用此函数。”
然而,代码(3.10.5,drivers/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
例程也被编码为可以在中断上下文中安全使用。我猜早期版本不安全。
If low_latency
is not设置,然后schedule_work
叫做。呼唤schedule_work
是在中断上下文中从“上半部”调用“下半部”处理程序的经典方法。这导致flush_to_ldisc
在下一个时钟周期从“下半部分”处理程序调用。
深入一点看,评论和测试似乎都是 Alan Cox 的原著e0495736
提交tty_buffer.c
。这次提交是对早期代码的重写,因此似乎一度没有进行测试。谁添加了测试并修复了flush_to_ldisc
为了保证中断安全,没有费心去修复评论。
所以,永远相信代码,而不是注释。
However,在 3.12-rc* 中的相同代码中(截至 2013 年 10 月 23 日),当删除了 flash_to_ldisc 中的 spin_lock_irqsave 并添加了 mutex_locks 时,问题似乎再次出现。也就是说,在serial_struct标志中设置UPF_LOW_LATENCY并调用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
除非您确定永远不会更改支持它的内核版本。
更新:2014年2月18日,内核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