Linux 内核通知链随笔【下】

8660阅读 0评论2014-07-25 wjlkoorey258
分类:LINUX

    书接上回,闲话不表。话说,女神无论是在土豪或者屌丝那里都找不到归属感,冥冥之中天上掉下来一个王子(PS:又名高富帅),既可以满足女神的物质需求还可以满足女神的精神需求:

点击(此处)折叠或打开

  1. /*GFS.c*/
  2. #include <asm/uaccess.h>
  3. #include <linux/types.h>
  4. #include <linux/kernel.h>
  5. #include <linux/sched.h>
  6. #include <linux/notifier.h>
  7. #include <linux/init.h>
  8. #include <linux/types.h>
  9. #include <linux/module.h>
  10. MODULE_LICENSE("GPL");

  11. /*
  12. * 注册通知链
  13. */

  14. extern int register_godness_notifier(struct notifier_block*);
  15. extern int unregister_godness_notifier(struct notifier_block*);

  16. static int sweet_heart_requirments(struct notifier_block *this, unsigned long event, void *ptr)
  17. {
  18.         switch(event)
  19.         {
  20.                 case 0:
  21.                         printk("[GFS]Hi honey,the VISA card is ready for you! \n");
  22.                         break;
  23.                 case 1:
  24.                         printk("[GFS]Hi honey,let me play the piano for you! \n");
  25.                         break;
  26.                 default:
  27.                         break;
  28.         }
  29.         return 0;
  30. }

  31. static struct notifier_block honey_notifier =
  32. {
  33.         .notifier_call = sweet_heart_requirments,
  34.         .priority = 2,
  35. };

  36. static int __init GFS_register(void)
  37. {
  38.         int err;
  39.         printk("[GFS]GFS register honey_requirment response to Godness...");

  40.         err = register_godness_notifier(&honey_notifier);
  41.         if (err)
  42.         {
  43.                 printk("Refused!\n");
  44.                 return -1;
  45.         }
  46.         printk("Accepted!\n");

  47.         return err;
  48. }

  49. /*
  50. * 卸载刚刚注册了的通知链
  51. */
  52. static void __exit GFS_unregister(void)
  53. {
  54.         unregister_godness_notifier(&honey_notifier);
  55.         printk("[GFS]GFS broke up with Godness!(How sadness)\n");
  56. }
  57. module_init(GFS_register);
  58. module_exit(GFS_unregister);

   然后重新上演前面的故事,
播放的指令如下:
[root@localhost test]# insmod Goddess.ko;sleep 4;insmod Tuhao.ko; sleep 4; insmod Diors.ko;sleep 4; insmod GFS.ko
[root@localhost test]# rmmod GFS.ko;rmmod Diors.ko;rmmod Tuhao.ko;rmmod Goddess.ko
[root@localhost test]#

   播放内容如下:
Jun  2 00:39:41 localhost kernel: [Attention]The Godness coming into the world!
Jun  2 00:39:41 localhost kernel: [Godness]requirements thread starting...
Jun  2 00:39:44 localhost kernel: [Godness]requirment type: 1
Jun  2 00:39:45 localhost kernel: [Tuhao]Tuhao register Cash event  to Godness...Accepted!
Jun  2 00:39:47 localhost kernel: [Godness]requirment type: 0
Jun  2 00:39:47 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:39:49 localhost kernel: [Diors]Diors register music_requirment response to Godness...Accepted!
Jun  2 00:39:50 localhost kernel: [Godness]requirment type: 1
Jun  2 00:39:50 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:39:53 localhost kernel: [Godness]requirment type: 1
Jun  2 00:39:53 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:39:53 localhost kernel: [GFS]GFS register honey_requirment response to Godness...Accepted!
Jun  2 00:39:56 localhost kernel: [Godness]requirment type: 1
Jun  2 00:39:56 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:39:56 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:39:59 localhost kernel: [Godness]requirment type: 0
Jun  2 00:39:59 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:39:59 localhost kernel: [GFS]Hi honey,the VISA card is ready for you!
Jun  2 00:40:02 localhost kernel: [Godness]requirment type: 1
Jun  2 00:40:02 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:40:02 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:40:05 localhost kernel: [Godness]requirment type: 1
Jun  2 00:40:05 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:40:05 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:40:08 localhost kernel: [Godness]requirment type: 0
Jun  2 00:40:08 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:40:08 localhost kernel: [GFS]Hi honey,the VISA card is ready for you!
Jun  2 00:40:11 localhost kernel: [Godness]requirment type: 1
Jun  2 00:40:11 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:40:11 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:40:11 localhost kernel: [Godness]requirements thread ended!
Jun  2 00:40:52 localhost kernel: [GFS]GFS broke up with Godness!(How sadness)
Jun  2 00:40:52 localhost kernel: [Diors]Tuhao is giving up Godness!(What a pity)
Jun  2 00:40:52 localhost kernel: [Tuhao]Tuhao is giving up Godness!(Son of bitch)
Jun  2 00:40:52 localhost kernel: [Attention] The Godness leaving out!

   我们可以看到,高富帅向女神需求通知链上注册的回调函数,优先级也是2,我们在测试的时候是先加载土豪、再加载屌丝最后加载高富帅,所以每当女神提出需求时,如果是金钱需求则最先被土豪响应,如果是精神需求则最先被屌丝给响应了。这完全不符合高富帅的特征啊,于是高富帅将自己的优先级提高到5,然后replay一次:

点击(此处)折叠或打开

  1. static struct notifier_block honey_notifier =
  2. {
  3.         .notifier_call = sweet_heart_requirments,
  4.         .priority = 5,
  5. };

    结果如下:
Jun  2 00:50:29 localhost kernel: [Attention]The Godness coming into the world!
Jun  2 00:50:29 localhost kernel: [Godness]requirements thread starting...
Jun  2 00:50:32 localhost kernel: [Godness]requirment type: 0
Jun  2 00:50:33 localhost kernel: [Tuhao]Tuhao register Cash event  to Godness...Accepted!
Jun  2 00:50:35 localhost kernel: [Godness]requirment type: 0
Jun  2 00:50:35 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:50:37 localhost kernel: [Diors]Diors register music_requirment response to Godness...Accepted!
Jun  2 00:50:38 localhost kernel: [Godness]requirment type: 1
Jun  2 00:50:38 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:50:41 localhost kernel: [Godness]requirment type: 0
Jun  2 00:50:41 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:50:41 localhost kernel: [GFS]GFS register honey_requirment response to Godness...Accepted!
Jun  2 00:50:44 localhost kernel: [Godness]requirment type: 0
Jun  2 00:50:44 localhost kernel: [GFS]Hi honey,the VISA card is ready for you!
Jun  2 00:50:44 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:50:47 localhost kernel: [Godness]requirment type: 1
Jun  2 00:50:47 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:50:47 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:50:50 localhost kernel: [Godness]requirment type: 1
Jun  2 00:50:50 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:50:50 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:50:53 localhost kernel: [Godness]requirment type: 0
Jun  2 00:50:53 localhost kernel: [GFS]Hi honey,the VISA card is ready for you!
Jun  2 00:50:53 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:50:56 localhost kernel: [Godness]requirment type: 0
Jun  2 00:50:56 localhost kernel: [GFS]Hi honey,the VISA card is ready for you!
Jun  2 00:50:56 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:50:59 localhost kernel: [Godness]requirment type: 1
Jun  2 00:50:59 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:50:59 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:50:59 localhost kernel: [Godness]requirements thread ended!
Jun  2 00:51:04 localhost kernel: [GFS]GFS broke up with Godness!(How sadness)
Jun  2 00:51:04 localhost kernel: [Diors]Tuhao is giving up Godness!(What a pity)
Jun  2 00:51:04 localhost kernel: [Tuhao]Tuhao is giving up Godness!(Son of bitch)
Jun  2 00:51:04 localhost kernel: [Attention] The Godness leaving out!

    这次我们看到,高富帅终于如愿以偿地于第一时间响应到了女神的需求。再考虑一种情况,如果高富帅不想让女神的需求传递到土豪和屌丝那里,怎么办?其实也很简单,高富帅只要在自己的响应函数里向女神返回NOTIFY_STOP值就可以了:

点击(此处)折叠或打开

  1. static int sweet_heart_requirments(struct notifier_block *this, unsigned long event, void *ptr)
  2. {
  3.         switch(event)
  4.         {
  5.                 case 0:
  6.                         printk("[GFS]Hi honey,the VISA card is ready for you! \n");
  7.                         break;
  8.                 case 1:
  9.                         printk("[GFS]Hi honey,let me play the piano for you! \n");
  10.                         break;
  11.                 default:
  12.                         break;
  13.         }
  14.         return NOTIFY_STOP;
  15. }

   然后故事就变成酱紫了:
Jun  2 00:55:56 localhost kernel: [Attention]The Godness coming into the world!
Jun  2 00:55:56 localhost kernel: [Godness]requirements thread starting...
Jun  2 00:55:59 localhost kernel: [Godness]requirment type: 1
Jun  2 00:56:00 localhost kernel: [Tuhao]Tuhao register Cash event  to Godness...Accepted!
Jun  2 00:56:02 localhost kernel: [Godness]requirment type: 0
Jun  2 00:56:02 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:56:04 localhost kernel: [Diors]Diors register music_requirment response to Godness...Accepted!
Jun  2 00:56:05 localhost kernel: [Godness]requirment type: 1
Jun  2 00:56:05 localhost kernel: [Diors]Hi girl,This is a classic Music disk,take it.
Jun  2 00:56:08 localhost kernel: [Godness]requirment type: 0
Jun  2 00:56:08 localhost kernel: [Tuhao]Hi Baby,$$$$$$$$ 么么哒
Jun  2 00:56:08 localhost kernel: [GFS]GFS register honey_requirment response to Godness...Accepted!
Jun  2 00:56:11 localhost kernel: [Godness]requirment type: 1
Jun  2 00:56:11 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:56:14 localhost kernel: [Godness]requirment type: 0
Jun  2 00:56:14 localhost kernel: [GFS]Hi honey,the VISA card is ready for you!
Jun  2 00:56:17 localhost kernel: [Godness]requirment type: 1
Jun  2 00:56:17 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:56:20 localhost kernel: [Godness]requirment type: 1
Jun  2 00:56:20 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:56:23 localhost kernel: [Godness]requirment type: 0
Jun  2 00:56:23 localhost kernel: [GFS]Hi honey,the VISA card is ready for you!
Jun  2 00:56:26 localhost kernel: [Godness]requirment type: 1
Jun  2 00:56:26 localhost kernel: [GFS]Hi honey,let me play the piano for you!
Jun  2 00:56:26 localhost kernel: [Godness]requirements thread ended!
Jun  2 00:56:30 localhost kernel: [GFS]GFS broke up with Godness!(How sadness)
Jun  2 00:56:30 localhost kernel: [Diors]Tuhao is giving up Godness!(What a pity)
Jun  2 00:56:30 localhost kernel: [Tuhao]Tuhao is giving up Godness!(Son of bitch)
Jun  2 00:56:30 localhost kernel: [Attention] The Godness leaving out!

   在高富帅还没将自己的响应函数注册到女神之前,女神的物质需求是被土豪给霸占了,精神需求被屌丝给享有了,等到00:56:08秒之后,高富帅的请求被女神接受了,于是接下来就没土豪和屌丝啥事儿了。OK,到这里我们的故事也就讲完了,让我们回头来总结一下Linux内核中通知链的相关知识点(首先非常感谢wwx0715兄弟指出了我【上】篇博文的一个错误,在【上】篇博文里我将通知链的优先级弄反了,是数字越大优先级越高,通知函数越是先会被执行,在此非常感谢。):
   1、如果一个子系统A在运行过程中会产生一个实时的事件,而这些事件对其他子系统来说非常重要,那么系统A可以定义一个自己的通知链对象,根据需求可以选择原子通知链、非阻塞通知链或者原始通知链,并向外提供向这个通知链里注册、卸载执行事件的回调函数的接口;
   2、如果子系统B对子系统A中的某(些)个事件感兴趣,或者说强依赖,就是说系统B需要根据系统A中某些事件来执行自己特定的操作,那么此时系统就需要实例化一个通知块struct notifier_block XXX{},然后编写通知块里的回调处理函数来响应A系统中响应的事件就可以了;
   3、在我们这个示例里用到了struct notifier_block{}的优先级特性,其实在标准内核里每个实例化的通知块都没有用优先级字段。不用优先级字段的结果就是,先注册的通知块里的回调函数在事件发生时会先执行。注意这里所说的后注册指的是模块被动态加载内核的先后顺序,和哪个模块的代码先写完没有关系,注意区分。意思就是说,如果子系统B和C都对子系统A的up事件感兴趣,B和C在向A注册up事件的回调函数时并没有指定函数的优先级。无论是通过insmod手动加载模块B和C,还是系统boot时自动加载B和C,哪个模块先被加载,它的回调函数在A系统的up事件发生时会先被执行;
   4、关于通知链的回调函数,正常情况下都需要返回NOTIFY_OK或者NOTIFY_DONE,这样通知链上后面挂载的其他函数可以继续执行。如果返回NOTIFY_STOP,则会使得本通知链上后续挂载的函数无法得到执行,除非你特别想这么做,否则在编写通知链的回调函数时一般最好不要返回这个值;
   5、通知链上回调函数的原型int (*notifier_call)(struct notifier_block *, unsigned long, void *),其中第二个参数一般用于指明事件的类型,通常都是一个整数。而第三个参数是一个void类型的内存地址,在不同的子系统中用于表示不同的信息,例如在邻居子系统里,第三个参数可以是一个邻居信息结构体对象的地址struct neighbour *v;而在驱动框架里又可以是一个net_device{}结构体对象的地址等等;我们在设计自己的通知链系统可以用第三个入参实现在通知系统与被通知系统之间实现数据的传递,以便被通知系统的工作可以更加紧凑、高效;
   6、如果以后再看到内核中某个子系统在调用通知链的注册函数时,不要心虚、不要怕。做到以下两点就没事儿了:
       第一:心里首先要明确,这个注册通知链回调函数的系统一定和提供通知链的系统有某种连续,且本系统需要对那个系统的某些重要事件进行响应;
       第二:看本系统注册的通知回调函数的实现,具体看它对那些事件感兴趣,并且是怎么处理的;
       第三:看看原提供通知链对象的系统有哪些事件;
   最后,心里也就明白了这个系统为什么要用通知链来感知别的系统的变化了,这样一来,对这两个系统从宏观到甚微观的层面就都有一个总体的认识和把握,后续再研究起来就顺风顺水了,而这也正是内核通知链的神奇所在。
   完。
上一篇:Linux 内核通知链随笔【中】
下一篇:Linux内核【链表】整理笔记(1)