【问题标题】:How to implement a kernel thread that never sleeps?如何实现一个永不休眠的内核线程?
【发布时间】:2014-07-16 17:00:53
【问题描述】:

问题

我需要一个能够长时间工作而不屈服的内核线程,基本上完全按需分配一个 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 驱动程序,因此可能存在与模块相关的原因导致卸载时冻结。但是,这并没有改变我关于如何最好地实现永不休眠线程的一般问题。

【问题讨论】:

  • 有时你需要让其他东西在那个 CPU 上运行。在else 子句中尝试schedule()。只要没有其他 CPU 密集型进程试图在此 CPU 上运行,它就会快速返回。
  • @Peter else schedule() 确实修复了模块卸载时系统冻结 :) 在我原本空闲的系统上执行需要 5 到 20 微秒。但是,我正在轮询的寄存器的变化可能比这快一点(比如每 3 μs 一次),理想情况下,我希望注意到每一个变化。有没有更快的方法?

标签: linux-kernel scheduling watchdog


【解决方案1】:

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

【讨论】:

  • 我确实偶然发现了这个问题(这不是我的问题),但正在寻找一种更灵活的解决方案,即仅暂时占用一个核心而不是在启动时将其隔离。也许根本就没有……但是当我从不睡觉时,它确实起到了作用。只有当我尝试卸载我的模块时,事情才会完全崩溃。
  • @Karim 这应该是评论,而不是答案
  • @Peter 我没有足够的声誉来发表评论!
猜你喜欢
  • 2019-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多