转自: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)【转】的更多相关文章

  1. Linux内核基础--事件通知链(notifier chain)

    转载: http://blog.csdn.net/wuhzossibility/article/details/8079025 http://blog.chinaunix.net/uid-277176 ...

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

    转自:http://www.cnblogs.com/pengdonglin137/p/4075148.html 阅读目录(Content) 1.1. 概述 1.2.数据结构 1.3.  运行机理 1. ...

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

    转自:http://blog.csdn.net/wuhzossibility/article/details/8079025 内核通知链 1.1. 概述 Linux内核中各个子系统相互依赖,当其中某个 ...

  4. [Linux] 内核通知链 notifier

    Linux 内核中每个模块之间都是独立的,如果模块需要感知其他模块的事件,就需要用到内核通知链. 最典型的通知链应用就是 LCD 和 TP 之间,TP 需要根据 LCD 的亮灭来控制是否打开关闭触摸功 ...

  5. Linux 内核通知链随笔【中】

    关于内核通知链不像Netlink那样,既可以用于内核与用户空间的通信,还能用于内核不同子系统之间的通信,通知链只能用于内核不同子系统之间的通信.那么内核通知链到底是怎么工作的?我们如何才能用好通知链? ...

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

    转自:http://blog.chinaunix.net/uid-23069658-id-4364171.html 关于内核通知链不像Netlink那样,既可以用于内核与用户空间的通信,还能用于内核不 ...

  7. Linux 内核通知链机制的原理及实现

    一.概念: 大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子 系统,Linux内核提供了通知链的机制.通 ...

  8. Linux内核通知链模块

    通知链描写叙述 大多数内核子系统都是相互独立的,因此某个子系统可能对其他子系统产生的事件感兴趣. 为了满足这个需求,也即是让某个子系统在发生某个事件时通知其他的子系统.Linux内核提供了通知链的机制 ...

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

    转自:http://www.cnblogs.com/armlinux/archive/2011/11/11/2396781.html 一.概念: 大多数内核子系统都是相互独立的,因此某个子系统可能对其 ...

随机推荐

  1. Bootstrap起步

    Bootstrap 是最受欢迎的 HTML.CSS 和 JS 框架,用于开发响应式布局.移动设备优先的 WEB 项目. Bootstrap 插件全部依赖 jQuery 请注意,Bootstrap 的所 ...

  2. asp.net core 排序过滤分页组件:sieve(1)

    使用asp.net core开发时避免不了要用一个合适的分页组件来让前端获取分页数据.github上面有一个开源的分页组件在这方面很适合我的使用,于是我把他的文档翻译一下,随后会分析它里面的源码.这是 ...

  3. [Java]list集合为空或为null的区别

    判断的是list这个集合的问题,当前需要判断list内值的问题. 简述判断一个list集合是否为空,我们的惯性思维是判断list是否等于null即可,但是在Java中,list集合为空还是为null, ...

  4. 读取导入csv csv报错iterable expected, not float

    示例代码import pandas as pdimport reimport csv data = pd.read_csv('nuojia.csv', encoding='utf-8')# print ...

  5. Go语言中Loop的注意点

    Go语言和其他语言不一样,它只有一种循环方式,就是for语句 可以参考如下公式: for initialisation; condition; post{ //Do Something } 执行顺序 ...

  6. 特殊计数序列——Catalan数

    Catalan数 前10项 \(1,1,2,5,14,42,132,429,1430,4862\) (注:从第\(0\)项起) 计算式 \(C_n=\frac{1}{n+1}\dbinom{2n}{n ...

  7. 【THUSC2017】【LOJ2978】杜老师 高斯消元

    题目大意 给你 \(l,r\),求从 \(l\) 到 \(r\) 这 \(r-l+1\) 个数中能选出多少个不同的子集,满足子集中所有的数的乘积是一个完全平方数. 对 \(998244353\) 取模 ...

  8. AttributeError: 'NoneType' object has no attribute 'split' 报错处理

    报错场景 social_django 组件对原生 django 的支持较好, 但是因为 在此DRF进行的验证为 JWT 方式 和 django 的验证存在区别, 因此需要进行更改自行支持 JWT 方式 ...

  9. Android Intent 传递数据注意事项

    不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction缓存为 1MB),可能导致 OOM.

  10. SpringMVC 文件上传下载

    目录 文件上传 MultipartFile对象 文件下载 上传下载示例 pom.xml增加 创建uploadForm.jsp 创建uploadForm2.jsp 创建userInfo.jsp spri ...