从基本理解到深入探究 Linux kernel 通知链(notifier chain)【转】

转自:https://blog.csdn.net/u014134180/article/details/86563754

版权声明:本文为博主原创文章,未经博主允许不得转载。——Wu_Being https://blog.csdn.net/u014134180/article/details/86563754 文章目录 基本理解Linux 内核事件通知链 1. TP 驱动相关代码 2. LCM 背光相关代码 3. 运行结果 深入探究Linux 内核事件通知链 1. 通知链的引入 2. 四种通知链的类型 原子通知链(Atomic notifier chains) 可阻塞通知链(Blocking notifier chains) 原始通知链(Raw notifierchains) SRCU 通知链(SRCU notifier chains) 3. 一个简单的通知链实例 基本理解Linux 内核事件通知链 内核事件通知链一个比较典型的例子就是Display 背光通知TP suspend和resume 的过程,我们这里先从高通平台的LCD 背光通知TP suspend 入场,以快速理解Linux 内核事件通知链应用。

1. TP 驱动相关代码 kernel/msm-4.9/drivers/input/touchscreen/xxxxx_touch/xxxx_core.c TP 驱动probe 函数里指定到背光通知回调函数fb_notifier_callback,并注册到通知链里。fb_notifier_callback 函数根据收到的通知event信息调用TS resume 或suspend 函数。

static int xxx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { ... ... ts_data->fb_notif.notifier_call = fb_notifier_callback; ret = fb_register_client(&ts_data->fb_notif); }

static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct fb_event *evdata = data; int *blank; struct xxx_ts_data *xxx_data = container_of(self, struct xxx_ts_data, fb_notif); printk("[xxx][WU] event = %ld, FB_EVENT_BLANK = %d or FB_EARLY_EVENT_BLANK = %d", event, FB_EVENT_BLANK); //16 == 9 or 16; 9 == 9 or 16 if (evdata && evdata->data && event == FB_EARLY_EVENT_BLANK \ && fts_data && fts_data->client) { blank = evdata->data; printk("[FTS][WU] blank = %d", *blank);

