如何实现永不休眠的内核线程?

时间:2014-07-16 17:00:54

标签: linux-kernel scheduling watchdog

问题

我需要一个内核线程能够长时间工作而不会屈服,基本上可以根据需要完全专用CPU内核:

int my_kthread(void *arg)
{
    while(!kthread_should_stop()) {
        do_some_work();
        if(sleeping_enabled) msleep(1000);
        else {
            // What to do here to avoid lockup warnings
            // and ensure system stability?
        }
    }
    return 0;
}

背景

当我正在处理的模块被加载时,线程就像这样创建:

my_task = kthread_run(&my_kthread, (void *)some_data, "My KThread")
set_cpus_allowed(my_task, *cpumask_of(10)); // Pin thread to core #10

并在卸载模块时停止:

kthread_stop(my_task);

sleeping_enabledtrue时,一切正常。

否则,在线程启动后不久,内核就会抱怨明显的锁定。 起初,我只是想避免各种警告,如

BUG: soft lockup - CPU#10 stuck for 22s!

INFO: rcu_sched detected stalls on CPUs/tasks: { 10} (detected by 15, t=30567 jiffies)

因为他们倾向于使用所有> 20核心的转储以及"锁定"是理想的行为。

我试着这样看门狗:

if(sleeping_enabled) msleep(1000);
else touch_softlockup_watchdog();

(echo 1 > /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress)结合使用 并且几乎得到了我想要的东西(一个永不休眠的线程,成功地做了我想要的,在控制台中没有垃圾邮件)。

然而,这不仅仅是解决方案"感觉像是作弊,似乎我通过占用那个核心完全打破了一些东西:当通过rmmod卸载模块时,整个系统冻结了。控制台开始定期在所有核心上转储软锁定,使用此调用跟踪:

[<ffffffff810c96b0>] ? queue_stop_cpus_work+0xd0/0xd0
[<ffffffff810c9903>] cpu_stopper_thread+0xe3/0x1b0
[<ffffffff8108639a>] ? finish_task_switch+0x4a/0xf0
[<ffffffff8169e654>] ? __schedule+0x3c4/0x700
[<ffffffff81080e98>] ? __wake_up_common+0x58/0x90
[<ffffffff810c9820>] ? __stop_cpus+0x80/0x80
[<ffffffff81077e93>] kthread+0x93/0xa0
[<ffffffff816a9724>] kernel_thread_helper+0x4/0x10
[<ffffffff81077e00>] ? flush_kthread_worker+0xb0/0xb0
[<ffffffff816a9720>] ? gs_change+0x13/0x13

与此同时,我的内核线程继续运行(正如一些控制台消息所证明的那样,它偶尔打印出来),所以它从未看到kthread_should_stop()返回true

卸载确实正常工作并在我切换到完全没有睡觉之前停止了线程。现在,我无法在不重新启动的情况下进行迭代修改。

请注意,我在这里简化了很多描述。我试图添加这样一个线程(以轮询一些硬件寄存器并记录他们的更改)到GPU驱动程序,因此可能存在依赖于模块的原因导致卸载冻结。但是,这并没有改变我关于如何最好地实现永不休眠的线程的一般性问题。

1 个答案:

答案 0 :(得分:0)

我认为这个问题类似于您的问题"whole one core dedicated to single process",请查看那里的回复。