从基本理解到深入探究 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。
[32m[ 1045.412245] [33mPM[0m: suspend entry 2019-01-13 19:15:43.130364966 UTC // linux kernel 进入休眠
// 退出休眠与进入休眠的UTC时间戳一差,就是kernel 休眠的时间(19:15:55 - 19:15:43)
// 按电源键唤醒系统亮屏 ... ...
[32m[ 1050.799717] [33mPM[0m: suspend exit 2019-01-13 19:15:55.594697461 UTC // linux kernel 退出休眠
[32m[ 1051.144198] [0m[xxx][WU] event = 16, FB_EVENT_BLANK = 9 // 背光发送两次event,一次是16一次是9
[32m[ 1051.144211] [0m[xxx][WU] event = 9, FB_EVENT_BLANK = 9
[32m[ 1051.144221] [0m[xxx][WU] blank = 0 // 其中参数的blank 为0 调用TP resume
[32m[ 1051.144232] [0m[xxx][WU] xxx_ts_resume FB_BLANK_UNBLANK = 0
[32m[ 1051.144233] [33m[xxx]xxx_ts_resume[0m: Enter
[32m[ 1051.146266] [33m[xxx]xxx_ts_resume[0m: Exit(1668)
// 亮屏了10s后,按电源键灭屏 ... ...
[32m[ 1061.519665] [0m[xxx][WU] event = 16, FB_EVENT_BLANK = 9 // 背光发送两次event,一次是16一次是9
[32m[ 1061.519680] [0m[xxx][WU] event = 9, FB_EVENT_BLANK = 9
[32m[ 1061.519690] [0m[xxx][WU] blank = 4 // 其中参数的blank 为4 调用TP suspend
[32m[ 1061.519702] [0m[xxx][WU] xxx_ts_suspend FB_BLANK_POWERDOWN = 4
[32m[ 1061.519703] [33m[xxx]xxx_ts_suspend[0m: Enter
[32m[ 1061.523594] [33m[xxx]xxx_ts_suspend[0m: Exit(1609)
[32m[ 1061.528000] [33m mdss_dsi_panel_power_off // 然后高通display 下电
[32m[ 1061.529240] [33mhbtp[31m: hbtp->input_dev not ready!
[32m[ 1061.532073] [33mPM[0m: suspend entry 2019-01-13 19:16:06.327045373 UTC
...
[32m[ 1061.649485] [33mPM[0m: suspend exit 2019-01-13 19:16:06.444469957 UTC
[32m[ 1061.853378] [33mPM[0m: suspend entry 2019-01-13 19:16:06.648349227 UTC
[32m[ 1061.853419] [33mPM[0m: Syncing filesystems ... done.
[32m[ 1061.888011] [33mPM[0m: Preparing system for sleep (mem)
[32m[ 1061.888187] [0mFreezing user space processes ... (elapsed 3.964 seconds) done.
[32m[ 1065.852448] [0mFreezing remaining freezable tasks ... (elapsed 0.009 seconds) done.
[32m[ 1065.861693] [33mPM[0m: Suspending system (mem)
[32m[ 1065.861723] [0mSuspending console(s) (use no_console_suspend to debug)
// 因为TP已经休眠了, 上面 fb_set_suspend 函数也发来fb set supend 事件,不过这次已经无效了
[32m[ 1065.895347] [0m[xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend
[32m[ 1065.933676] [0m[xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend
[32m[ 1066.742596] [33mPM[0m: 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
版权声明:本文为博主原创文章,转载请附上博文链接!
从基本理解到深入探究 Linux kernel 通知链(notifier chain)【转】的更多相关文章
- Linux内核基础--事件通知链(notifier chain)
转载: http://blog.csdn.net/wuhzossibility/article/details/8079025 http://blog.chinaunix.net/uid-277176 ...
- Linux内核基础--事件通知链(notifier chain)good【转】
转自:http://www.cnblogs.com/pengdonglin137/p/4075148.html 阅读目录(Content) 1.1. 概述 1.2.数据结构 1.3. 运行机理 1. ...
- Linux内核基础--事件通知链(notifier chain)【转】
转自:http://blog.csdn.net/wuhzossibility/article/details/8079025 内核通知链 1.1. 概述 Linux内核中各个子系统相互依赖,当其中某个 ...
- [Linux] 内核通知链 notifier
Linux 内核中每个模块之间都是独立的,如果模块需要感知其他模块的事件,就需要用到内核通知链. 最典型的通知链应用就是 LCD 和 TP 之间,TP 需要根据 LCD 的亮灭来控制是否打开关闭触摸功 ...
- Linux 内核通知链随笔【中】
关于内核通知链不像Netlink那样,既可以用于内核与用户空间的通信,还能用于内核不同子系统之间的通信,通知链只能用于内核不同子系统之间的通信.那么内核通知链到底是怎么工作的?我们如何才能用好通知链? ...
- Linux 内核通知链随笔【中】【转】
转自:http://blog.chinaunix.net/uid-23069658-id-4364171.html 关于内核通知链不像Netlink那样,既可以用于内核与用户空间的通信,还能用于内核不 ...
- Linux 内核通知链机制的原理及实现
一.概念: 大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子 系统,Linux内核提供了通知链的机制.通 ...
- Linux内核通知链模块
通知链描写叙述 大多数内核子系统都是相互独立的,因此某个子系统可能对其他子系统产生的事件感兴趣. 为了满足这个需求,也即是让某个子系统在发生某个事件时通知其他的子系统.Linux内核提供了通知链的机制 ...
- Linux内核通知链机制的原理及实现【转】
转自:http://www.cnblogs.com/armlinux/archive/2011/11/11/2396781.html 一.概念: 大多数内核子系统都是相互独立的,因此某个子系统可能对其 ...
随机推荐
- centos7之zabbix监控mysql(mariadb)数据库
一.Zabbix3.2.6使用自带模板监控MySQL 添加zabbix_agent客户端方法:http://www.cnblogs.com/lei0213/p/8858269.html mysql服务 ...
- Python基础:第一个Python程序(2)
1.Python Shell 1.1 Windows命令 (1)[开始]|[运行],输入cmd回车,进入Windows命令界面. (2)输入python,回车,进入Python Shell. 1.2 ...
- String.Join Method
Overloads Join(String, String[], Int32, Int32) Concatenates the specified elements of a string array ...
- springboot 配置mybatis
- leanote折腾指南
持续更新. 过几天把自己的修改好的css放到github上给大家参考. https://github.com/whuwangyong/leanote-conf TODO leanote Linux/W ...
- Nginx下配置SSL模块,支持https
Http与Https的区别 HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效 ...
- 浅析Spring
一:什么是Spring Spring是一个开源的框架,是为了解决企业应用程序开发复杂性由RodJohnson创建的.虽然Spring是为企业级应用推出的,但是所有的Java系统开发都可以使用Sprin ...
- vue axios使用方法
首先安装axios: cnpm install axios -save 安装成功后,在main.js页面引用: import axios from 'axios' import Qs from 'qs ...
- JavaScript DOM 高级程序设计读书笔记一
创建可重用的对象 简而言之,对象就是包含一组变量(称为属性)和函数(称为方法)的集合的实例.对象通常由类派生而来,而类中定义了对象拥有的属性和方法.如果你的脚本中都是对象之间的交互操作,那么就可以称之 ...
- Apache Hadoop 2.9.2 的集群管理之服役和退役
Apache Hadoop 2.9.2 的集群管理之服役和退役 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 随着公司业务的发展,客户量越来越多,产生的日志自然也就越来越大来,可能 ...