linux内核notifier机制 linux通知链

在linux内核系统中,各个模块、子系统之间是相互独立的。Linux内核可以通过通知链机制来获取由其它模块或子系统产生的它感兴趣的某些事件。使用notifier由通知者可以传递给被通知者长整型参数与指针。在linux中有许多地方用到,比如reboot通知,cpu调频通知,网卡事件,电池低电警报等等。熟悉使用notifier有助于linux内核驱动开发。

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


其中,
1. notifier_call:通知链回调函数,由被通知方提供,第一个 参数notifier_block结构体指针,第二第三个参数分别是由call chain,也就是通知链发起者传递过来的;
2. notifier_block *next:用于链接成链表的指针;
3. priority:回调函数的优先级,一般默认为0。

何时调用到notifier_call?通常在通知链register与unregister定义文件中就有notifier call发起函数;


下面是具体应用实例:

被通知文件中:
1:在被通知链文件定义一个notifier call函数:
static int xxxx_notify(struct notifier_block *nb,
         unsigned long status, void *unused)
{
     int rc;

     if (!the_chip) {
         pr_err("not initialized\n");
         return -EINVAL;
     }

     switch (status) {
     case 0:
         pr_debug("0 received\n");
         break;
     case 1:
         pr_debug("1 received\n");

         break;
     case 2:

         break;
     default:
         pr_err("error received\n");
         break;
     }

     return 0;
};



2:定义alarm_notifier通知链,将上面定义的函数入口赋值给函数指针

notifier_call;

static struct notifier_block xxxx_notifier = {
     .notifier_call = xxxx_notify,
};



3:注册alarm_notifier通知链:
probe函数里面:
     {
     -----
     rc = xxxx_register_notifier(&alarm_notifier);
     if (rc) {
         pr_err("unable to register alarm notifier rc=%d\n", rc);
         return rc;
     ------
     }




通知文件中:

1:定义notifier register函数,提供给被通知链调用:
int xxxx_register_notifier(struct notifier_block *nb)
{
     -------
     rc = srcu_notifier_chain_register(&chip->irq_notifier_list, nb);
     -------
     return rc;
}
EXPORT_SYMBOL(xxxx_register_notifier);



2:notifier call发起的地方,这里是在中断的queue work里面调用 
srcu_notifier_call_chain(),其被内核定义在
notifier.c,注意后面的2个参数会传递给回调函数。
static void xxxx_isr_work(struct work_struct *work)
{
     struct xxxx_chip *chip
         = container_of(work, struct xxxx_chip, irq_work);
     int status;

     if (!chip)
         return;

     status = xxxx_status_read();

     srcu_notifier_call_chain(&chip->irq_notifier_list,
                         status, NULL);

}



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。