情景:
- 如果某一时刻完成一个操作,而该操作应该引起一个附加的操作,实现相应的功能。
- 事件A,附加操作B。当A完成,B就要被调用。
- 目前,在内核中附加操作B的存在形式是以链表的形式存在,每个操作为链表的一项。要调用就会遍历整个链表,全部执行挂载在链表的操作B(回调函数)
概括:
notify机制 (通知链)
通知链技术可以概括为:事件的被通知者将事件发生时应该执行的操作通过函数指针方式保存在链表(通知链)中,然后当事件发生时通知者依次执行链表中每一个元素的回调函数完成通知。
原始的数据结构和函数
一、notify定义
struct notifier_block {
notifier_fn_t notifier_call; //回调接口
struct notifier_block __rcu *next; //执行完回调接口后的下一个通知结构
int priority; //优先级
};
二、初始化(由宏BLOCKING_NOTIFIER_HEAD来初始化notifier_block链表头)
#define BLOCKING_NOTIFIER_HEAD(name) \
struct blocking_notifier_head name = \
BLOCKING_NOTIFIER_INIT(name)
三、注册、注销、通知接口
static int notifier_chain_register(struct notifier_block **nl,
struct notifier_block *n);
static int notifier_chain_unregister(struct notifier_block **nl,
struct notifier_block *n);
static int __kprobes notifier_call_chain(struct notifier_block **nl,
unsigned long val, void *v,int nr_to_call, int *nr_calls);
四、接口封装(针对阻塞,不可阻塞等),通常在不同的内核子系统中,会做不同的封装
extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb);
extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
struct notifier_block *nb);
extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v);
五、在帧缓冲设备中通信链机制的使用
linux/drivers/video/fb_notify.c
fb中初始化链表头fb_notifier_list及定义函数接口fb_register_client、fb_unregister_client、fb_notifier_call_chain
/*
* 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>
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);
六、初始化一个通知项
static struct notifier_block fbcon_event_notifier = {
.notifier_call = fbcon_event_notify,
};
fb_notifier_call_chain调用后,最终调用的就是fbcon_event_notify。(函数详情如上)
七、注册一个notify的过程
fb_register_client() ---->
blocking_notifier_chain_register() ---->
notifier_chain_register()
八、注销notify
fb_unregister_client() ---->
blocking_notifier_chain_unregister() --->
notifier_chain_unregister()
九、通知notify
fb_notifier_call_chain() ---->
blocking_notifier_call_chain() ---->
__blocking_notifier_call_chain() ---->
notifier_call_chain()
参考例子:https://blog.csdn.net/u014770862/article/details/72917061
十、示例
例如在RK平台下,编写notify接口的驱动
static void knock_input_later_resume(void)
{
DBG("%s :enter\n", __func__);
gpio_set_value(gpio_info->gpio3,1);
return;
}
static void knock_input_early_suspend(void)
{
DBG("%s :enter\n", __func__);
gpio_set_value(gpio_info->gpio3,0);
return;
}
static int knock_input_event_notify(struct notifier_block *self,
unsigned long action, void *data) //回调时需要完成的任务,在该事例中是判断不同的FB状态
{
struct fb_event *event = data;
int blank_mode = *((int *)event->data);
switch (blank_mode) {
case FB_BLANK_UNBLANK:
knock_input_later_resume();
break;
case FB_BLANK_NORMAL:
knock_input_early_suspend();
break;
default:
knock_input_early_suspend();
break;
}
return 0;
}
static struct notifier_block knock_input_fb_notifier = {
.notifier_call = knock_input_event_notify, //回调接口
};
static int xxxx_probe(struct platform_device *pdev){
.....
fb_register_client(&knock_input_fb_notifier); //注册notify
.....
}