Linux内核机制之通知链

1,637 阅读2分钟

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, 值越大, 优先级越高
};
  • 通知链类型

    1. 原子通知链: 回调函数在中断或原子上下文中运行, 不允许阻塞

      struct atomic_notifier_head {
      	spinlock_t lock;
      	struct notifier_block __rcu *head;
      };
      
    2. 可阻塞通知链: 回调函数在进程上下文运行, 允许阻塞

      struct blocking_notifier_head {
      	struct rw_semaphore rwsem;
      	struct notifier_block __rcu *head;
      };
      
    3. 原始通知链: 对回调函数无限制, 所有的锁和保护机制由调用者维护

      struct raw_notifier_head {
      	struct notifier_block __rcu *head;
      };
      
    4. 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);
        ...
    }