if (*blank == FB_BLANK_UNBLANK){//0 printk("[FTS][WU] fts_ts_resume FB_BLANK_UNBLANK = %d", FB_BLANK_UNBLANK); fts_ts_resume(&fts_data->client->dev); } else if (*blank == FB_BLANK_POWERDOWN){//4 printk("[FTS][WU] fts_ts_suspend FB_BLANK_POWERDOWN = %d", FB_BLANK_POWERDOWN); fts_ts_suspend(&fts_data->client->dev); } } return 0; } 注:若对上面container_of有题问,可参考文章 《从基本理解到深入探究Linux kernel container_of 宏》

2. LCM 背光相关代码 kernel/msm-4.9/drivers/video/fbdev/core/fbmem.c LCM 背光代码根据相关场景给通知链发送相关事件的通知,通知链收到通知就执行上面的背光通知回调函数fb_notifier_callback,fb_notifier_callback函数根据不同event事件执行不同的函数。

int fb_blank(struct fb_info *info, int blank) { ... early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);// FB_EARLY_EVENT_BLANK = 16 if (info->fbops->fb_blank) ret = info->fbops->fb_blank(blank, info); if (!ret) fb_notifier_call_chain(FB_EVENT_BLANK, &event); //FB_EVENT_BLANK = 9 else { /** if fb_blank is failed then revert effects of * the early blank event. */ if (!early_ret) fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event); } return ret; } ... void fb_set_suspend(struct fb_info *info, int state) { struct fb_event event; event.info = info; if (state) { fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); // FB_EVENT_SUSPEND = 0x02 info->state = FBINFO_STATE_SUSPENDED; } else { info->state = FBINFO_STATE_RUNNING; fb_notifier_call_chain(FB_EVENT_RESUME, &event); // FB_EVENT_RESUME = 0x03 } } 3. 运行结果 下面是板子运行的log(已经屏蔽客户信息),我们在下面在log解释原理比较简明吧! 从运行结果可以知道高通背光通知TP过程中,先休眠TP再休眠LCM。

[ 1045.412245] PM: suspend entry 2019-01-13 19:15:43.130364966 UTC // linux kernel 进入休眠 // 退出休眠与进入休眠的UTC时间戳一差,就是kernel 休眠的时间(19:15:55 - 19:15:43) // 按电源键唤醒系统亮屏 ... ... [ 1050.799717] PM: suspend exit 2019-01-13 19:15:55.594697461 UTC // linux kernel 退出休眠 [ 1051.144198] [xxx][WU] event = 16, FB_EVENT_BLANK = 9 // 背光发送两次event,一次是16一次是9 [ 1051.144211] [xxx][WU] event = 9, FB_EVENT_BLANK = 9 [ 1051.144221] [xxx][WU] blank = 0 // 其中参数的blank 为0 调用TP resume [ 1051.144232] [xxx][WU] xxx_ts_resume FB_BLANK_UNBLANK = 0 [ 1051.144233] [xxx]xxx_ts_resume: Enter [ 1051.146266] [xxx]xxx_ts_resume: Exit(1668) // 亮屏了10s后,按电源键灭屏 ... ... [ 1061.519665] [xxx][WU] event = 16, FB_EVENT_BLANK = 9 // 背光发送两次event,一次是16一次是9 [ 1061.519680] [xxx][WU] event = 9, FB_EVENT_BLANK = 9 [ 1061.519690] [xxx][WU] blank = 4 // 其中参数的blank 为4 调用TP suspend [ 1061.519702] [xxx][WU] xxx_ts_suspend FB_BLANK_POWERDOWN = 4 [ 1061.519703] [xxx]xxx_ts_suspend: Enter [ 1061.523594] [xxx]xxx_ts_suspend: Exit(1609) [ 1061.528000]  mdss_dsi_panel_power_off // 然后高通display 下电 [ 1061.529240] hbtp: hbtp->input_dev not ready! [ 1061.532073] PM: suspend entry 2019-01-13 19:16:06.327045373 UTC ... [ 1061.649485] PM: suspend exit 2019-01-13 19:16:06.444469957 UTC [ 1061.853378] PM: suspend entry 2019-01-13 19:16:06.648349227 UTC [ 1061.853419] PM: Syncing filesystems ... done. [ 1061.888011] PM: Preparing system for sleep (mem) [ 1061.888187] Freezing user space processes ... (elapsed 3.964 seconds) done. [ 1065.852448] Freezing remaining freezable tasks ... (elapsed 0.009 seconds) done. [ 1065.861693] PM: Suspending system (mem) [ 1065.861723] Suspending console(s) (use no_console_suspend to debug) // 因为TP已经休眠了, 上面 fb_set_suspend 函数也发来fb set supend 事件,不过这次已经无效了 [ 1065.895347] [xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend [ 1065.933676] [xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend [ 1066.742596] PM: suspend exit 2019-01-13 19:16:27.002118646 UTC 总结下来就三个函数:

int fb_register_client(struct notifier_block *nb) int fb_unregister_client(struct notifier_block *nb) int fb_notifier_call_chain(unsigned long val, void *v) 上面三个函数就只是简单调用系统接口,如下代码 linux/drivers/video/fbdev/core/fb_notify.c

/* * linux/drivers/video/fb_notify.c * * Copyright (C) 2006 Antonino Daplas <adaplas@pol.net> * * 2001 - Documented with DocBook * - Brad Douglas <brad@neruo.com> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. */ #include <linux/fb.h> #include <linux/notifier.h> #include <linux/export.h>

static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);

/** * fb_register_client - register a client notifier * @nb: notifier block to callback on events */ int fb_register_client(struct notifier_block *nb) { return blocking_notifier_chain_register(&fb_notifier_list, nb); } EXPORT_SYMBOL(fb_register_client);

/** * fb_unregister_client - unregister a client notifier * @nb: notifier block to callback on events */ int fb_unregister_client(struct notifier_block *nb) { return blocking_notifier_chain_unregister(&fb_notifier_list, nb); } EXPORT_SYMBOL(fb_unregister_client);

/** * fb_notifier_call_chain - notify clients of fb_events * */ int fb_notifier_call_chain(unsigned long val, void *v) { return blocking_notifier_call_chain(&fb_notifier_list, val, v); } EXPORT_SYMBOL_GPL(fb_notifier_call_chain);

注:EXPORT_SYMBOL_GPL 是导出参数的函数给kernel其他地方使用,要加include头文件。

一般会使用这个几个接口就行了,若不想放弃请看下面深入探究Linux 内核事件通知链。

深入探究Linux 内核事件通知链 1. 通知链的引入 Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,就必须使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施。为满足这样的需求,内核实现了事件通知链机制(notification chain)。 通知链只能用在各个子系统之间,而不能在内核和用户空间进行事件的通知。组成内核的核心系统代码均位于kernel目录下,通知链表位于kernel/notifier.c中,对应的头文件为include/linux/notifier.h。 事件通知链表是一个事件处理函数的列表,每个通知链都与某个或某些事件有关,当特定的事件发生时,就调用相应的事件通知链中的回调函数,进行相应的处理。

