Linux 内核 notifier机制
一般而言特定的子系统会用特定的notifier_chain_register包装函数来注册,比如tp通过fb_register_client来注册notifier_block(在具体的应用场景中会封装对应的注册和调用函数)。
1.fb_notify.c中的封装:
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);
}
小结:无论是注册还是反注册或者是调用都需要一个 struct blocking_notifier_head结构体
struct blocking_notifier_head {struct rw_semaphore rwsem;struct notifier_block __rcu *head;
};
含有1个信号量和1个notifier_block
2.详细介绍
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,struct notifier_block *n)
{int ret;down_write(&nh->rwsem); // 使用信号量进行互斥操作,可睡眠,此注册函数应用于进程上下文,而不可用于中断上下文ret = notifier_chain_register(&nh->head, n); up_write(&nh->rwsem);return ret;
}
static int notifier_chain_register(struct notifier_block **nl,struct notifier_block *n)
{while ((*nl) != NULL) { // 当nl指向的notifier_block不为空时,循环继续if (n->priority > (*nl)->priority)break;nl = &((*nl)->next);// nl指向链表中的下1个notifier_block} //当nl指向的notifier_block为空时或n指向的notifier_block的优先级比n1指向的高时,退出循环n->next = *nl; // 让 n->next 指向 n1rcu_assign_pointer(*nl, n);return 0;
}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;
}
static int notifier_call_chain(struct notifier_block **nl,unsigned long val, void *v,int nr_to_call, int *nr_calls)
{int ret = NOTIFY_DONE;struct notifier_block *nb, *next_nb;nb = rcu_dereference_raw(*nl);while (nb && nr_to_call) {next_nb = rcu_dereference_raw(nb->next);ret = nb->notifier_call(nb, val, v); // 调用每个notifier_block上的回调函数,第二三个参数分别为 fb_notifier_call_chain 传入的2个参数if (nr_calls)(*nr_calls)++;if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)break;nb = next_nb;nr_to_call--;}return ret;
}
3.应用实例
TP可以通过获取framebuffer子系统来实现亮屏和灭屏时触发相应的事件。
probe函数中与notifier相关部分实现:
static int fb_notifier_callback(struct notifier_block *self,unsigned long event, void *data)
{struct fb_event *evdata = data;int *blank;struct fts_ts_data *fts_data =container_of(self, struct fts_ts_data, fb_notif);if (evdata && evdata->data && event == FB_EVENT_BLANK &&fts_data && fts_data->client) {blank = evdata->data;if (*blank == FB_BLANK_UNBLANK)fts_ts_resume(&fts_data->client->dev);else if (*blank == FB_BLANK_POWERDOWN ||*blank == FB_BLANK_VSYNC_SUSPEND)fts_ts_suspend(&fts_data->client->dev);}return 0;
}
static int fts_ts_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
data->fb_notif.notifier_call = fb_notifier_callback;err = fb_register_client(&data->fb_notif);
}
LCD的调用部分代码:
int
fb_blank(struct fb_info *info, int blank)
{ struct fb_event event;int ret = -EINVAL, early_ret;if (blank > FB_BLANK_POWERDOWN)blank = FB_BLANK_POWERDOWN;event.info = info;event.data = ␣early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event); // 此函数传入的参数即为各个callback函数的参数,将决定TP是休眠还是唤醒if (info->fbops->fb_blank)ret = info->fbops->fb_blank(blank, info);if (!ret)fb_notifier_call_chain(FB_EVENT_BLANK, &event);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;
}
Linux 内核 notifier机制相关推荐
- Linux内核notifier机制通知链
内核使用通知链的机制在内核各子系统之间进行事件通知(注:无法用于内核态和用户态之间的事件通知). 一.通知链介绍 在文件include/linux/notifier.h中,可以查看Linux内核定义的 ...
- Linux内核Notifier机制
notifier是kernel的一种异步通信机制,用于告知某些模块产生了一个事件event. notifier涉及: 1,publisher,类比于server.provider等概念,负责: 提供一 ...
- Linux内核同步机制之(四):spin lock【转】
转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...
- 深度剖析Linux内核地址映射机制
深度剖析Linux内核地址映射机制 1.虚拟空间数据结构 2.进程虚拟空间 3.内存映射 视频讲解如下,点击观看: Linux内核开发系列第7讲--深度剖析Linux内核地址映射机制 C/C++ ...
- linux 内核mmap,Linux内核mmap机制
1. 问:如何将物理地址映射到用户空间的虚拟地址上? 2.linux内核mmap机制 2.1.回顾LED驱动数据流的操作过程 通过分析LED驱动,得出以下结论: 如果利用read,write,ioct ...
- Linux的notifier机制在TP中的应用【转】
转自:https://blog.csdn.net/armfpga123/article/details/51771666 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog ...
- Linux内核OOM机制的浅析
Linux内核根据应用程序的要求分配内存,通常来说应用程序分配了内存但是并没有实际全部使用,为了提高性能,这部分没用的内存可以留作它用,这部分内存是属于每个进程的,内核直接回收利用的话比较麻烦,所以内 ...
- linux内核锁机制学习
在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需要一些同步机制来同步不同处理器上 ...
- linux内核 RCU机制概述
简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制 ...
最新文章
- 馅饼还是陷阱,TMG2010升级经验谈
- 快手二面:Java 里的 for (;;) 与 while (true),哪个更快?
- 阿里研究员谷朴:警惕软件复杂度困局
- Citrix xenapp
- 联想将在CES上展示LePad平板
- 如何使用js动态显示或隐藏DIV
- netcore quartz job用不了services_.NetCore开源集成框架
- ubuntu20.04自带python版本_替换 ubuntu 自带的python版本
- [转]简明 Nginx Location Url 配置笔记
- java连接oftp_[Share] EDI 系统之 OFTP 端口
- matlab2c使用c++实现matlab函数系列教程-atan函数
- echarts没有数据时显示暂无数据
- 卸载Oracle 12c
- 【源码】基于部分随机PSO的光伏MPPT算法
- ftp下载工具 免费,7大值得推荐的免费版ftp下载工具
- Vista 如何关闭UAC(用户帐户控制)
- 华为外包测试2年,不甘被替换,168天的学习转岗成正式员工
- 关于微信刷票的Python源码
- 山东罕见姓氏百家姓都没有,翻家谱竟是皇室后裔,专家:是真的
- matlab怎么把scop图形用plot,怎么把ulink出来的数据导出来