低延迟模式与 Linux 串行端口一起使用是否安全?

2024-01-21

在 Linux 串行端口上使用 low_latency tty 模式是否安全?这tty_flip_buffer_push https://github.com/torvalds/linux/blob/master/drivers/tty/tty_buffer.c#L512函数被记录为“如果设置了 port->low_latency,则不得从 IRQ 上下文调用”。尽管如此,许多低级串行端口驱动程序都会从​​ ISR 中调用它,无论是否设置了该标志。例如,mpc52xx 驱动程序调用翻转缓冲区 https://github.com/torvalds/linux/blob/master/drivers/tty/serial/mpc52xx_uart.c#L1002每次从 FIFO 读取后无条件执行。

ISR 中低延迟翻转缓冲区的结果是线路规则驱动程序被输入到 IRQ 上下文中。我的目标是从高速 mpc52xx 串行端口读取时获得一毫秒或更短的延迟。设置 low_latency 可以实现延迟目标,但它也违反了 tty_flip_buffer_push 记录的前提条件。


这个问题是在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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

低延迟模式与 Linux 串行端口一起使用是否安全? 的相关文章

  • 在 Linux 中获取指向结构设备的指针哪种更干净?

    我需要获得一个指向在linux 中注册的特定设备的指针 简而言之 该设备代表了mii bus目的 问题是这个设备似乎不属于总线 它的dev gt bus is NULL 所以我不能使用这个函数bus for each dev 然而 该设备是
  • 无序执行会导致推测内存访问吗?

    当无序处理器遇到类似情况时 LOAD R1 0x1337 LOAD R2 R1 LOAD R3 0x42 假设所有访问都会导致缓存未命中 处理器是否可以在请求 R1 甚至 0x1337 的内容之前向内存控制器请求 0x42 的内容 如果是这
  • Linux Kernel 4.2中如何获取当前进程的UID和EUID?

    正如 LDD3 第 6 章 p175 所示 我们可以通过以下方式获取当前进程 UID 和 EUIDcurrent gt uid and current gt euid 但定义struct task structLinux Kernel 4
  • 使用用户定义或 python 命令序列的 C++ 线程不会在 gdb 异步模式下停止

    我在嵌入式 powerpc 目标上使用 gdb 7 4 1 对使用 pthread 的多线程 C 程序执行一些分析 我的最终目标是使用 python 编写 gdb 脚本来自动化一些常见的分析功能 问题是 当我单独运行命令与在 gdb 用户定
  • 在 Linux 终端应用程序中接收按键按下和按键释放事件

    我想编写一个简单的 C 程序 它将根据 key down 和 key up 事件执行不同的操作 该程序将从内部运行rxvt http en wikipedia org wiki Rxvt 我应该使用什么库或机制来访问按键和释放 读书是真的吗
  • 抢占的中断处理程序会发生什么?

    即使在一些写得很好的内核书籍中 我也找不到以下问题的正确答案 他们说 ISR 无法休眠 因为它无法重新调度 ISR 因为它没有与任何进程连接 那么当更高优先级的中断抢占正在执行的中断时会发生什么 中断的 ISR 不会再次重新调度 执行 如果
  • 如何在Power 8或PPC64机器上安装pytorch?

    我正在尝试安装pytorch using conda on Power 8 IBM 机器 虽然 我读过来自IBM blog https developer ibm com tutorials install pytorch on power
  • 从内核空间到用户空间的事件通知

    当内核空间发生事件时如何通知用户空间应用程序 当数据到达某个 GPIO 时 硬件会生成中断 该数据被复制到内核缓冲区 此时 我希望驱动程序通知应用程序它可以调用read函数将数据从内核缓冲区复制到用户空间缓冲区 我想用epoll方法 但是e
  • 通过 getauxval 检测 Power8 核心加密?

    我使用的是 GCC112 它是运行 Linux 的小端 Power8 机器 Power8有核心加密 https www ibm com developerworks library se power8 in core cryptograph
  • sys_open 是如何工作的?

    我编写了一个简单的字符设备驱动程序 mydev 其中包含 打开 文件操作 在用户空间应用程序中 我打开这个驱动程序节点 使用 open dev mydev O RDONLY open 系统调用内部调用sys open 我只想知道 sys o
  • 在用户空间中启用写组合 IO 访问

    我有一个带有用户空间驱动程序的 PCIe 设备 我通过 BAR 向设备写入命令 这些命令对延迟敏感并且数据量很小 64 字节 因此我不想使用 DMA 如果我使用以下命令重新映射内核中 BAR 的物理地址ioremap wc然后将64字节写入
  • 类似于 ftrace 打印 CPU 编号

    我想打印当前进程或函数正在执行的 CPU 编号 类似于 ftrace 如下所示 TASK PID CPU TIMESTAMP FUNCTION
  • 添加条目到task_struct并初始化为默认值

    我想添加一个条目到进程控制块结构 task struct 让我们说一种标记某些进程的方法 我想将除 一些特殊进程 之外的所有进程的该字段初始化为 0 稍后通过调用sched setscheduler 我将为 特殊进程 设置此标志 有谁知道如
  • 添加 request_mem_region 后,我的驱动程序每次第一次访问都会失败,并显示“忙”消息

    好吧 这对我来说真的很奇怪 我有一个模拟的 CAN 总线驱动程序 它是一个 Linux 内核模块 然后我有一个在用户空间中运行的测试应用程序 它通过打开文件描述符并发送来访问驱动程序ioctl 消息 现在 CAN 总线驱动程序只是我一直采用
  • Linux 内核中的 DMA 映射和 DMA 引擎是什么?

    Linux 内核中的 DMA 映射和 DMA 引擎是什么 DMA映射API和DMA引擎API何时可以在Linux设备驱动程序中使用 任何真正的 Linux 设备驱动程序示例作为参考都会很棒 Linux 内核中的 DMA 映射和 DMA 引擎
  • 环形缓冲区和 DMA

    我试图了解从数据包到达网卡到目标应用程序收到数据包之间发生的所有事情 假设 缓冲区足够大 可以容纳整个数据包 我知道情况并非总是如此 但我不想介绍太多技术细节 一种选择是 1 Packet reaches the NIC 2 Interru
  • 自动持有自旋锁时返回是否不安全?

    受人尊敬的书说 The flags参数传递给spin unlock irqrestore必须与传递给的变量相同spin lock irqsave 您还必须致电spin lock irqsave and spin unlock irqrest
  • 在Linux伪终端中执行从一个终端发送到另一个终端的字符串

    假设我有一个终端 其中 tty 的输出是 dev pts 2 我想从另一个终端向第一个终端发送命令并执行它 使用 echo ls gt dev pts 2 仅在第一个终端中打印 ls 有没有办法执行字符串 不 终端不执行命令 它们只是数据的
  • 将 mmap 内核启动参数保留的内存映射到用户空间

    正如中所讨论的this https stackoverflow com q 1911473 143897问题 我在启动时使用内核启动参数保留一个内存块memmap 8G 64G 我写了一个字符驱动程序 http pete akeo ie 2
  • 树莓派的设备树驱动内核

    我想用设备树驱动的 Linux 内核启动树莓派 有什么特别的事情要做吗 谁能指出为树莓派设置基于设备树的内核启动需要什么 我可能需要有树莓派内核源代码 其中设备驱动程序应与设备树兼容 如果是这样 我在哪里可以找到 Raspberry Pi

随机推荐