Linux 内核通知链随笔【中】【转】

转自:http://blog.chinaunix.net/uid-23069658-id-4364171.html

关于内核通知链不像Netlink那样,既可以用于内核与用户空间的通信,还能用于内核不同子系统之间的通信,通知链只能用于内核不同子系统之间的通信。那么内核通知链到底是怎么工作的?我们如何才能用好通知链?内核源代码里随处可见的通知链身影,我们到底该如何理解呢?本片博文过后,您的这些疑问和顾虑将统统消除。

   以前有个女神,超凡脱俗、出水芙蓉,不过在怎么滴也是人,是人就会有各种各样的需求,女神的所有需求都放在她的需求链表里requirment_chain,比如物质需求,精神需求等等。然后女神首先需要做的事情就是将自己的需求链给实例化了:

点击(此处)折叠或打开

  1. /* Godness.c */
  2. /* 我们假设女神需求链的类型是原始通知链(PS:不要和原始需求挂钩理解 -_-||)*/
  3. static RAW_NOTIFIER_HEAD(requirment_chain);

    当需求被定义出来后,还需要向外提供两个接口:一个是别人用于满足她需求的接口,另一个是别人需要和她break out的接口(虽然在现实生活中这种情况比较令人sadness,但女神所在的虚拟世界里这个是必须的)。于是女神提供了别人往其需求链注册响应函数的接口和卸载响应函数的接口:

点击(此处)折叠或打开

  1. /* Godness.c*/
  2. int register_godness_notifier(struct notifier_block *nb)
  3. {
  4.         return raw_notifier_chain_register(&requirment_chain, nb);
  5. }
  6. EXPORT_SYMBOL(register_godness_notifier); //注册函数实现了之后必须将其公布出去,不然别人怎么看得到呢
  7. int unregister_godness_notifier(struct notifier_block *nb)
  8. {
  9.         return raw_notifier_chain_unregister(&requirment_chain, nb);
  10. }
  11. EXPORT_SYMBOL(unregister_godness_notifier); //同上

    然后,女神要做的就是提需求,并看看哪些屌丝、土豪或高富帅来追求自己:

点击(此处)折叠或打开

  1. int call_godness_notifier_chain(unsigned long val, void *v)
  2. {
  3.         return raw_notifier_call_chain(&requirment_chain, val, v);
  4. }
  5. EXPORT_SYMBOL(call_godness_notifier_chain);

    为了模拟测试过程,我们需要一个内核线程,模拟女神提需求的过程,然后不断调用上面的需求响应的检测函数。我们姑且认为认为女神的需求有两种:物质需求就是对menoy的需求,精神需求就是音乐的需求。女神每3秒钟提一个需求,一共提10个需求:

点击(此处)折叠或打开

  1. #define PHY_REQ 0 //物质需求
  2. #define SPR_REQ 1 //精神需求
  3. #define REQ_MAX SPR_REQ+1
  4. static int make_requirment_thread(void *data)
  5. {
  6.      int i = 10;
  7.      struct completion cmpl;
  8.      unsigned int requirment_type = 0;
  9.      printk("[Godness]requirements thread starting...\n");
  10.      while((i--) > 0){
  11.             init_completion(&cmpl);
  12.             wait_for_completion_timeout(&cmpl, 3 * HZ);
  13.             get_random_bytes(&requirment_type,sizeof(requirment_type));  //生成一个内核随机数
  14.             requirment_type %= REQ_MAX;  //需求类型之可能是0或者1
  15.             printk("[Godness]requirment type: %d \n",requirment_type);
  16.             call_godness_notifier_chain(requirment_type,NULL);
  17.      }
  18.      printk("[Godness]requirements thread ended!\n");
  19.      return 0;
  20. }

    女神的最终模型如下:

点击(此处)折叠或打开

  1. #include <asm/uaccess.h>
  2. #include <linux/types.h>
  3. #include <linux/kernel.h>
  4. #include <linux/sched.h>
  5. #include <linux/notifier.h>
  6. #include <linux/init.h>
  7. #include <linux/types.h>
  8. #include <linux/module.h>
  9. #include <linux/kthread.h>
  10. MODULE_LICENSE("GPL");
  11. #define PHY_REQ 0 //物质需求
  12. #define SPR_REQ 1 //精神需求
  13. #define REQ_MAX SPR_REQ+1
  14. extern void get_random_bytes(void* buf,int nbytes);
  15. static struct task_struct *requirments_thread = NULL;
  16. /*
  17. * 女神所有的需求都会列在她的需求链里。这里我们定义了一个原始通知链,暂时没考虑锁的问题。
  18. */
  19. static RAW_NOTIFIER_HEAD(requirment_chain);
  20. /*
  21. * 如果谁想追求本女王,就来献殷勤吧
  22. */
  23. int register_godness_notifier(struct notifier_block *nb)
  24. {
  25.         return raw_notifier_chain_register(&requirment_chain, nb);
  26. }
  27. EXPORT_SYMBOL(register_godness_notifier);
  28. /*
  29. * 伺候不起的,赶紧Get out as soon as 
  30. */
  31. int unregister_godness_notifier(struct notifier_block *nb)
  32. {
  33.         return raw_notifier_chain_unregister(&requirment_chain, nb);
  34. }
  35. EXPORT_SYMBOL(unregister_godness_notifier);
  36. /*
  37. * 本女王开始提需求了,看看谁能才是真心的。
  38. */
  39. int call_godness_notifier_chain(unsigned long val, void *v)
  40. {
  41.         return raw_notifier_call_chain(&requirment_chain, val, v);
  42. }
  43. EXPORT_SYMBOL(call_godness_notifier_chain);
  44. static int make_requirment_thread(void *data)
  45. {
  46.      int i = 10;
  47.      struct completion cmpl;
  48.      unsigned int requirment_type = 0;
  49.      printk("[Godness]requirements thread starting...\n");
  50.      while((i--) > 0){
  51.             init_completion(&cmpl);
  52.             wait_for_completion_timeout(&cmpl, 3 * HZ);
  53.             get_random_bytes(&requirment_type,sizeof(requirment_type));  //生成一个内核随机数
  54.             requirment_type %= REQ_MAX;  //需求类型之可能是0或者1
  55.            printk("[Godness]requirment type: %d \n",requirment_type);
  56.             call_godness_notifier_chain(requirment_type,NULL);
  57.      }
  58.      printk("[Godness]requirements thread ended!\n");
  59.      return 0;
  60. }
  61. static int __init godness_init_notifier(void)
  62. {
  63.         printk("[Attention]The Godness coming into the world!\n");
  64.         requirments_thread = kthread_run(make_requirment_thread,NULL,"Godness_requirments_thread");
  65.         return 0;
  66. }
  67. static void __exit godness_exit_notifier(void)
  68. {
  69.         printk("[Attention]The Godness leaving out!\n");
  70. }
  71. module_init(godness_init_notifier);
  72. module_exit(godness_exit_notifier);

    这个时候有个叫土豪的家伙,突然于茫茫人海中发现了女神,并且知道了女神有金钱需求的欲望,于是土豪向女神的需求链里注册了一个金钱的响应函数,这样一旦女神需要用钱的时候他第一时间就能收到通知,然后以迅雷下载不及掩耳盗铃之势加以满足:

点击(此处)折叠或打开

  1. /*Tuhao.c*/
  2. extern int register_godness_notifier(struct notifier_block*);
  3. extern int unregister_godness_notifier(struct notifier_block*);
  4. static int baby_need_money(struct notifier_block *this, unsigned long event, void *ptr)
  5. {
  6.         if(event != 0)  //不是金钱需求关我鸟事
  7.         {
  8.             return NOTIFY_DONE; //Don't care
  9.         }
  10.         printk("[Tuhao]Hi Baby,$$$$$$$$ 么么哒 \n");
  11.         return NOTIFY_OK;
  12. }
  13. static struct notifier_block cash_notifier =
  14. {
  15.         .notifier_call = baby_need_money,
  16.         .priority = 2,
  17. };
  18. static int __init tuhao_register(void)
  19. {
  20.         int err;
  21.         printk("[Tuhao]Tuhao register cash_requirment response to Godness...");
  22.         err = register_godness_notifier(&cash_notifier);
  23.         if (err)
  24.         {
  25.                 printk("Refused!\n");
  26.                 return -1;
  27.         }
  28.         printk("Accepted!\n");
  29.         return err;
  30. }
  31. static void __exit tuhao_unregister(void)
  32. {
  33.         unregister_godness_notifier(&cash_notifier);
  34.         printk("[Tuhao]Tuhao is giving up Godness!(Son of bitch)\n");
  35. }
  36. module_init(tuhao_register);
  37. module_exit(tuhao_unregister);

   这时,有一个屌丝,也于茫茫人海中发现了女神,他发现女神喜欢音乐,于是他开始响应女神的精神需求:

点击(此处)折叠或打开

  1. /*Diors.c*/
  2. extern int register_godness_notifier(struct notifier_block*);
  3. extern int unregister_godness_notifier(struct notifier_block*);
  4. static int godness_need_music(struct notifier_block *this, unsigned long event, void *ptr)
  5. {
  6.         if(event != 1) //我又没钱,给不了你大房子、气派的车子...
  7.         {
  8.             return NOTIFY_DONE; //Don't care
  9.         }
  10.         printk("[Diors]Hi girl,This is a classic Music disk,take it. \n");
  11.         return NOTIFY_OK;
  12. }
  13. static struct notifier_block music_notifier =
  14. {
  15.         .notifier_call = godness_need_music,
  16.         .priority = 2,
  17. };
  18. static int __init diors_register(void)
  19. {
  20.         int err;
  21.         printk("[Diors]Diors register music_requirment response to Godness...");
  22.         err = register_godness_notifier(&music_notifier);
  23.         if (err)
  24.         {
  25.                 printk("Refused!\n");
  26.                 return -1;
  27.         }
  28.         printk("Accepted!\n");
  29.         return err;
  30. }
  31. static void __exit diors_unregister(void)
  32. {
  33.         unregister_godness_notifier(&music_notifier);
  34.         printk("[Diors]Tuhao is giving up Godness!(What a pity)\n");
  35. }
  36. module_init(diors_register);
  37. module_exit(diors_unregister);

    好的,到此为止,一切就绪,好戏正式开始:

点击(此处)折叠或打开

  1. #Makefile for fun
  2. obj-m:=Goddess.o Tuhao.o Diors.o
  3. CURRENT_PATH := $(shell pwd)
  4. KERNEL_VERSION := $(shell uname -r)
  5. KERNEL_HEADER_DIR := /usr/src/kernels/$(LINUX_KERNELKERNEL_VERSION)
  6. all:
  7.         make -C $(KERNEL_HEADER_DIR) M=$(CURRENT_PATH) modules
  8. clean:
  9.         make -C $(KERNEL_HEADER_DIR) M=$(CURRENT_PATH) clean

   主角们闪亮登场:

   It's time time to show :)

   我们可以看到,女神初到人间时需要用钱,结果没人搭理,去了趟韩国回来之后,被土豪给瞄到了,于是土豪开始大把大把地视金钱如粪土。过了8秒钟,屌丝男也发现了女神,当女神想听歌时屌丝男就屁颠屁颠地把自己珍藏了多年的古典乐光盘送给了女神。最后剧中,谢幕。

   OK,让我们总结一下Linux内核通知链的应用场景。如果一个子系统需要向外通告事件时,它需要首先定义自己的通知链对象,然后向内核里其他子系统提供一个向自己的通知链注册消息响应函数的接口,当然也必须提供一个用于从自己从自己的通知链上卸载响应函数的接口。接下来,我们这个子系统要做的事情就是根据自己的实际运行情况,定期地产生一些消息,并调用自己通知链里别的系统已经注册好了消息响应函数,这样别的子系统就可以根据我们这个系统的的消息类型进行一些处理动作。
   那么多个子系统对我们的同一种消息都挂有响应函数时该怎么处理?鉴于时间关系,下次再叙。
   未完,待续...