2. 四种通知链的类型 内核使用struct notifier_block结构代表一个notifier

struct notifier_block; typedef int (*notifier_fn_t)(struct notifier_block *nb, unsigned long action, void *data); //notifier回调函数类型 struct notifier_block { notifier_fn_t notifier_call; //回调函数 struct notifier_block __rcu *next; //用于挂到通知链上 int priority; }; //notifier 结构体 内核提供了四种不同类型的notifier chain,notifier block 和 notifier chain的数据结构组织方式如下:

原子通知链(Atomic notifier chains) 之所以被称为原子通知链,是因为通知链元素的回调函数(当事件发生时要执行的函数)在中断或原子操作上下文中运行,不允许阻塞。

struct atomic_notifier_head { spinlock_t lock; // 自旋锁保护通知链 struct notifier_block __rcu *head; //通知链元素的链表 }; 原子通知链对应的API

//1.初始化一个原子通知链 #define ATOMIC_NOTIFIER_HEAD(name) \ struct atomic_notifier_head name = \ ATOMIC_NOTIFIER_INIT(name) //2.注册一个notifier block 到通知链 extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *nb); //3.发送一个事件到通知链上的notifier block extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v); //4.从通知链删除一个notifier block extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *nb);

相关函数定义如下

/* * Atomic notifier chain routines. Registration and unregistration * use a spinlock, and call_chain is synchronized by RCU (no locks). */ int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *n) { unsigned long flags; int ret; spin_lock_irqsave(&nh->lock, flags); ret = notifier_chain_register(&nh->head, n); spin_unlock_irqrestore(&nh->lock, flags); return ret; } int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *n) { unsigned long flags; int ret; spin_lock_irqsave(&nh->lock, flags); ret = notifier_chain_unregister(&nh->head, n); spin_unlock_irqrestore(&nh->lock, flags); synchronize_rcu(); return ret; } /** * Calls each function in a notifier chain in turn. The functions * run in an atomic context, so they must not block. * This routine uses RCU to synchronize with changes to the chain. */ int __atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v, int nr_to_call, int *nr_calls) { int ret; rcu_read_lock(); ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); rcu_read_unlock(); return ret; } int atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v) { return __atomic_notifier_call_chain(nh, val, v, -1, NULL); } 可阻塞通知链(Blocking notifier chains) 通知链元素的回调函数在进程上下文中运行,允许阻塞。

struct blocking_notifier_head { struct rw_semaphore rwsem; struct notifier_block *head; }; 可阻塞通知链对应的API

//1.初始化一个阻塞通知链 #define BLOCKING_NOTIFIER_HEAD(name) \ struct blocking_notifier_head name = \ BLOCKING_NOTIFIER_INIT(name) //2.注册一个notifier block 到通知链 extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *nb); //3.发送一个事件到通知链上的notifier block extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v); //4.从通知链删除一个notifier block extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, struct notifier_block *nb);

相关函数定义如下

/* * Blocking notifier chain routines. All access to the chain is * synchronized by an rwsem. */ int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *n) { int ret; /* * This code gets used during boot-up, when task switching is * not yet working and interrupts must remain disabled. At * such times we must not call down_write(). */ if (unlikely(system_state == SYSTEM_BOOTING)) return notifier_chain_register(&nh->head, n); down_write(&nh->rwsem); ret = notifier_chain_register(&nh->head, n); up_write(&nh->rwsem); return ret; } int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, struct notifier_block *n) { int ret; /* * This code gets used during boot-up, when task switching is * not yet working and interrupts must remain disabled. At * such times we must not call down_write(). */ if (unlikely(system_state == SYSTEM_BOOTING)) return notifier_chain_unregister(&nh->head, n); down_write(&nh->rwsem); ret = notifier_chain_unregister(&nh->head, n); up_write(&nh->rwsem); return ret; } int __blocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v, int nr_to_call, int *nr_calls) { int ret = NOTIFY_DONE; /* * We check the head outside the lock, but if this access is * racy then it does not matter what the result of the test * is, we re-check the list after having taken the lock anyway: */ if (rcu_access_pointer(nh->head)) { down_read(&nh->rwsem); ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); up_read(&nh->rwsem); } return ret; } int blocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v) { return __blocking_notifier_call_chain(nh, val, v, -1, NULL); }

原始通知链(Raw notifierchains) 对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护。

struct raw_notifier_head { struct notifier_block *head; }; 原始通知链对应的API

//1.初始化一个原始通知链 #define RAW_NOTIFIER_HEAD(name) \ struct raw_notifier_head name = \ RAW_NOTIFIER_INIT(name) //2.注册一个notifier block 到通知链 extern int raw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *nb); //3.发送一个事件到通知链上的notifier block extern int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v); //4.从通知链删除一个notifier block extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh, struct notifier_block *nb); 相关函数定义如下

/* * Raw notifier chain routines. There is no protection; * the caller must provide it. Use at your own risk! */ int raw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *n) { return notifier_chain_register(&nh->head, n); } int raw_notifier_chain_unregister(struct raw_notifier_head *nh, struct notifier_block *n) { return notifier_chain_unregister(&nh->head, n); } int __raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v, int nr_to_call, int *nr_calls) { return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); } int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v) { return __raw_notifier_call_chain(nh, val, v, -1, NULL); }

SRCU 通知链(SRCU notifier chains) 可阻塞通知链的一种变体。对应的链表头:

struct srcu_notifier_head { struct mutex mutex; struct srcu_struct srcu; struct notifier_block *head; }; SRCU 通知链对应的API

//1.初始化一个SRCU通知链 #ifdef CONFIG_TREE_SRCU #define _SRCU_NOTIFIER_HEAD(name, mod) \ static DEFINE_PER_CPU(struct srcu_data, name##_head_srcu_data); \ mod struct srcu_notifier_head name = \ SRCU_NOTIFIER_INIT(name, name##_head_srcu_data) #else #define _SRCU_NOTIFIER_HEAD(name, mod) \ mod struct srcu_notifier_head name = \ SRCU_NOTIFIER_INIT(name, name) #endif //2.注册一个notifier block 到通知链 extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *nb); //3.发送一个事件到通知链上的notifier block extern int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v); //4.从通知链删除一个notifier block extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v);

相关函数定义如下

#ifdef CONFIG_SRCU /* * SRCU notifier chain routines. Registration and unregistration * use a mutex, and call_chain is synchronized by SRCU (no locks). */ int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *n) { int ret; /* * This code gets used during boot-up, when task switching is * not yet working and interrupts must remain disabled. At * such times we must not call mutex_lock(). */ if (unlikely(system_state == SYSTEM_BOOTING)) return notifier_chain_register(&nh->head, n); mutex_lock(&nh->mutex); ret = notifier_chain_register(&nh->head, n); mutex_unlock(&nh->mutex); return ret; } int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, struct notifier_block *n) { int ret; /* * This code gets used during boot-up, when task switching is * not yet working and interrupts must remain disabled. At * such times we must not call mutex_lock(). */ if (unlikely(system_state == SYSTEM_BOOTING)) return notifier_chain_unregister(&nh->head, n); mutex_lock(&nh->mutex); ret = notifier_chain_unregister(&nh->head, n); mutex_unlock(&nh->mutex); synchronize_srcu(&nh->srcu); return ret; } int __srcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v, int nr_to_call, int *nr_calls) { int ret; int idx; idx = srcu_read_lock(&nh->srcu); ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); srcu_read_unlock(&nh->srcu, idx); return ret; } int srcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v) { return __srcu_notifier_call_chain(nh, val, v, -1, NULL); } #endif /* CONFIG_SRCU */ 3. 一个简单的通知链实例 我们可以自己写一个内核模块在Ubuntu 运行验证一下通知链的使用方法。

1.模块代码 /** * file : raw-notifer-chain.c * owner: wuchengbing * data : 20190125 * */

#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> //#include <linux/fs.h> //#include <linux/delay.h> #include <linux/notifier.h>

// define notifier event type #define EVENT_A 0x01 #define EVENT_B 0x02

static RAW_NOTIFIER_HEAD(raw_chain_list); //define notifer chain list

// define callback function int raw_notifer_callback(struct notifier_block *nb, unsigned long event, void *v) { switch (event) { case EVENT_A: printk("raw_notifer_callback running EVENT_A\n"); break; case EVENT_B: printk("raw_notifer_callback running EVENT_B\n"); break; default: break; }

return NOTIFY_DONE; }

// define notifier block static struct notifier_block raw_notif = { .notifier_call = raw_notifer_callback, //appoint notifier callback function };

