notifier是kernel的一种异步通信机制,用于告知某些模块产生了一个事件event。

notifier涉及:

1,publisher,类比于server、provider等概念,负责:

  • 提供一个notifier head链表供subscriber注册handler
  • 遍历head链表逐一告知subscriber发生了某个事件

2,subscriber,类比于client、consumer等概念,接收到publisher的事件通知后开行自己的工作

实例:
kernel中针对reboot提供了一个notifier:

notifier.h (include\linux)
extern struct blocking_notifier_head reboot_notifier_list;sys.c (kernel)
/***    register_reboot_notifier - Register function to be called at reboot time*   @nb: Info about notifier function to be called*/
int register_reboot_notifier(struct notifier_block *nb)

接下来我们实现一个自己的notifier来接收reboot事件:

static int mynotifier_fn(struct notifier_block *nb, unsigned long action, void *data)
{printk("%s action: %d\n", __func__, action);return NOTIFY_OK;
}static struct notifier_block mynotifier = {.notifier_call = mynotifier_fn,
};static int mynotifier_init(void)
{printk("%s enter\n", __func__);return register_reboot_notifier(&mynotifier);
}late_initcall(mynotifier_init);

reboot后将会接收到这个reboot通知,在handler函数中这里仅仅打印了下action值:

详细资料,参考:

The Crux of Linux Notifier Chains

Linux is monolithic like any other kernel. Its subsystems or modules help to keep the kernel light by being flexible enough to load and unload at runtime. In most cases, the kernel modules are interconnected to one another. An event captured by a certain module might be of interest to another module. For instance, when a USB device is plugged to your kernel, the USB core driver has to communicate to the bus driver sitting at the top. This will allow the bus driver to take care of the rest. Another classic example would be of interfaces. Many kernel modules would be looking for a network interface state change. The lower level module that detects the network interface state change, would communicate this information to the other modules.

Typically, communication systems implement request-reply messaging, or polling. In such models, a program that receives a request will have to send the data available since the last transaction. Such methods sometimes require high bandwidth or they waste polling cycles.

Linux uses a notifier chain, a simple list of functions that is executed when an event occurs. These notifier chains work in a publish-subscribe model. This model is more effective when compared to polling or the request-reply model. In a publish-subscribe model, the ‘client’ (subscriber) that requires notification of a certain event, ‘registers’ itself with the ‘server’ (publisher). The server will inform the client whenever an event of interest occurs. Such a model reduces the bandwidth requirement or the polling cycle requirement, as the client no longer requests for new data regularly.

Notifier chains

Linux uses notifier chains to inform asynchronous events or status, through the function calls registered. The data structure is defined in include/linux/notifier.h:

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

The notifier data structure is a simple linked list of function pointers. The function pointers are registered with ‘functions’ that are to be called when an event occurs. Each module needs to maintain a notifier list. The functions are registered to this notification list.

The notification module (publisher) maintains a list head that is used to manage and traverse the notifier block list. The function that subscribes to a module is added to the head of the module’s list by using the xxxxxx_notifier_chain_register API and deletion from the list is done using xxxxxx_notifier_chain_unregister.

When an event occurs which is of interest to a particular list, then thexxxxxx_notifier_call_chain API is used to traverse the list and service the subscribers. The ‘xxxxxx_’ in the above APIs represents the type of notifier chains.

Let us now look at the different types of notifier chains in the following section.

Types of notifier chains

