Linux核心機制之通知鏈
阿新 • • 發佈:2021-12-14
linux
核心中的事件通知鏈主要用於各模組之間的存在依賴, 用於事件的通知. 通知鏈只能用於核心空間之間的各模組之間, 不能用於核心空間和使用者空間的之間. 事件通知鏈就是在特定的事件發生後, 通過回撥函式去主動通知接受方. 核心程式碼在kernel-4.14/kernel/notifier.c
, 標頭檔案kernel-4.14/include/linux/notifier.h
通知鏈的核心資料結構:
struct notifier_block { notifier_fn_t notifier_call; //通知鏈要執行的回撥函式 struct notifier_block __rcu *next; //連線其他的通知鏈, 形成連結串列 int priority; //這個通知的優先順序, 預設0, 值越大, 優先順序越高 };
-
通知鏈型別
-
原子通知鏈: 回撥函式在中斷或原子上下文中執行, 不允許阻塞
struct atomic_notifier_head { spinlock_t lock; struct notifier_block __rcu *head; };
-
可阻塞通知鏈: 回撥函式在程序上下文執行, 允許阻塞
struct blocking_notifier_head { struct rw_semaphore rwsem; struct notifier_block __rcu *head; };
-
原始通知鏈: 對回撥函式無限制, 所有的鎖和保護機制由呼叫者維護
struct raw_notifier_head { struct notifier_block __rcu *head; };
-
SRCU
通知鏈: 可阻塞通知鏈變體struct srcu_notifier_head { struct mutex mutex; struct srcu_struct srcu; struct notifier_block __rcu *head; };
-
-
操作函式
-
定義鏈頭以及初始化
#define ATOMIC_NOTIFIER_HEAD(name) 原子通知鏈 #define BLOCKING_NOTIFIER_HEAD(name) 可阻塞通知鏈 #define RAW_NOTIFIER_HEAD(name) 原始通知鏈
-
註冊/解除安裝 通知鏈
//註冊 extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *nb); extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *nb); extern int raw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *nb); extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *nb); extern int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh, struct notifier_block *nb); //解除安裝 extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *nb); extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, struct notifier_block *nb); extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh, struct notifier_block *nb); extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, struct notifier_block *nb);
-
通知函式/回撥函式
extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v); extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v); extern int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v); extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v);
-
-
事例
馬達和
camera
的模組是分開的, 現在有一個需求: 在camera open/close
, 需要把camera
當前的狀態發給馬達的驅動模組. 我們可以通過事件通知鏈來實現,camera
是事件通知方, 馬達是事件接受方imgsensor.c
---camera
... extern int camera_notifier_call_chain(unsigned long val, void *v); MINT32 imgsensor_sensor_open(struct IMGSENSOR_SENSOR *psensor) { ... if (IMGSENSOR_SENSOR_IDX_MAIN == psensor_inst->sensor_idx) camera_notifier_call_chain(IMGSENSOR_STATE_OPEN, NULL); ... } MINT32 imgsensor_sensor_close(struct IMGSENSOR_SENSOR *psensor) { ... if (IMGSENSOR_SENSOR_IDX_MAIN == psensor_inst->sensor_idx) camera_notifier_call_chain(IMGSENSOR_STATE_CLOSE, NULL); ... }
main_lens.c
---- 馬達模組#include <linux/notifier.h> ... static struct notifier_block af_notifier; static BLOCKING_NOTIFIER_HEAD(af_notifier_list); static int camera_status_notice_callback(struct notifier_block *nb, unsigned long val, void *data) { int ret = NOTIFY_OK; back_camera_opened = !!val; switch(back_camera_opened) { case 0: //back camera close //do soming break; case 1: //back camera open //do soming break; default: ret = NOTIFY_BAD; printk("[%s], camera status error!!!. \n", __func__); break; } return ret; } int camera_notifier_call_chain(unsigned long val, void *v) { return blocking_notifier_call_chain(&af_notifier_list, val, v); } EXPORT_SYMBOL(camera_notifier_call_chain); static inline int Register_AF_CharDrv(void) { ... af_notifier.notifier_call = camera_status_notice_callback; blocking_notifier_chain_register(&af_notifier_list, &af_notifier); ... } static inline void Unregister_AF_CharDrv(void) { ... blocking_notifier_chain_unregister(&af_notifier_list, &af_notifier); ... }
-
擴充套件
以上是一個通知方一個接收方的處理, 那多個接收方該如何實現都通知到?
我們需要在寫一個通知塊, 將之加入定義好的連結串列上
main_lens.c
#include <linux/notifier.h> ... static BLOCKING_NOTIFIER_HEAD(af_notifier_list); /* ------------------------第一個通知塊----------------------------------------------------- */ static struct notifier_block af_notifier; static int camera_status_notice_callback(struct notifier_block *nb, unsigned long val, void *data) { int ret = NOTIFY_OK; back_camera_opened = !!val; switch(back_camera_opened) { case 0: //back camera close //do soming break; case 1: //back camera open //do soming break; default: ret = NOTIFY_BAD; printk("[%s], camera status error!!!. \n", __func__); break; } return ret; } /*---------------------------------------------------------------------------------------- */ /* ------------------------第二個通知塊----------------------------------------------------- */ static struct notifier_block module_notifier = { .notifier_call = module_notice_callback, .priority = 5, }; static int module_notice_callback(struct notifier_block *nb, unsigned long val, void *data) { .... //do soming } /*--------------------------------------------------------------------------------------- */ int camera_notifier_call_chain(unsigned long val, void *v) { return blocking_notifier_call_chain(&af_notifier_list, val, v); } EXPORT_SYMBOL(camera_notifier_call_chain); static inline int Register_AF_CharDrv(void) { ... af_notifier.notifier_call = camera_status_notice_callback; blocking_notifier_chain_register(&af_notifier_list, &af_notifier); blocking_notifier_chain_register(&af_notifier_list, &module_notifier); //第二個通知塊 ... } static inline void Unregister_AF_CharDrv(void) { ... blocking_notifier_chain_unregister(&af_notifier_list, &af_notifier); blocking_notifier_chain_unregister(&af_notifier_list, &module_notifier); ... }