Kworker线程被SCHED_RR用户空间线程阻止

时间:2016-12-05 14:59:49

标签: c++ linux multithreading linux-kernel real-time

我们有一个使用内核3.14.17,PREEMPT RT的Linux系统。它是一个单核系统。

对于延迟问题,我们的应用程序将其某些线程的调度类型设置为SCHED_RR。但是,这会导致内核中的kworkers被阻塞,因为它们只在模式SCHED_OTHER中运行。这可能会导致一种优先级倒置,因为低优先级SCHED_RR线程可以阻止更高优先级SHED_RR接收来自驱动程序的数据。

正在阻止TTY驱动程序。它在函数tty_flip_buffer_push中使用工作队列。可能更多的电话,但这是我们已经确定的。

有没有办法轻松解决这个问题 - 一个依赖于kworker的RT应用程序?我们希望我们不必自己破解驱动程序/内核。 RT内核中是否存在针对此类内容的任何内核配置选项?我们可以,

  • 为kworkers设置SCHED_RR优先级?
  • 禁用特定驱动程序的工作队列?

如果我们不得不破解驱动程序,我们可能会给它自己的工作队列,并使用SCHED_RR kworker。

当然,任何其他解决方案也是有意义的。如果有一些新功能,我们可以升级到更高版本的内核版本。

1 个答案:

答案 0 :(得分:0)

此行为的根本原因是tty_flip_buffer_push()

kernel/drivers/tty/tty_buffer.c:518中, tty_flip_buffer_push调度异步任务。这很快就会被一个kworker线程异步执行。

但是,如果任何实时线程在系统上执行并保持繁忙,那么kworker线程很快就会执行的可能性非常小。最终,一旦RT线程放弃CPU或RT-throttling被触发,它最终可能为kworker线程提供执行的机会。

较旧的内核支持TTY子系统中的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

低延迟/实时UART / TTY的自定义:

1。为TTY图层创建和使用个人工作队列。

在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);

2。使用私人工作队列。

将翻转缓冲区命名为上述私有工作队列,而不是内核的全局全局工作队列。

int queue_work(struct workqueue_struct *queue, struct work_struct *work);

在tty_flip_buffer_push()调用的函数中将schedule_work()替换为queue_work()

3。调整私有工作队列的执行优先级。

启动时,TTY层工作队列使用的kworker线程可以通过创建它时使用的字符串name来识别。根据系统设计的要求,在此线程上使用chrt设置适当的更高RT优先级。