Notifier chains are broadly classified based on the context in which they are executed and the lock/protect mechanism of the calling chain. Based on the need of the module, the notifiers can be executed in the process context or interrupt/atomic context. Thus, notifier chains are classified into four types:

  • Atomic notifier chains: As the name indicates, this notifier chain is executed in interrupt or atomic context. Normally, events that are time critical, use this notifier. This also means it is a non-blockable call. Linux modules use atomic notifier chains to inform watchdog timers or message handlers. For example,register_keyboard_notifier uses atomic_notifier_chain_register to get called back on keyboard events. This notifier is usually called from the interrupt context.
  • Blocking notifier chains: A blocking notifier chain runs in the process context. The calls in the notification list could be blocked as it runs in the process context. Notifications that are not highly time critical could use blocking notifier chains. Linux modules use blocking notifier chains to inform the modules on a change in QOS value or the addition of a new device. For example, usb_register_notify usesblocking_notifier_chain_register to inform either USB devices or buses being added or removed.
  • Raw notifier chains: A raw notifier chain does not manage the locking and protection of the callers. Also, there are no restrictions on callbacks, registration, or de-registration. It provides flexibility to the user to have individual lock and protection mechanisms. Linux uses the raw notifier chain in low-level events. For example,register_cpu_notifier uses raw_notifier_chain_register to pass on CPU going up/down information.
  • SRCU notifier chains: Sleepable Read Copy Update (SRCU) notifier chains are similar to the blocking notifier chain and run in the process context. It differs in the way it handles locking and protection. The SRCU methodology brings in less overhead when we notify the registered callers. On the flip side, it consumes more resource while unregistering. So it is advisable to choose this methodology where we use the notifier call often and where there’s very little requirement for removing from the chain. For example, Linux module uses srcu_notifier_chain_register in CPU frequency handling.

    Using notifier chains

    Let us consider two modules: a publisher and a subscriber. The publisher module has to maintain and export a ‘notification head’. Generally, this is exported through an interface function that helps the subscriber to register itself with the publisher. The subscriber has to provide a callback function through notifier_block. Let us now look at how a publisher and a subscriber work using blocking notifier chains.

    Assume a scenario in which an action needs to be taken by a module when a USB device is plugged into the kernel. Any USB activity is first detected by the USB core of the Linux kernel. The USB core has to ‘publish’ a notification list head to inform new USB devices of activity in the kernel. Thus the USB core becomes the publisher.

    The USB core publishes its notification list through the following interface function and the notifier list data structure (snippet of drivers/usb/core/notify.c file):

    18 static BLOCKING_NOTIFIER_HEAD(usb_notifier_list);1920 /**21  * usb_register_notify - register a notifier callback whenever a usb change happens22 * @nb: pointer to the notifier block for the callback events.23 *24 * These changes are either USB devices or busses being added or removed.25 */26 void usb_register_notify (struct notifier_block *nb)27 {28       blocking_notifier_chain_register (&usb_notifier_list, nb);29 }30 EXPORT_SYMBOL_GPL(usb_register_notify);

    The first step of the publisher is to provide a notifier list. The usb_notifier_list is declared as the notifier list head for the USB notification. An interface function that exports the USB notification list is also provided by the USB core. It is a better programming practice to provide an interface function than exporting a global variable.

    Now, we can see how to write an example USB hook module that ‘subscribes’ to the USB core. The first step is to declare a handler function and initialise it to anotifier_block type variable. In the following example (a sample usbhook.c file),usb_notify is the handler function and it is initialised to a notifier_block type variable usb_nb.

    /** usbhook.c - Hook to the usb core*/
    #include <linux /module.h>
    #include </linux><linux /kernel.h>
    #include </linux><linux /usb.h>
    #include </linux><linux /notifier.h>static int usb_notify(struct notifier_block *self, unsigned long action, void *dev)
    {printk(KERN_INFO “USB device added n”);switch (action) {case USB_DEVICE_ADD:printk(KERN_INFO “USB device added n”);break;case USB_DEVICE_REMOVE:printk(KERN_INFO “USB device removed n”);break;case USB_BUS_ADD:printk(KERN_INFO “USB Bus added n”);break;case USB_BUS_REMOVE:printk(KERN_INFO “USB Bus removed n”);}return NOTIFY_OK;
    }
    static struct notifier_block usb_nb = {.notifier_call =        usb_notify,
    };
    int init_module(void)
    {printk(KERN_INFO “Init USB hook.n”);/*
    * Hook to the USB core to get notification on any addition or removal of USB devices*/usb_register_notify(&usb_nb);return 0;
    }void cleanup_module(void)
    {/** Remove the hook*/usb_unregister_notify(&usb_nb);printk(KERN_INFO “Remove USB hookn”);
    }MODULE_LICENSE(“GPL”);

    The above sample code registers the notifier_block usb_nb using the interface function of the USB core. The interface function adds the usbhook function to theusb_notifier_list of the USB core. Now we are set to receive the notification from the USB core.

    When a USB device is attached to the kernel, the USB core detects it and uses theblocking_notifier_call_chain API to call the registered subscribers:

    60 void usb_notify_add_bus(struct usb_bus *ubus)
    61 {
    62    blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
    63 }

    This blocking_notifier_call_chain will call the usb_notify function of the
    USB hook registered in usb_notifier_list.

    The above sample briefs you on the infrastructure of Linux blocking notifier chains. The same methodology can be used for other types of notifier chains.

    Linux kernel modules are loosely coupled and get loaded and unloaded runtime with ease. An effective methodology is required to communicate between these modules. Linux notifier chains do this effectively. They are mainly brought in for network devices and can be effectively used by other technologies as well. As developers, we have to look for such utility functions that are available in the kernel and use them effectively in our designs instead of reinventing the wheel. 

