Linux内核通知链技术-notification chain

通知链技术( notification chain )

          在 Linux 内核中,各个子系统之间有很强的相互关系,一些被一个子系统生成或者被探测到的事件,很可能是另一个或者多个子系统感兴趣的,也就是说这个事件的获取者必须能够通知所有对该事件感兴趣的子系统,并且还需要这种通知机制具有一定的通用性。基于这些, Linux 内核引入了“通知链”技术。

          通知链表是一个函数链表,链表上的每一个节点都注册了一个函数。当某个事情发生时,链表上所有节点对应的函数就会被执行。所以对于通知链表来说有一个通知方与一个接收方。在通知这个事件时所运行的函数由被通知方决定,实际上也即是被通知方注册了某个函数,在发生某个事件时这些函数就得到执行。通知链表只能够在内核的子系统之间使用,而不能够在内核与用户空间之间进行事件的通知。 其实和系统调用signal的思想差不多。

通知链有四种类型,

  1. 原子通知链( Atomic notifier chains ):通知链元素的回调函数(当事件发生时要执行的函数)只能在中断上下文中运行,不允许阻塞
  2. 可阻塞通知链( Blocking notifier chains ):通知链元素的回调函数在进程上下文中运行,允许阻塞
  3. 原始通知链( Raw notifier chains ):对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护
  4. SRCU 通知链( SRCU notifier chains ):可阻塞通知链的一种变体

所以对应了四种通知链头结构:

  • struct atomic_notifier_head :原子通知链的链头
    struct atomic_notifier_head {
    	spinlock_t lock;
    	struct notifier_block __rcu *head;
    };
  • struct blocking_notifier_head :可阻塞通知链的链头
    struct blocking_notifier_head {
    	struct rw_semaphore rwsem;
    	struct notifier_block __rcu *head;
    };
  • struct raw_notifier_head :原始通知链的链头
    struct raw_notifier_head {
    	struct notifier_block __rcu *head;
    };
  • struct srcu_notifier_head : SRCU 通知链的链头
    struct srcu_notifier_head {
    	struct mutex mutex;
    	struct srcu_struct srcu;
    	struct notifier_block __rcu *head;
    };

      通知链元素的类型:

      • struct notifier_block :通知链中的元素,记录了当发出通知时,应该执行的操作(即回调函数)
        struct notifier_block {
        	int (*notifier_call)(struct notifier_block *, unsigned long, void *);
        	struct notifier_block __rcu *next;
        	int priority;//priority是这个通知的优先级,同一条链上的notifier_block{}是按优先级排列的。
        };

      链头中保存着指向元素链表的指针。通知链元素结构则保存着回调函数的类型以及优先级,参见 notifier.h 文件。

      运作机制

      通知链的运作机制包括两个角色:

      1. 被通知者:对某一事件感兴趣一方。定义了当事件发生时,相应的处理函数,即回调函数。但需要事先将其注册到通知链中(被通知者注册的动作就是在通知链中增加一项)。
      2. 通知者:事件的通知者。当检测到某事件,或者本身产生事件时,通知所有对该事件感兴趣的一方事件发生。他定义了一个通知链,其中保存了每一个被通知者对事件的处理函数(回调函数)。通知这个过程实际上就是遍历通知链中的每一项,然后调用相应的事件处理函数。

      包括以下过程:

      1. 通知者定义通知链
      2. 被通知者向通知链中注册回调函数
      3. 当事件发生时,通知者发出通知(执行通知链中所有元素的回调函数)

      被通知者调用 notifier_chain_register 函数注册回调函数,该函数按照优先级将回调函数加入到通知链中 。注销回调函数则使用 notifier_chain_unregister 函数,即将回调函数从通知链中删除。2.2.1节讲述的4种通知链各有相应的注册和注销函数,但是他们最终都是调用上述两个函数完成注册和注销功能的。有兴趣的读者可以自行查阅内核代码。

      通知者调用 notifier_call_chain 函数通知事件的到达,这个函数会遍历通知链中所有的元素,然后依次调用每一个的回调函数(即完成通知动作)。2.2.1节讲述的4种通知链也都有其对应的通知函数,这些函数也都是最终调用 notifier_call_chain 函数完成事件的通知。

      由以上的叙述,“通知链”技术可以概括为:事件的被通知者将事件发生时应该执行的操作通过函数指针方式保存在链表(通知链)中,然后当事件发生时通知者依次执行链表中每一个元素的回调函数完成通知。


      #define RAW_INIT_NOTIFIER_HEAD(name) do {    \
              (name)->head = NULL;        \
          } while (0)

      RAW_INIT_NOTIFIER_HEAD(my_raw_notifier_list);
      
      
      struct notifier_block my_head {
      	.notifier_call = my_notifier_function;
      };

      raw_notifier_chain_register(&my_raw_notifier_list,&my_head);

      static int my_notifier_function(struct notifier_block *this, unsigned long event, void *ptr)
      {
             printk("In Event 1: Event Number is %d\n", event);
             return 0;
      }

      
      

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值