背景
在做内核开发的过程中,多模块的开发是十分常见的,模块与模块之间的信息交互也是不可避免的,其中NotifierChain的机制比较好的进行了解耦,而不是直接模块间提供函数进行调用;
涉及到的结构体与宏
包含头文件
确保包含了正确的头文件,一般需要包含 linux/notifier.h
。
#include <linux/notifier.h>
//宏
RAW_NOTIFIER_HEAD(...)
//结构体
struct notifier_block;
//函数 -- 这里暂时只介绍无锁的注册与注销
raw_notifier_chain_register(...)
raw_notifier_chain_unregister(...)
用法模块划分
消息中转者
struct RAW_NOTIFIER_HEAD(middle_chain);
//需要暴露如下接口提供给消息消费者使用
int demo_listener_register_notifier(struct notifier_block *nb)
{
return raw_notifier_chain_register(&middle_chain, nb);
}
EXPORT_SYMBOL(demo_listener_register_notifier);
int demo_listener_unregister_notifier(struct notifier_block *nb)
{
return raw_notifier_chain_unregister(&middle_chain, nb);
}
EXPORT_SYMBOL(demo_listener_unregister_notifier);
//暴露如下接口提供给消息生产者使用
int demo_producer_notifier_call_chain(long val, void *v)
{
return raw_notifier_call_chain(&middle_chain, val, v);
}
通知消息生产者
#define DEMO_TYPE 1
static void ANY_func(...) {
struct demo_st d = {...};
//完成通知DEMO_TYPE消息的创建与发布
demo_producer_notifier_call_chain(DEMO_TYPE, &d);
}
通知消息消费者
static struct notifier_block listener = {
.notifier_call = demo_callback,
.priority = NOTIFY_PRIO_PBR,
};
static int demo_callback(struct notifier_block *nb, long type, void *arg)
{
//TODO
return NOTIFY_OK;
};
static int listener_module_init(...) {
demo_listener_register_notifier(&listener);
}
注意事项
-
线程安全:
raw_notifier_chain_register
和raw_notifier_chain_unregister
不是线程安全的,所以在多线程环境下使用时需要注意同步。 -
返回值检查:
确保检查raw_notifier_chain_register
的返回值,以确定注册操作是否成功。 -
生命周期管理:
确保在模块卸载或其他适当的时机调用raw_notifier_chain_unregister
解除注册,以避免内存泄漏或野指针问题。ret = raw_notifier_chain_unregister(&my_notifier_chain, &my_notifier); if (ret) { printk(KERN_ERR "Failed to unregister notifier\n"); }
类似接口
除了 raw_notifier_chain_register
之外,还有其他类型的 notifier chain,可以根据不同的需求选择合适的接口:
-
atomic_notifier_chain_register:
用于需要原子操作的通知链。int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *n); int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *n);
-
blocking_notifier_chain_register:
用于阻塞通知链,适用于可能需要睡眠的情况。int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *n); int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, struct notifier_block *n);
-
srcu_notifier_chain_register:
使用 SRCU(Sleepable Read-Copy Update)机制的通知链,适用于复杂同步要求的情况。int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *n); int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, struct notifier_block *n);
关键字
通知 消息机制 监听者