注意:notification chain適用於內核子系統之間的信息傳遞,不涉及用戶態。
Notification chain使用發佈-訂閱模型(publish-and-subscribe model):
在事件發生時,檢測或產生事件的子系統作爲主動一方通過通知函數來告知作爲被動一方的訂閱者(對此事件感興趣的子系統)。這裏有個額外要求,訂閱一方要提供callback函數以供發佈方調用,當然,提供什麼樣的callback函數完全由訂閱方決定。訂閱者必須知道其他子系統提供了哪些事件通知支持,以選擇可以訂閱的事件通知;當然,訂
從某種意義上來說,notification chain實現了事件信息的共享
struct notifier_block結構
Notification chain由notifier block組成,其結構類型如下(include/linux/notifier.h):
struct notifier_block
{
int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
struct notifier_block *next;
int priority;
};
實際上notification chain就是一組函數列表。通常notification chain的名字的格式爲xxx_chain、xxx_notifier_chain、 xxx_notifier_list,例如reboot_notifier_list。
回調函數notifier_call
前面已經講過函數參數的含義,注意到該函數的返回值爲int類型,這裏就來看一下可能的返回
NOTIFY_DONE 0x0000 對該事件不感興趣(根據unsigned long參數)
NOTIFY_OK 0x0001 成功響應該事件
NOTIFY_STOP_MASK 0x8000 該回調函數返回後停止處理後續notifier block
NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) 出錯,回調函數返回後停止處理後續notifier block
NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) 成功響應事件,回調函數返回後停止處理後續notifier block
注意,NOTIFY_STOP和NOTIFY_BAD的定義都包含了NOTIFY_STOP_MASK。
併發訪問控制在kernel/sys.c文件中定義了對notification chain進行併發訪問控制的讀寫鎖notifier_lock。系統中對所有notification chain的併發訪問都是由該鎖來控制。子系統通常只在boot或者加載module時註冊notifier block,即修改notification chain,而大多數時間僅以只讀方式來訪問,因此一個鎖基本不會影響系統性能。
基 本 API
下面的基本例程位於kernel/sys.c文件中要接收某些事件的通知需要先註冊到支持這些事件的notification chain中:
int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
n爲當前子系統提供的notifier_block,其中指明瞭回調函數該函數會根據notifier_block的優先級priority將n插入到list中合適位置如果不想接受已訂閱事件的通知,則需要取消訂閱註冊:
int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
nl爲notification chain
n爲當前子系統提供的notifier_block當事件發生時,要通知訂閱該事件的子系統:
int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
n爲notification chain
val爲事件類型,前面提到過一個chain可能支持多個事件,該參數用來對事件進行區分
v存放特定於事件的信息該函數會遍歷chain,對chain中每個notifier block,以參數val和v調用其notifier_call函數,若notifier_call函數返回值中標誌了NOTIFY_STOP_MASK(如NOTIFY_BAD、NOTIFY_STOP),則函數停止處理,返回當前notifier block的返回值;否則返回chain中最後一個notifier block的返回值。
注意:多數子系統都定義了這些基本例程的封裝函數,因此很少看到對這些函數的直接調用。例如後面的例子中用到的register_reboot_notifier和unregister_reboot_notifier就是簡單的封裝函數。
在kernel/sys.c文件中定義了一個全局reboot_notifier_list,該chain用來掛接想在系統shutdown時執行的函數,例如進行某種清理工作。前面提到過register_reboot_notifier和unregister_reboot_notifier是對notifier_chain_register和notifier_chain_unregister簡單封裝,具體請參考實現,在此不再贅述。下面給出一個簡單的使用notification chain的例子。該模塊向reboot_notifier_list註冊了一個函數myreboot,該函數在系統reboot時會簡單地打印一些信息(在系統shutdown時也可以)注意到傳遞給myreboot的event參數值爲1,而include/linux/notifier.h文件中定義了與系統關機相關的一組事件常值,而1對應於事件SYS_DOWN。
|