最近在看《深入理解Linux網絡內幕》一書,學習了一下書中講到的內核通知鏈方面的知識,寫了一個讀書筆記和一點代碼來加深理解,希望能夠對大家有一點幫助。
大多數內核子系統都是相互獨立的,因此某個子系統可能對其它子系統產生的事件感興趣。爲了滿足這個需求,也即是讓某個子系統在發生某個事件時通知其它的子系統,Linux內核提供了通知鏈的機制。通知鏈表只能夠在內核的子系統之間使用,而不能夠在內核與用戶空間之間進行事件的通知。
通知鏈表是一個函數鏈表,鏈表上的每一個節點都註冊了一個函數。當某個事情發生時,鏈表上所有節點對應的函數就會被執行。所以對於通知鏈表來說有一個通知方與一個接收方。在通知這個事件時所運行的函數由被通知方決定,實際上也即是被通知方註冊了某個函數,在發生某個事件時這些函數就得到執行。其實和系統調用signal的思想差不多。
通知鏈表的節點類型爲notifier_block,其定義如下:
其中最重要的就是notifier_call這個函數指針,表示了這個節點所對應的要運行的那個函數。next指向下一個節點,即當前事件發生時還要繼續執行的那些節點。
3.註冊通知鏈
在通知鏈註冊時,需要有一個鏈表頭,它指向這個通知鏈表的第一個元素。這樣,之後的事件對該鏈表通知時就會根據這個鏈表頭而找到這個鏈表中所有的元素。
註冊的函數是:
int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n)
也即是將新的節點n加入到nl所指向的鏈表中去。
卸載的函數是:
int notifier_chain_unregister(strut notifier_block **nl, struct notifier_block *n)
也即是將節點n從nl所指向的鏈表中刪除。
4.通知鏈表
當有事件發生時,就使用notifier_call_chain向某個通知鏈表發送消息。
int notifier_call_chain(struct notifier_block **nl, unsigned long val, void *v)
這個函數是按順序運行nl指向的鏈表上的所有節點上註冊的函數。簡單地說,如下所示:
5.示例
在這裏,寫了一個簡單的通知鏈表的代碼。
代碼1 buildchain.c
它的作用是自定義一個通知鏈表test_chain,然後再自定義兩個函數分別向這個通知鏈中加入或刪除節點,最後再定義一個函數通知這個test_chain鏈。
代碼2 regchain.c
該代碼的作用是將test_notifier1 test_notifier2 test_notifier3這三個節點加到之前定義的test_chain這個通知鏈表上,同時每個節點都註冊了一個函數。
代碼3 notify.c
該代碼的作用就是向test_chain通知鏈中發送消息,讓鏈中的函數運行。
Makefile文件
運行:
這樣就可以看到通知鏈運行的效果了