亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 52207 | 回復(fù): 51
打印 上一主題 下一主題

內(nèi)核通知鏈 學(xué)習(xí)筆記 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2008-12-09 18:34 |只看該作者 |倒序?yàn)g覽
最近在看《深入理解Linux網(wǎng)絡(luò)內(nèi)幕》一書,學(xué)習(xí)了一下書中講到的內(nèi)核通知鏈方面的知識,寫了一個(gè)讀書筆記和一點(diǎn)代碼來加深理解,希望能夠?qū)Υ蠹矣幸稽c(diǎn)幫助。內(nèi)核通知鏈在網(wǎng)絡(luò)方面得到了廣泛的使用。


1.通知鏈表簡介
    大多數(shù)內(nèi)核子系統(tǒng)都是相互獨(dú)立的,因此某個(gè)子系統(tǒng)可能對其它子系統(tǒng)產(chǎn)生的事件感興趣。為了滿足這個(gè)需求,也即是讓某個(gè)子系統(tǒng)在發(fā)生某個(gè)事件時(shí)通知其它的子系統(tǒng),Linux內(nèi)核提供了通知鏈的機(jī)制。通知鏈表只能夠在內(nèi)核的子系統(tǒng)之間使用,而不能夠在內(nèi)核與用戶空間之間進(jìn)行事件的通知。
    通知鏈表是一個(gè)函數(shù)鏈表,鏈表上的每一個(gè)節(jié)點(diǎn)都注冊了一個(gè)函數(shù)。當(dāng)某個(gè)事情發(fā)生時(shí),鏈表上所有節(jié)點(diǎn)對應(yīng)的函數(shù)就會被執(zhí)行。所以對于通知鏈表來說有一個(gè)通知方與一個(gè)接收方。在通知這個(gè)事件時(shí)所運(yùn)行的函數(shù)由被通知方?jīng)Q定,實(shí)際上也即是被通知方注冊了某個(gè)函數(shù),在發(fā)生某個(gè)事件時(shí)這些函數(shù)就得到執(zhí)行。其實(shí)和系統(tǒng)調(diào)用signal的思想差不多。

2.通知鏈表數(shù)據(jù)結(jié)構(gòu)
    通知鏈表的節(jié)點(diǎn)類型為notifier_block,其定義如下:

  1. struct notifier_block
  2. {
  3.     int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
  4.     struct notifier_block *next;
  5.     int priority;
  6. };
復(fù)制代碼

    其中最重要的就是notifier_call這個(gè)函數(shù)指針,表示了這個(gè)節(jié)點(diǎn)所對應(yīng)的要運(yùn)行的那個(gè)函數(shù)。next指向下一個(gè)節(jié)點(diǎn),即當(dāng)前事件發(fā)生時(shí)還要繼續(xù)執(zhí)行的那些節(jié)點(diǎn)。

3.注冊通知鏈
    在通知鏈注冊時(shí),需要有一個(gè)鏈表頭,它指向這個(gè)通知鏈表的第一個(gè)元素。這樣,之后的事件對該鏈表通知時(shí)就會根據(jù)這個(gè)鏈表頭而找到這個(gè)鏈表中所有的元素。
    注冊的函數(shù)是:
int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n)
    也即是將新的節(jié)點(diǎn)n加入到nl所指向的鏈表中去。
    卸載的函數(shù)是:
int notifier_chain_unregister(strut notifier_block **nl, struct notifier_block *n)
    也即是將節(jié)點(diǎn)n從nl所指向的鏈表中刪除。

4.通知鏈表
    當(dāng)有事件發(fā)生時(shí),就使用notifier_call_chain向某個(gè)通知鏈表發(fā)送消息。
int notifier_call_chain(struct notifier_block **nl, unsigned long val, void *v)
    這個(gè)函數(shù)是按順序運(yùn)行nl指向的鏈表上的所有節(jié)點(diǎn)上注冊的函數(shù)。簡單地說,如下所示:

  1.     struct notifier_block *nb = *n;

  2.     while (nb)
  3.     {
  4.         ret = nb->notifier_call(nb, val, v);
  5.         if (ret & NOTIFY_STOP_MASK)
  6.         {
  7.             return ret;
  8.         }
  9.         nb = nb->next;
  10.     }
