【发布时间】:2017-03-30 16:19:04
【问题描述】:
我正在编写一个 Linux 模块,其中我有一个循环来处理如下工作:
while (1) {
while (there's work) {
process_work
}
if (should_stop)
break
sleep // wait to be woken up
}
当工作量很大时,会导致软锁定。消息是这样的:
[ 1426.067061] BUG: soft lockup - CPU#3 stuck for 23s! [comp_wqa:2969]
[ 1426.067903] Modules linked in: testmodule(OE+) xt_CHECKSUM ipt_MASQUERADE nf_nat_masquerade_ipv4 tun ip6t_rpfilter ip6t_REJECT ipt_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw iptable_filter hwmon_vid dm_mirror dm_region_hash dm_log dm_mod snd_hda_codec_realtek snd_hda_codec_hdmi snd_hda_codec_generic intel_powerclamp coretemp intel_rapl kvm eeepc_wmi crc32_pclmul asus_wmi ghash_clmulni_intel sparse_keymap rfkill mxm_wmi aesni_intel wmi lrw snd_hda_intel gf128mul glue_helper snd_hda_codec pcspkr ablk_helper sg
[ 1426.067924] cryptd shpchp snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm tpm_infineon acpi_pad snd_timer mei_me mei snd soundcore nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables ext4 mbcache jbd2 sd_mod crc_t10dif crct10dif_generic crct10dif_pclmul crct10dif_common crc32c_intel serio_raw i915 ahci libahci libata i2c_algo_bit drm_kms_helper drm e1000e ptp pps_core i2c_core video
[ 1426.067939] CPU: 3 PID: 2969 Comm: comp_wqa Tainted: G OE ------------ 3.10.0-327.28.3.el7.x86_64 #1
[ 1426.067940] Hardware name: ASUS All Series/Z97-A, BIOS 2401 04/24/2015
[ 1426.067941] task: ffff88080f212280 ti: ffff880810a68000 task.ti: ffff880810a68000
[ 1426.067942] RIP: 0010:[<ffffffff8107e11f>] [<ffffffff8107e11f>] vprintk_emit+0x1bf/0x530
[ 1426.067946] RSP: 0018:ffff880810a6bbc0 EFLAGS: 00000246
[ 1426.067947] RAX: 0000000000000001 RBX: 0000000000000003 RCX: 0000000000000000
[ 1426.067948] RDX: 0000000000000001 RSI: ffff88083fb8f6c8 RDI: 0000000000000246
[ 1426.067948] RBP: ffff880810a6bc20 R08: 0000000000000092 R09: 0000000000007d0d
[ 1426.067949] R10: 0000000000008000 R11: ffffc90023effff8 R12: 0000000000000081
[ 1426.067950] R13: ffffffff81a08020 R14: 000000009176cc6c R15: 0000000000000000
[ 1426.067951] FS: 0000000000000000(0000) GS:ffff88083fb80000(0000) knlGS:0000000000000000
[ 1426.067951] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1426.067952] CR2: 00007f42411ff00e CR3: 000000000194a000 CR4: 00000000001407e0
[ 1426.067953] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 1426.067954] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 1426.067954] Stack:
[ 1426.067955] ffffffff81cae082 0000000000000071 0000000000000000 ffff880810a6bc40
[ 1426.067956] ffffffffa07a45a0 000000008116c24e 0000000000000246 ffff8807dfbba800
[ 1426.067958] ffff880810a70000 ffff8807dfbc5030 ffff8807dfbc4e00 ffff8807e65b3000
[ 1426.067959] Call Trace:
所以经过一番谷歌搜索后,我将代码更改为以下内容:
while (1) {
while (there's work) {
process_work
cond_resched()
}
if (should_stop)
break
sleep // wait to be woken up
}
使用此代码,软锁定发生的可能性较小。但是,它仍然发生在负载较重的情况下。我想如果这个线程长期占用cpu,那么cond_resched会放弃cpu。我想我错了。
我想知道应该如何避免软锁定,同时又不至于太闲(我希望模块处理大量工作而没有长时间的延迟)。
在考虑了更多之后,我意识到我想要的只是让一个 cpu 核心运行一个专用线程,而不会被中断。内核似乎不直接支持这一点。有一个名为watchdog_thresh 的内核参数决定了一个线程可以连续运行多少秒。我读过其他帖子表明这种软锁定是无害的。而且我现在更深入地了解,我的驱动程序的性能在很大程度上取决于单 CPU 内核的性能,因为我必须使用单线程来处理工作。
【问题讨论】:
-
@sawdust 也许我没能说清楚。在内核中,如果一个线程长时间连续运行(取决于配置,20 秒或 60 秒等),内核将打印消息说该线程已卡住 23 秒等。
-
如果您只调用
schedule()而不是cond_resched()会发生什么?或者这是否会过多地降低工作量? -
请注意,如果
CONFIG_PREEMPT被定义,cond_resched()是一个空操作。 -
@IanAbbott
schedule()会使线程进入休眠状态,需要有其他线程唤醒它,否则它将无限期休眠。 -
@IanAbbott 我不认为
cond_resched()在定义CONFIG_PREEMPT时是空操作。你能提供更多关于这方面的信息吗?
标签: linux-kernel linux-device-driver kernel-module