static int __init raw_notifier_init(void) { printk("raw_notifier_chain_register\n\n"); raw_notifier_chain_register(&raw_chain_list, &raw_notif);

printk("raw_notifier call EVENT_A\n"); raw_notifier_call_chain(&raw_chain_list, EVENT_A, NULL);

printk("raw_notifier call EVENT_B\n"); raw_notifier_call_chain(&raw_chain_list, EVENT_B, NULL);

return 0; }

static void __exit raw_notifier_exit(void) { printk("raw_notifier_chain_unregister\n\n"); raw_notifier_chain_unregister(&raw_chain_list, &raw_notif); }

module_init(raw_notifier_init); module_exit(raw_notifier_exit);

MODULE_AUTHOR("Wu_Being"); MODULE_LICENSE("GPL");

2.Makefile 文件 ## # file : Makefile # owner: wuchengbing # data : 20190125 ##

obj-m += raw-chain-notifier.o # geneate modules ko file CURRENT_PATH := $(shell pwd) # current core path LINUX_KERNEL := $(shell uname -r) # kernel version

# kernel core path LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)

# make or make all all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules

# make clean clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

3.运行结果 wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ ls -l total 8 -rw-rw-r-- 1 wucb0122 wucb0122 453 1月 25 10:10 Makefile -rw-rw-r-- 1 wucb0122 wucb0122 1440 1月 25 10:08 raw-chain-notifier.c

wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ make make -C /usr/src/linux-headers-3.13.0-147-generic M=/home/wucb0122/Codes/notifier_chain/raw-notifer-chain modules make[1]: Entering directory `/usr/src/linux-headers-3.13.0-147-generic' CC [M] /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/raw-chain-notifier.o Building modules, stage 2. MODPOST 1 modules CC /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/raw-chain-notifier.mod.o LD [M] /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/raw-chain-notifier.ko make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-147-generic'

wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ls -ltr total 36 -rw-rw-r-- 1 wucb0122 wucb0122 1440 1月 25 10:08 raw-chain-notifier.c -rw-rw-r-- 1 wucb0122 wucb0122 451 1月 25 10:12 Makefile -rw-rw-r-- 1 wucb0122 wucb0122 4752 1月 25 10:12 raw-chain-notifier.o -rw-rw-r-- 1 wucb0122 wucb0122 83 1月 25 10:12 modules.order -rw-rw-r-- 1 wucb0122 wucb0122 966 1月 25 10:12 raw-chain-notifier.mod.c -rw-rw-r-- 1 wucb0122 wucb0122 0 1月 25 10:12 Module.symvers -rw-rw-r-- 1 wucb0122 wucb0122 2784 1月 25 10:12 raw-chain-notifier.mod.o -rw-rw-r-- 1 wucb0122 wucb0122 5395 1月 25 10:12 raw-chain-notifier.ko

wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ sudo insmod raw-chain-notifier.ko [sudo] password for wucb0122: wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ sudo dmesg -c ... [153967.504748] raw_chain_notifier: module verification failed: signature and/or required key missing - tainting kernel [153967.505121] raw_notifier_chain_register [153967.505121] [153967.505123] raw_notifier call EVENT_A [153967.505124] raw_notifer_callback running EVENT_A [153967.505124] raw_notifier call EVENT_B [153967.505125] raw_notifer_callback running EVENT_B

wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ make clean make -C /usr/src/linux-headers-3.13.0-147-generic M=/home/wucb0122/Codes/notifier_chain/raw-notifer-chain clean make[1]: Entering directory `/usr/src/linux-headers-3.13.0-147-generic' CLEAN /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/.tmp_versions CLEAN /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/Module.symvers make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-147-generic'

wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ ls -ltr total 8 -rw-rw-r-- 1 wucb0122 wucb0122 451 1月 25 10:12 Makefile -rw-rw-r-- 1 wucb0122 wucb0122 1479 1月 25 10:19 raw-chain-notifier.c

wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ sudo rmmod raw-chain-notifier.ko wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ sudo dmesg -c [154548.347863] raw_notifier_chain_unregister [154548.347863] wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$

Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢! 《从基本理解到深入探究Linux kernel 通知链(notifier chain)》:https://blog.csdn.net/u014134180/article/details/86563754 --------------------- 作者:Wu_Being 来源:CSDN 原文:https://blog.csdn.net/u014134180/article/details/86563754 版权声明:本文为博主原创文章,转载请附上博文链接!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券