復(fù)制代碼


5.示例
    在這里,寫了一個(gè)簡單的通知鏈表的代碼。

    實(shí)際上,整個(gè)通知鏈的編寫也就兩個(gè)過程:
    首先是定義自己的通知鏈的頭節(jié)點(diǎn),并將要執(zhí)行的函數(shù)注冊到自己的通知鏈中。
    其次則是由另外的子系統(tǒng)來通知這個(gè)鏈,讓其上面注冊的函數(shù)運(yùn)行。

    我這里將第一個(gè)過程分成了兩步來寫,第一步是定義了頭節(jié)點(diǎn)和一些自定義的注冊函數(shù)(針對該頭節(jié)點(diǎn)的),第二步則是使用自定義的注冊函數(shù)注冊了一些通知鏈節(jié)點(diǎn)。分別在代碼buildchain.c與regchain.c中。
    發(fā)送通知信息的代碼為notify.c。

代碼1 buildchain.c
    它的作用是自定義一個(gè)通知鏈表test_chain,然后再自定義兩個(gè)函數(shù)分別向這個(gè)通知鏈中加入或刪除節(jié)點(diǎn),最后再定義一個(gè)函數(shù)通知這個(gè)test_chain鏈。


  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. MODULE_LICENSE("GPL");

  10. /*
  11. * 定義自己的通知鏈頭結(jié)點(diǎn)以及注冊和卸載通知鏈的外包函數(shù)
  12. */

  13. /*
  14. * RAW_NOTIFIER_HEAD是定義一個(gè)通知鏈的頭部結(jié)點(diǎn),
  15. * 通過這個(gè)頭部結(jié)點(diǎn)可以找到這個(gè)鏈中的其它所有的notifier_block
  16. */

  17. static RAW_NOTIFIER_HEAD(test_chain);

  18. /*
  19. * 自定義的注冊函數(shù),將notifier_block節(jié)點(diǎn)加到剛剛定義的test_chain這個(gè)鏈表中來
  20. * raw_notifier_chain_register會調(diào)用notifier_chain_register
  21. */

  22. int register_test_notifier(struct notifier_block *nb)
  23. {
  24.         return raw_notifier_chain_register(&test_chain, nb);
  25. }
  26. EXPORT_SYMBOL(register_test_notifier);

  27. int unregister_test_notifier(struct notifier_block *nb)
  28. {
  29.         return raw_notifier_chain_unregister(&test_chain, nb);
  30. }
  31. EXPORT_SYMBOL(unregister_test_notifier);

  32. /*
  33. * 自定義的通知鏈表的函數(shù),即通知test_chain指向的鏈表中的所有節(jié)點(diǎn)執(zhí)行相應(yīng)的函數(shù)
  34. */

  35. int test_notifier_call_chain(unsigned long val, void *v)
  36. {
  37.         return raw_notifier_call_chain(&test_chain, val, v);
  38. }
  39. EXPORT_SYMBOL(test_notifier_call_chain);

  40. /*
  41. * init and exit
  42. */

  43. static int __init init_notifier(void)
  44. {
  45.         printk("init_notifier\n");
  46.         return 0;
  47. }

  48. static void __exit exit_notifier(void)
  49. {
  50.         printk("exit_notifier\n");
  51. }
  52. module_init(init_notifier);
  53. module_exit(exit_notifier);
復(fù)制代碼