时间: 2024-09-17 22:53:53

Linux 内核通知链随笔【中】【转】的相关文章

Linux内核通知链机制的原理及实现【转】

转自:http://www.cnblogs.com/armlinux/archive/2011/11/11/2396781.html 一.概念:     大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,Linux内核提供了通知链的机制.通知链表只能够在内核的子系统之间使用,而不能够在内核与用户空间之间进行事件的通知. 通知链表是一个函数链表,链表上的每一个节点都注册了一个函数.当某个事情发生时,

Linux内核通知链分析【转】

转自:http://www.cnblogs.com/jason-lu/articles/2807758.html Linux内核通知链分析 1. 引言 Linux是单内核架构(monolithic kernel),大多数内核子系统和模块是相互独立的,它们被动态地加载或卸载,以使内核变得小巧和可扩展.然而,子系统或模块之间需要通信,或者说某个特定模块扑捉到的事件可能其它模块对此感兴趣,这就需要一种机制来满足子系统或模块之间交互的需求. Linux使用通知链表来实现这一需求,它是一个简单的函数链表,

notifier chain — 内核通知链【转】

转自:http://blog.csdn.net/g_salamander/article/details/8081724 大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,Linux内核提供了通知链的机制.通知链表只能够在内核的子系统之间使用,而不能够在内核与用户空间之间进行事件的通知.通知链表是一个函数链表,链表上的每一个节点都注册了一个函数.当某个事情发生时,链表上所有节点对应的函数就会被执行

Linux内核系列—C语言中内嵌汇编 asm __volatile__,asm__volatile_【转】

转自:http://www.bkjia.com/Androidjc/1109412.html 在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作. 1.简单的内嵌汇编例:        __asm__ __volatile__("hlt"); "__asm__"表示后面的代码为内嵌

Linux内核基础--事件通知链(notifier chain)good【转】

转自:http://www.cnblogs.com/pengdonglin137/p/4075148.html 阅读目录(Content) 1.1. 概述 1.2.数据结构  1.3.  运行机理 1.4.  简单一例:  一.概述 二.结构体 三.操作过程 四.实例 转载: http://blog.csdn.net/wuhzossibility/article/details/8079025 http://blog.chinaunix.net/uid-27717694-id-4286337.h

Linux内核基础--事件通知链(notifier chain)【转】

转自:http://blog.csdn.net/wuhzossibility/article/details/8079025 内核通知链 1.1. 概述        Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,就必须使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施.为满足这样的需求,内核实现了事件通知链机制(notificationchain).        通知链只能用在各个子系统之间,而不能在内核和用户空间进行事件的通知.组成内核的核心系统代

SYN Cookie在Linux内核中的实现_unix linux

概述 在目前以IPv4为支撑的网络协议上搭建的网络环境中,SYN Flood是一种非常危险而常见的DoS攻击方式.到目前为止,能够有效防范SYN Flood攻击的手段并不多,而SYN Cookie就是其中最著名的一种.SYN Cookie原理由D. J. Bernstain和 Eric Schenk发明.在很多操作系统上都有各种各样的实现.其中包括Linux.本文就分别介绍一下SYN Flood攻击和SYN Cookie的原理,更重要的是介绍Linux内核中实现SYN Cookie的方式.最后,

大话Linux内核中锁机制之RCU、大内核锁

大话Linux内核中锁机制之RCU.大内核锁 在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linux内核中锁机制>系列博文进行了总结,并提出关于目前Linux内核中提供的锁机制的一些基本使用观点. 十.RCU机制 本节将讨论另一种重要锁机制:RCU锁机制.首先我们从概念上理解下什么叫RCU,其中读(Read):读者不需要获得任何锁就可访问RCU保护的临界

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】

原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja  转自:http://blog.chinaunix.net/uid-25909619-id-4938390.html   在构架相关的汇编代码运行完之后,程序跳入了构架无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段,      下面我就顺这代码逐个函数的解释,但是这