内核模块和SCHED_RR线程的优先级

Phi*_*ipp 7 c c++ linux scheduling real-time

我有一个嵌入式Linux平台(Beagleboard,运行Angstrom Linux),连接了两个设备:

  • 通过USB连接的激光测距仪(Hokuyo UTM 30)
  • 通过SPI连接的定制外部板

我们有一个Linux内核模块,负责SPI数据传输.它有一个IRQ处理程序,在其中调用spi_async,从而导致调用异步回调方法.

我的C++应用程序包含三个线程:

  • 数据处理的主线程
  • 激光轮询线
  • 一个SPI轮询线程

我遇到的问题似乎是由上述模块如何相互作用引起的.

  • 当我关闭USB设备(激光测距仪)时,我正确接收所有SPI消息(每3ms一条消息,消息长度除以数据速率<1ms),独立于线程调度
  • 当我打开USB设备并运行我的程序时,正常的线程调度(SCHED_OTHER,优先级0,没有很好的级别设置)大约1%的消息"丢失",因为spi_async的回调方法在下一个IRQ发生时运行(我可以区别对待这种情况,以免丢失消息,所以这不是一个大问题.)
  • 打开USB设备后,我用SCHED_RR运行程序

    • 主线程的优先级= 10
    • SPI读取线程的优先级= 10
    • USB /激光轮询线程的优先级= 4

    然后我丢失了40%的消息,因为在调用spi-callback方法之前再次触发IRQ!(我仍然可以找到解决方法,但问题是我需要快速响应时间,在这种情况下无法再达到).我需要使用线程调度和激光设备,所以我正在寻找一种方法来解决这种情况.

问题1:

我的假设是IRQ处理程序和内核空间中spi_async触发的回调比用户空间中运行的任何线程(无论是SCHED_RR还是SCHED_OTHER)具有更高的优先级.这意味着在我的应用程序中转向SCHED_RR不应该减慢SPI传输速度,但这似乎非常错误.是吗?

问题2:

我怎样才能确定这里发生了什么?哪些调试辅助工具存在?(或者您可能不需要任何进一步的信息?)对我来说,主要的问题是:为什么我只在打开激光设备时才会遇到问题.USB驱动程序会消耗这么多时间吗?

-----编辑:

我做了以下观察:

spi_async的回调调用wake_up_interruptible(&mydata->readq);(with wait_queue_head_t readq;).从用户空间(我的应用程序)我调用一个函数导致poll_wait(file, &mydata->readq, wait);轮询返回用户空间调用read().

  • 当我的应用程序运行时,SCHED_OTHER我可以看到回调方法首先read()在我的内核模块中输入方法之前完成.
  • 当我的应用程序运行时,退出回调之前SCHED_RR输入了read .

这似乎证明了用户空间线程的优先级高于回调方法的上下文优先级.有没有办法改变这种行为,仍然有SCHED_RR我的应用程序的线程?

sho*_*nex 1

并非所有内核线程都有 RT 优先级。想象一下,一个需要做一些后台工作的定期唤醒线程正在被唤醒。您不希望该线程抢占您的 RT 线程。所以我想你的第一个假设是错误的。

根据您的其他问题:

  • 您的主处理循环通过队列接收 SPI 数据
  • spi 处理线程向主处理队列提供数据

看来您的主处理线程妨碍了负责 spi 数据传输的 spi 驱动程序线程。

发生的情况如下:

  • IRQ 被激发
  • spi_async 被调用,这意味着数据传输已排队,将由 spi 主驱动程序创建的线程拾取。
  • spi 主线程与您的主处理线程(激光线程)竞争,但该内核线程没有 RT 优先级,因此每次 RR 线程之一运行时它都会丢失。

您可以做的是回到正常的调度,同时使用各种 CONFIG_PREEMPT_ 选项。或者搞乱 spi 主驱动程序,以确保任何延迟的工作都以足够的优先级排队。或者甚至根本不排队。