代碼2 regchain.c
    該代碼的作用是將test_notifier1 test_notifier2 test_notifier3這三個(gè)節(jié)點(diǎn)加到之前定義的test_chain這個(gè)通知鏈表上,同時(shí)每個(gè)節(jié)點(diǎn)都注冊了一個(gè)函數(shù)。


  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. MODULE_LICENSE("GPL");

  10. /*
  11. * 注冊通知鏈
  12. */

  13. extern int register_test_notifier(struct notifier_block*);

  14. extern int unregister_test_notifier(struct notifier_block*);

  15. static int test_event1(struct notifier_block *this, unsigned long event, void *ptr)
  16. {
  17.         printk("In Event 1: Event Number is %d\n", event);
  18.         return 0;
  19. }

  20. static int test_event2(struct notifier_block *this, unsigned long event, void *ptr)
  21. {
  22.         printk("In Event 2: Event Number is %d\n", event);
  23.         return 0;
  24. }

  25. static int test_event3(struct notifier_block *this, unsigned long event, void *ptr)
  26. {
  27.         printk("In Event 3: Event Number is %d\n", event);
  28.         return 0;
  29. }

  30. /*
  31. * 事件1,該節(jié)點(diǎn)執(zhí)行的函數(shù)為test_event1
  32. */

  33. static struct notifier_block test_notifier1 =
  34. {
  35.         .notifier_call = test_event1,
  36. };

  37. /*
  38. * 事件2,該節(jié)點(diǎn)執(zhí)行的函數(shù)為test_event1
  39. */

  40. static struct notifier_block test_notifier2 =
  41. {
  42.         .notifier_call = test_event2,
  43. };

  44. /*
  45. * 事件3,該節(jié)點(diǎn)執(zhí)行的函數(shù)為test_event1
  46. */

  47. static struct notifier_block test_notifier3 =
  48. {
  49.         .notifier_call = test_event3,
  50. };

  51. /*
  52. * 對這些事件進(jìn)行注冊
  53. */

  54. static int __init reg_notifier(void)
  55. {
  56.         int err;
  57.         printk("Begin to register:\n");
  58.        
  59.         err = register_test_notifier(&test_notifier1);
  60.         if (err)
  61.         {
  62.                 printk("register test_notifier1 error\n");
  63.                 return -1;
  64.         }
  65.         printk("register test_notifier1 completed\n");

  66.         err = register_test_notifier(&test_notifier2);
  67.         if (err)
  68.         {
  69.                 printk("register test_notifier2 error\n");
  70.                 return -1;
  71.         }
  72.         printk("register test_notifier2 completed\n");

  73.         err = register_test_notifier(&test_notifier3);
  74.         if (err)
  75.         {
  76.                 printk("register test_notifier3 error\n");
  77.                 return -1;
  78.         }
  79.         printk("register test_notifier3 completed\n");
  80.         return err;
  81. }

  82. /*
  83. * 卸載剛剛注冊了的通知鏈
  84. */

  85. static void __exit unreg_notifier(void)
  86. {
  87.         printk("Begin to unregister\n");
  88.         unregister_test_notifier(&test_notifier1);
  89.         unregister_test_notifier(&test_notifier2);
  90.         unregister_test_notifier(&test_notifier3);
  91.         printk("Unregister finished\n");
  92. }
  93. module_init(reg_notifier);
  94. module_exit(unreg_notifier);
復(fù)制代碼


代碼3 notify.c
    該代碼的作用就是向test_chain通知鏈中發(fā)送消息,讓鏈中的函數(shù)運(yùn)行。

  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. MODULE_LICENSE("GPL");

  10. extern int test_notifier_call_chain(unsigned long val, void *v);

  11. /*
  12. * 向通知鏈發(fā)送消息以觸發(fā)注冊了的函數(shù)
  13. */

  14. static int __init call_notifier(void)
  15. {
  16.         int err;
  17.         printk("Begin to notify:\n");

  18. /*
  19. * 調(diào)用自定義的函數(shù),向test_chain鏈發(fā)送消息
  20. */

  21.         printk("==============================\n");
  22.         err = test_notifier_call_chain(1, NULL);
  23.         printk("==============================\n");
  24.         if (err)
  25.                 printk("notifier_call_chain error\n");
  26.         return err;
  27. }


  28. static void __exit uncall_notifier(void)
  29. {
  30.         printk("End notify\n");
  31. }
  32. module_init(call_notifier);
  33. module_exit(uncall_notifier);
復(fù)制代碼


Makefile文件

  1. obj-m:=buildchain.o regchain.o notify.o

  2. KERNELDIR:=/lib/modules/$(shell uname -r)/build

  3. default:
  4.         make -C $(KERNELDIR) M=$(shell pwd) modules
復(fù)制代碼


運(yùn)行:

  1. make

  2. insmod buildchain.ko
  3. insmod regchain.ko
  4. insmod notify.ko
復(fù)制代碼


