内核驱动中不能用C++指针操作IRQ亲和性,必须使用C语言及内核API:通过cpumask_var_t分配掩码,调用irq_set_affinity()设置,注意GFP_ATOMIC分配、CPU热插拔处理及资源释放。

内核驱动里不能直接用 C++ 指针操作 IRQ 亲和性
Linux 内核本身不支持 C++,所有驱动代码必须用 C 编写。所谓“C++ 指针”在内核上下文中是无效概念——new、delete、RTTI、异常、STL 容器等全部不可用。IRQ 亲和性管理依赖的是内核 C API,核心结构体是 struct cpumask,操作入口是 irq_set_affinity_hint() 或 irq_set_affinity(),它们接收的是 const struct cpumask *,不是裸指针。
如何正确设置 IRQ 亲和性(C 风格)
在 request_irq() 之后、或通过 sysfs 动态调整时,需构造有效的 CPU 掩码并传入。常见错误是直接传栈变量地址而未初始化掩码,或误用 cpumask_of() 返回的临时值导致悬垂引用。
-
cpumask_var_t是推荐的动态掩码类型,必须配对使用alloc_cpumask_var()和free_cpumask_var() - 设置单个 CPU:用
cpumask_clear(mask); cpumask_set_cpu(cpu_num, mask),别直接写mask->bits[0] = 1UL —— <code>struct cpumask布局与位宽随 NR_CPUS 变化 - 调用
irq_set_affinity(irq, mask)前,确保该 IRQ 支持迁移(检查irq_desc->irq_data.affinity是否非 NULL,且irqd_is_affinity_settable(&desc->irq_data)返回 true) - 返回值为
int,非零表示失败(如 -EINVAL 表示 CPU 不在线,-EBUSY 表示中断正被处理中)
为什么不能用普通指针模拟 cpumask
有人试图用 unsigned long * 指向栈数组并强转成 struct cpumask *,这在大多数配置下会崩溃或静默失效:
-
struct cpumask在 CONFIG_CPUMASK_OFFSTACK=y 时是间接结构,内部含struct cpumask *bits字段,而非内联位图 -
cpumask_test_cpu()等宏会根据编译配置展开为不同逻辑,裸指针绕过这些抽象层必然出错 - ARM64 上 NR_CPUS 可达 512,掩码占多个
unsigned long,栈分配大小易溢出或对齐失败 - 中断上下文禁止睡眠,但
alloc_cpumask_var(GFP_KERNEL)会休眠——必须用GFP_ATOMIC
实际可运行的最小片段(模块初始化阶段)
以下代码在 init_module() 中安全设置 IRQ 亲和性:
立即学习“C++免费学习笔记(深入)”;
static cpumask_var_t my_irq_affinity;
static int __init mydrv_init(void)
{
if (!alloc_cpumask_var(&my_irq_affinity, GFP_KERNEL))
return -ENOMEM;
cpumask_clear(my_irq_affinity);
cpumask_set_cpu(1, my_irq_affinity); // 绑定到 CPU 1
if (irq_set_affinity(my_irq_num, my_irq_affinity) != 0) {
pr_err("Failed to set affinity for irq %d\n", my_irq_num);
free_cpumask_var(my_irq_affinity);
return -EIO;
}
return 0;
}
注意:my_irq_num 必须来自 platform_get_irq() 或类似接口,不能硬编码;释放资源时必须在 exit_module() 中调用 free_cpumask_var(my_irq_affinity)。
真正麻烦的是热插拔 CPU 场景——亲和性掩码可能瞬间失效,需要监听 CPU_ONLINE/CPU_DOWN_PREPARE 通知并重算。这点容易被忽略,但线上系统出问题往往就在这里。



















