內核子系統相互獨立,但常需跨子系統事件通知。通知鏈提供了一種內核態的「觀察者模式」:通知鏈本質是函數指針鏈表,每個節點註冊一個回調函數。事件發生時,遍歷鏈表依次調用。僅限內核子系統間使用,不可跨越用戶態。
| 類型 | 鎖機制 | 上下文 | 阻塞 | 頭結構 |
|---|---|---|---|---|
| 原子通知鏈 | spinlock | 中斷上下文 | 不允許 | atomic_notifier_head |
| 可阻塞通知鏈 | rw_semaphore | 進程上下文 | 允許 | blocking_notifier_head |
| 原始通知鏈 | 無(調用者自管) | 無限制 | 視調用者 | raw_notifier_head |
| SRCU 通知鏈 | mutex + SRCU | 進程上下文 | 允許 | srcu_notifier_head |
核心節點結構:
struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *);
struct notifier_block *next;
int priority; // 優先級高者排前
};
notifier_chain_register() 按優先級插入回調notifier_call_chain() 遍歷執行回調返回值控制流程:NOTIFY_DONE(不關心)、NOTIFY_OK(成功)、NOTIFY_STOP_MASK(停止後續傳遞)。
static RAW_NOTIFIER_HEAD(test_chain);
int register_test_notifier(struct notifier_block *nb) { return raw_notifier_chain_register(&test_chain, nb); }
int unregister_test_notifier(struct notifier_block *nb) { return raw_notifier_chain_unregister(&test_chain, nb); }
int test_notifier_call_chain(unsigned long val, void *v) { return raw_notifier_call_chain(&test_chain, val, v); }
EXPORT_SYMBOL(register_test_notifier);
EXPORT_SYMBOL(unregister_test_notifier);
EXPORT_SYMBOL(test_notifier_call_chain);
static int test_event1(struct notifier_block *this, unsigned long event, void *ptr) { printk("Event 1: %ld\n", event); return 0; }
static int test_event2(...) { printk("Event 2: %ld\n", event); return 0; }
static int test_event3(...) { printk("Event 3: %ld\n", event); return 0; }
static struct notifier_block test_notifier1 = { .notifier_call = test_event1 };
static struct notifier_block test_notifier2 = { .notifier_call = test_event2 };
static struct notifier_block test_notifier3 = { .notifier_call = test_event3 };
static int __init reg_notifier(void) {
register_test_notifier(&test_notifier1);
register_test_notifier(&test_notifier2);
register_test_notifier(&test_notifier3);
return 0;
}
extern int test_notifier_call_chain(unsigned long val, void *v);
static int __init call_notifier(void) {
test_notifier_call_chain(1, NULL); // 觸發所有註冊回調
return 0;
}
obj-m := buildchain.o regchain.o notify.o KERNELDIR := /usr/src/linux-headers-$(shell uname -r) all: make -C $(KERNELDIR) M=$(shell pwd) modules clean: make -C $(KERNELDIR) M=$(shell pwd) clean
編譯加載:make && insmod buildchain.ko && insmod regchain.ko && insmod notify.ko
內核日誌輸出:Event 1: 1
Event 2: 1
Event 3: 1