notifier通知鏈機制

1. 目的

Linux內核中各個子系統相互依賴,當其中某個子系統狀態發生改變時,就必須使用一定的機制告知使用其服務的其他子系統,以便其他子系統採取相應的措施。爲滿足這樣的需求,內核實現了事件通知鏈機制(notificationchain)。

2. 範圍

通知鏈只能用在各個子系統之間,而不能在內核和用戶空間進行事件的通知。

3. 代碼位置

組成內核的核心繫統代碼均位於kernel目錄下,通知鏈表位於kernel/notifier.c中,對應的頭文件爲include/linux/notifier.h。

4. 被通知數據結構

notifier_block是通知鏈中的主要結構:

struct notifier_block {
    int (*notifier_call)(struct notifier_block *, unsigned long, void *);
    struct notifier_block *next;
    int priority;
};

其中,
a. notifier_call:當相應事件發生時應該調用的函數,由被通知方提供;
b. notifier_block *next:用於鏈接成鏈表的指針;
c. priority:回調函數的優先級,一般默認爲0;

5. 通知鏈數據結構

圍繞核心數據結構notifier_block,內核定義了四種通知鏈類型:
a. 原子通知鏈( Atomic notifier chains ):通知鏈元素的回調函數(當事件發生時要執行的函數)在中斷或原子操作上下文中運行,不允許阻塞。對應的鏈表頭結構:

struct atomic_notifier_head {
    spinlock_t  lock;
    struct  notifier_block *head;
};

b. 可阻塞通知鏈( Blocking notifier chains ):通知鏈元素的回調函數在進程上下文中運行,允許阻塞。對應的鏈表頭:

struct  blocking_notifier_head {
    struct  rw_semaphore  rwsem;
    struct  notifier_block   *head;
};

c. 原始通知鏈( Raw notifierchains ):對通知鏈元素的回調函數沒有任何限制,所有鎖和保護機制都由調用者維護。對應的鏈表頭:

struct  raw_notifier_head {
    struct  notifier_block   *head;
};

d. SRCU 通知鏈( SRCU notifier chains ):可阻塞通知鏈的一種變體。對應的鏈表頭:

struct  srcu_notifier_head {
    struct  mutex mutex;
    struct  srcu_struct  srcu;
    struct  notifier_block  *head;
};

6. 使用過程

a. 通知方先初始化一個通知鏈;
b. 被通知方申明一個notifier_block;
c. 被通知方實現notifier_call函數;
d. 被通知方調用特定的事件通知鏈的註冊函數,將notifier_block註冊到通知方的通知鏈中。特定的註冊函數包括:

int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *n)
int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *n)
int raw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *n)
int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *n)

e. 當通知方狀態變化時,調用對應的notifier_call_chain函數通知其他子系統,對應的notifier_call_chain包括:

int atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v)
int blocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v)
int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v)
int srcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v)

f. 被通知方執行notifier_block函數;

7. 關於notifier_block函數的返回值

notifier_block的返回值是NOTIFY_XXX的形式,在include/linux/notifier.h中:

#define NOTIFY_DONE 0x0000 /* 對事件視而不見 */
#define NOTIFY_OK 0x0001 /* 事件正確處理 */
#define NOTIFY_STOP_MASK 0x8000 /*由notifier_call_chain檢查,看繼續調用回調函數,還是停止,_BAD和_STOP中包含該標誌 */
#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /*事件處理出錯,不再繼續調用回調函數 */
/*
 *Clean way to return from the notifier and stop further calls.
 */
#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) /*  回調出錯,不再繼續調用該事件回調函數 */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章