我们有一个使用内核3.14.17,PREEMPT RT的Linux系统。它是一个单核系统。
对于延迟问题,我们的应用程序将其某些线程的调度类型设置为SCHED_RR。但是,这会导致内核中的kworkers被阻塞,因为它们只在模式SCHED_OTHER中运行。这可能会导致一种优先级倒置,因为低优先级SCHED_RR线程可以阻止更高优先级SHED_RR接收来自驱动程序的数据。
正在阻止TTY驱动程序。它在函数tty_flip_buffer_push中使用工作队列。可能更多的电话,但这是我们已经确定的。
有没有办法轻松解决这个问题 - 一个依赖于kworker的RT应用程序?我们希望我们不必自己破解驱动程序/内核。 RT内核中是否存在针对此类内容的任何内核配置选项?我们可以,
如果我们不得不破解驱动程序,我们可能会给它自己的工作队列,并使用SCHED_RR kworker。
当然,任何其他解决方案也是有意义的。如果有一些新功能,我们可以升级到更高版本的内核版本。
答案 0 :(得分:0)
此行为的根本原因是tty_flip_buffer_push()
在kernel/drivers/tty/tty_buffer.c:518
中,
tty_flip_buffer_push调度异步任务。这很快就会被一个kworker线程异步执行。
但是,如果任何实时线程在系统上执行并保持繁忙,那么kworker线程很快就会执行的可能性非常小。最终,一旦RT线程放弃CPU或RT-throttling被触发,它最终可能为kworker线程提供执行的机会。
low_latency
标志。 Linux内核v3.15 tty_flip_buffer_push()
之前尊重tty端口的low_latency
标志。
如果UART驱动程序设置low_latency
标志如下(通常在其.startup()
函数中),
t->uport.state->port.tty->low_latency = 1;
然后tty_flip_buffer_push()
在当前函数调用本身的上下文中执行同步复制。因此,它会自动继承当前任务的优先级,即不会因异步调度工作任务而导致优先级倒置。
注意:如果串行驱动程序设置
low_latency
标志,则必须避免在ISR(中断上下文)中调用tty_flip_buffer_push()
。设置low_latency
标志后,tty_flip_buffer_push()
不会使用单独的工作队列,而是直接调用函数。因此,如果在中断上下文中调用,则ISR将花费更长的时间来执行。这将增加内核/系统其他部分的延迟。此外,在某些条件下(关于串行缓冲区中有多少数据可用)tty_flip_buffer_push()
可能会尝试休眠(获取互斥锁)。在Linux内核中调用ISR中的睡眠会导致kernel bug。
在tty_init()中创建一个新的工作队列。
使用create_workqueue()
创建的工作队列将为系统上的每个CPU提供1个工作线程。
struct workqueue_struct *create_workqueue(const char *name);
改为使用create_singlethread_workqueue()
创建一个包含单个kworker进程的工作队列
struct workqueue_struct *create_singlethread_workqueue(const char *name);
将翻转缓冲区命名为上述私有工作队列,而不是内核的全局全局工作队列。
int queue_work(struct workqueue_struct *queue, struct work_struct *work);
在tty_flip_buffer_push()调用的函数中将schedule_work()
替换为queue_work()
。
启动时,TTY层工作队列使用的kworker线程可以通过创建它时使用的字符串name
来识别。根据系统设计的要求,在此线程上使用chrt
设置适当的更高RT优先级。