Linux内核Notifier机制相关推荐

  1. Linux内核notifier机制通知链

    内核使用通知链的机制在内核各子系统之间进行事件通知(注:无法用于内核态和用户态之间的事件通知). 一.通知链介绍 在文件include/linux/notifier.h中,可以查看Linux内核定义的 ...

  2. Linux 内核 notifier机制

    一般而言特定的子系统会用特定的notifier_chain_register包装函数来注册,比如tp通过fb_register_client来注册notifier_block(在具体的应用场景中会封装 ...

  3. Linux内核同步机制之(四):spin lock【转】

    转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...

  4. 深度剖析Linux内核地址映射机制

    深度剖析Linux内核地址映射机制 1.虚拟空间数据结构   2.进程虚拟空间  3.内存映射 视频讲解如下,点击观看: Linux内核开发系列第7讲--深度剖析Linux内核地址映射机制 C/C++ ...

  5. linux 内核mmap,Linux内核mmap机制

    1. 问:如何将物理地址映射到用户空间的虚拟地址上? 2.linux内核mmap机制 2.1.回顾LED驱动数据流的操作过程 通过分析LED驱动,得出以下结论: 如果利用read,write,ioct ...

  6. Linux的notifier机制在TP中的应用【转】

    转自:https://blog.csdn.net/armfpga123/article/details/51771666 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog ...

  7. Linux内核OOM机制的浅析

    Linux内核根据应用程序的要求分配内存,通常来说应用程序分配了内存但是并没有实际全部使用,为了提高性能,这部分没用的内存可以留作它用,这部分内存是属于每个进程的,内核直接回收利用的话比较麻烦,所以内 ...

  8. linux内核锁机制学习

    在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需要一些同步机制来同步不同处理器上 ...

  9. linux内核 RCU机制概述

    简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制 ...

最新文章

  1. Redis初学17:集群
  2. 谷歌浏览器删除相同重复无效书签
  3. Python 爬虫原理实现自动google翻译
  4. 主/辅DNS服务器详细配置
  5. 20个Flutter实例视频教程-第03节: 不规则底部工具栏制作-1
  6. 为了不让代码“作恶”,能否将道德条款纳入开源许可证?
  7. Android之切换账号登录依然能登录成功问题解决办法
  8. 如何进行正确的SQL性能优化
  9. Mr. Bender and Square
  10. sv_labs学习笔记——sv_lab5_上(System Verilog)
  11. 09年关门歇业的15大网站 雅虎旗下4网站上榜
  12. Linux查找link文件,Linux下查找一个文件的所有软硬链接
  13. c语言怎么编程打开文件,怎么用c语言打开文件
  14. VMware+WinDBG_配置_资料
  15. 方程检验格式图片_eviews的异方差检验ppt课件
  16. UVALive 4490 Help Bubu
  17. c语言6月份考试时间,六级几点考试 考试时间明细
  18. win7系统激活工具怎么用?
  19. cad 打开硬件加速卡_CAD2020 使用图块插入命令特别卡怎么办?
  20. 百会CRM发布新春致5万企业用户的公开信

热门文章

  1. Flyme patchrom项目笔记
  2. Exchange Server 2016 安装部署
  3. 终有一天,你没法成为曾经梦里的那个人了。
  4. 2021华为杯数学建模D题完整思路
  5. php可以开发大型网站吗?其实这个问题不用回答
  6. JavaScript 案例综合提升
  7. C/C++播放音乐的函数的学习
  8. 微信抢票应用开发总结
  9. 太原科技大学调剂计算机,2016年太原科技大学考研调剂信息
  10. 蓝牙音乐和导航语音播放混音卡顿问题