這樣就可以看到通知鏈運(yùn)行的效果了

下面是我在自己的機(jī)器上面運(yùn)行得到的結(jié)果:
init_notifier
Begin to register:
register test_notifier1 completed
register test_notifier2 completed
register test_notifier3 completed
Begin to notify:
==============================
In Event 1: Event Number is 1
In Event 2: Event Number is 1
In Event 3: Event Number is 1
==============================

[ 本帖最后由 scutan 于 2008-12-11 22:33 編輯 ]

評分

參與人數(shù) 1可用積分 +6 收起 理由
Roemer + 6 精品文章

查看全部評分

論壇徽章:
36
IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-10 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-16 06:20:0015-16賽季CBA聯(lián)賽之廣東
日期:2016-04-16 19:59:32IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-18 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-19 06:20:00每日論壇發(fā)貼之星
日期:2016-04-19 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-25 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-06 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-08 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-13 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-28 06:20:00每日論壇發(fā)貼之星
日期:2016-05-28 06:20:00
2 [報(bào)告]
發(fā)表于 2008-12-09 19:49 |只看該作者
很佩服scutan兄邊學(xué)習(xí)邊總結(jié)的能力,而且經(jīng)常是獨(dú)立寫出例程。贊一個(gè)

論壇徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辭舊歲徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
3 [報(bào)告]
發(fā)表于 2008-12-09 20:26 |只看該作者
不錯(cuò),學(xué)習(xí)了

論壇徽章:
36
IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-10 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-16 06:20:0015-16賽季CBA聯(lián)賽之廣東
日期:2016-04-16 19:59:32IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-18 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-19 06:20:00每日論壇發(fā)貼之星
日期:2016-04-19 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-25 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-06 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-08 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-13 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-28 06:20:00每日論壇發(fā)貼之星
日期:2016-05-28 06:20:00
4 [報(bào)告]
發(fā)表于 2008-12-09 20:29 |只看該作者
例程簡單明了,但又展示了notifier的使用方法。以前沒時(shí)間寫程序?qū)嵺`一下,直接實(shí)踐了scutan兄的程序。

論壇徽章:
0
5 [報(bào)告]
發(fā)表于 2008-12-09 20:35 |只看該作者
學(xué)習(xí)了:wink:

論壇徽章:
0
6 [報(bào)告]
發(fā)表于 2008-12-09 22:51 |只看該作者
當(dāng)出看得時(shí)候我也總結(jié)了一篇,但是感覺還是有差距啊。
還得繼續(xù)提升總結(jié)能力

論壇徽章:
0
7 [報(bào)告]
發(fā)表于 2008-12-09 22:54 |只看該作者
我頂~~你個(gè)肺~~

論壇徽章:
36
IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-10 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-16 06:20:0015-16賽季CBA聯(lián)賽之廣東
日期:2016-04-16 19:59:32IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-18 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-19 06:20:00每日論壇發(fā)貼之星
日期:2016-04-19 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-04-25 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-06 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-08 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-13 06:20:00IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-05-28 06:20:00每日論壇發(fā)貼之星
日期:2016-05-28 06:20:00
8 [報(bào)告]
發(fā)表于 2008-12-10 09:59 |只看該作者
原帖由 emmoblin 于 2008-12-9 22:51 發(fā)表
當(dāng)出看得時(shí)候我也總結(jié)了一篇,但是感覺還是有差距啊。
還得繼續(xù)提升總結(jié)能力


呵呵,兄臺過謙了。有什么總結(jié)文章及時(shí)發(fā)上來,大家一起研究,也可以有助你完善和豐富你的總結(jié)啊。

論壇徽章:
0
9 [報(bào)告]
發(fā)表于 2008-12-10 14:43 |只看該作者
原帖由 emmoblin 于 2008-12-9 22:51 發(fā)表
當(dāng)出看得時(shí)候我也總結(jié)了一篇,但是感覺還是有差距啊。
還得繼續(xù)提升總結(jié)能力


兄弟過獎(jiǎng)了。大家多多交流,進(jìn)步才快。

論壇徽章:
0
10 [報(bào)告]
發(fā)表于 2008-12-10 15:11 |只看該作者
收藏 學(xué)習(xí)
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP