Linux通知链机制及实例

  • 时间:
  • 浏览:1
  • 来源:彩神幸运飞艇_神彩幸运飞艇官方

#define NETDEV_CHANGEMTU        0x0007 /* notify after mtu change happened */

#define NETDEV_FEAT_CHANGE      0x000B

struct atomic_notifier_head {

#define NETDEV_REGISTER 0x0005

{

l   SRCU 通知链( SRCU notifier chains ):可阻塞通知链的并不是变体。对应的链表头:srcu_notifier_head.

#define NETDEV_CHANGE_TX_QUEUE_LEN      0x001E

 static int register_test_notifier(struct notifier_block *nb)

  printk (KERN_DEBUG "Goodbye to test_clain_l\n");

MODULE_LICENSE ("GPL");

    default:

[40731.758724] I got the chain event: test_chain_2 is on the way of init

/* realize the notifier_call func */

};

#define TESTCHAIN_INIT 0x52U 

{

#define NETDEV_JOIN             0x0014

};

#define NETDEV_BONDING_INFO     0x0019

static void __exit test_chain_2_exit(void)

  return 0;

任何内核子系统都可不前要对该链条注册的另一一五个 回调函数以接收通知信息。

#define NETDEV_CHANGE   0x0004  /* Notify device state change */

向事件通知链注册步骤如下:

#define NETDEV_RESEND_IGMP      0x0016

                    if(err)

通知链是另一一五个 函数列表,当给定事件处于的很久予以执行。每条通知链都是被通知者和拥有者。拥有者定义列表,被通知的子系统选泽要执行的函数。网络子系统有3个通知链,如下图:

#define NETDEV_PRECHANGEUPPER   0x001A

[40731.758722] I'm in test_chain_2

       定义在include/linux/notifier.h文件中。

test_init_event (struct notifier_block *nb, unsigned long event, void *v)

      break;

static RAW_NOTIFIER_HEAD(test_chain);

而且内核组件前要出理 够某个事件通知链上发出的事件通知,其就该在初始化时在该通知链上注册回调函数。

Linux内核中通知链,一般命名为xxx_chain而且,xxx_notifier_chian。内核有并不是类型的通知链链表表头。

#include <linux/notifier.h>

struct raw_notifier_head {

}

}

#define NETDEV_UP       0x0001  /* For now you can't veto a device up/down */

       通用函数notifier_chain_register予以注册,定义在kernel/notifier.c

#define NETDEV_UDP_TUNNEL_PUSH_INFO     0x001C

l   可阻塞通知链( Blocking notifier chains ):通知链元素的回调函数在系统线程池池上下文中运行,允许阻塞。对应的链表头:blocking_notifier_head

定义notifier_block的test_init_notifier,其回调函数为test_init_event。

{

#include <linux/fs.h> /* everything() */

#define NETDEV_POST_TYPE_CHANGE 0x000F

            int err;

#define NETDEV_RELEASE          0x0012

        int priority;

1. 申明struct notifier_block底部形态

MODULE_LICENSE("GPL");

#include <linux/notifier.h>

  .notifier_call = test_init_event,

};

int

                                    goto out;

#define NETDEV_BONDING_FAILOVER 0x000C

              "I got the chain event: test_chain_2 is on the way of init\n");

[350086.518853] I'm in test_chain_0

        struct rw_semaphore rwsem;

#define NETDEV_REBOOT   0x0003  /* Tell a protocol stack a network interface

inet_subsys是通过notifier_call_chain来通知而且 的子系统(other_subsys_x)的。

通知链只有用在各个子系统之间,而只有在内核和用户空间进行事件的通知。

#define NETDEV_NOTIFY_PEERS     0x0013

module_exit(test_chain_0_exit);

}

/* define our own notifier_call_chain */

#define NETDEV_CHANGELOWERSTATE 0x001B

#define NETDEV_GOING_DOWN       0x0009

                call_test_notifiers(TESTCHAIN_INIT, "no_use");

            printk(KERN_DEBUG "Goodbye to test_chain_0\n");

调用模块0的事件发送函数call_test_notifiers,事件发送后,订阅时间的模块1会调用其当事人的函数test_init_event,输出字符串。

[40723.535358] I'm in test_chain_1

notifier_call_chain会按照通知链上各成员的优先级顺序执行回调函数(notifier_call_x);回调函数的执行现场在notifier_call_chain系统线程池池地址空间;其返回值是NOTIFY_XXX的形式,在include/linux/notifier.h中:

            printk(KERN_DEBUG "Goodbye to test_chain_2\n");

{

      printk (KERN_DEBUG

{

static int __init test_chain_0_init(void)

struct blocking_notifier_head {

EXPORT_SYMBOL(register_test_notifier);

定义另一一五个 函数,另一一五个 是注册函数register_test_notifier,另一一五个 发送事件函数call_test_notifiers

}

#define NOTIFY_STOP_MASK        0x50000          /* Don't call further */

l   原子通知链( Atomic notifier chains ):通知链元素的回调函数(当事件处于前要执行的函数)在中断或原子操作上下文中运行,不允许阻塞。对应的链表头底部形态:atomic_notifier_head

#include <linux/module.h>

notifier_call_chain捕获并返回最后另一一五个 事件出理 函数的返回值, 并而且一起去被不同的cpu调用,调用者须保证互斥。

#include <linux/kernel.h>       /* printk() */

{

};

            return raw_notifier_call_chain(&test_chain, val, v);

module_exit(test_chain_2_exit);

#include <linux/init.h>

        struct notifier_block __rcu *head;

Linux网络子系统含有3个通知链,表示ipv4地址发送变化时的inetaddr_chain,表示ipv6地址处于变化的inet6addr_chain,表示设备注册、清况 变化的netdev_chain。

}

#define NETDEV_CHANGEUPPER      0x0015

#define NETDEV_PRE_TYPE_CHANGE  0x000E

{

2. 编写notifier_call函数

        notifier_fn_t notifier_call;

#define NETDEV_POST_INIT        0x0010

#define NETDEV_CHANGENAME       0x000A

#define NOTIFY_BAD              (NOTIFY_STOP_MASK|0x0002)

        struct mutex mutex;

       而且可不前要依次插入模块chain0.ko,chain1.ko,chain2.ko。

输出如下:

out:

#define NETDEV_DOWN     0x0002

                        return err;

        struct notifier_block __rcu *head;

        struct notifier_block __rcu *next;

static void __exit

#define NETDEV_CHANGEADDR       0x0008

static struct notifier_block test_init_notifier = {

                    return 0;

#include <linux/fs.h> /* everything() */

        struct notifier_block __rcu *head;

{

    }

#include <linux/fs.h>           /* everything() */

       链中都是另一一五个 个notifier_block底部形态。

  return NOTIFY_DONE;

#define NETDEV_UNREGISTER_FINAL 0x0011

#define NETDEV_PRECHANGEMTU     0x0017 /* notify before mtu change happened */

test_chain_1_exit (void)

};

                                                /* Bad/Veto action */

            printk(KERN_DEBUG "I'm in test_chain_2\n");

}

                err = raw_notifier_chain_register(&test_chain, nb);

     实例代码如下,来自网络,并分发。

module_init (test_chain_1_init);

            printk(KERN_DEBUG "I'm in test_chain_0\n");

    {

#define NOTIFY_DONE             0x0000          /* Don't care */

3. 调用事件通知链的注册函数,将notifier_block注册到通知链中

        spinlock_t lock;

}

                                   detected a hardware crash and restarted

    case TESTCHAIN_INIT:

{

       notifier_call是要执行的函数,由被通知方提供,next用于链接列表的元素,而priority代表的是该函数的优先级。

#include <linux/kernel.h> /* printk() */

                                   - we can use this eg to kick tcp sessions

                return 0;

static void __exit test_chain_0_exit(void)

       通知链列表元素的类型是notifier_block

#include <linux/notifier.h>

/* define a notifier_block */

#define TESTCHAIN_INIT 0x52U

#include <linux/init.h>

#define NETDEV_PRE_UP           0x000D

      break;

#define NOTIFY_OK               0x0001          /* Suits me */

module_init(test_chain_2_init);

MODULE_LICENSE("GPL");

  switch (event)

static int call_test_notifiers(unsigned long val, void *v)

  register_test_notifier (&test_init_notifier);

module_exit (test_chain_1_exit);

#include <linux/init.h>

extern int call_test_notifiers(unsigned long val, void *v);

struct notifier_block {

#include <linux/kernel.h> /* printk() */

        struct notifier_block __rcu *head;

#define TESTCHAIN_INIT 0x52U 

  printk (KERN_DEBUG "I'm in test_chain_1\n");

struct srcu_notifier_head {

l   原始通知链( Raw notifierchains ):对通知链元素的回调函数越来越 任何限制,所有锁和保护机制都由调用者维护。对应的链表头:raw_notifier_head,网络子系统很久该类型

}

extern int register_test_notifier (struct notifier_block *nb);

对于网络子系统而言,事件常以NETDEV_XXX命名,用于描述网络设备清况 (dev->flags)、传送队列清况 (dev->state)、设备注册清况 (dev->reg_state),以及设备的硬件功能底部形态(dev->features),处于文件include/linux/notifier.h中:

                                   once done */

#define NETDEV_CHANGEINFODATA   0x0018

#define NETDEV_UNREGISTER       0x0006

#include <linux/module.h>

}

        struct srcu_struct srcu;



  Linux内核中各个子系统相互依赖,当其中某个子系统清况 处于改变时,要使用一定的机制告知使用其服务的而且 子系统,以便而且 子系统采取相应的方法。内核实现了事件通知链机制(notification chain)。

EXPORT_SYMBOL(call_test_notifiers);

static int __init test_chain_2_init(void)

/* define our own notifier_chain_register func */

被通知一方(other_subsys_x)通过notifier_chain_register向特定的chain注册回调函数,一般子系统会用特定的notifier_chain_register包装函数来注册,如网络子系统是使用register_netdevice_notifier来注册他的notifier_block。

};

#define NETDEV_UDP_TUNNEL_DROP_INFO     0x001D

module_init(test_chain_0_init);

static int __init

test_chain_1_init (void)

而且调用模块0中的事件注册函数register_test_notifier,向模块进行事件订阅。当事件处于还会后调用函数test_init_event.

#include <linux/module.h>