最新要闻
- 五部门联合开展集中用餐单位食品安全问题专项治理行动
- 安居客上海二手房价格真的吗(安居客上海)
- Microsoft Activation Scripts v1.8 一款开源的Windows/Office激活工具、无毒无捆绑
- 首战遭遇卫冕冠军,武汉三镇队亚冠赛程出炉
- 漯河市郾城中学:情系舌尖安全 情筑和谐校园
- 火炮兰的邀请函没有了(火炮兰的邀请函)
- 义乌首条“丹溪健康专线”开通
- 又有新台风生成!上海会受影响吗?下周天气如何?
- 北辰实业2023上半年扭亏为盈 股东应占利润1.33亿
- 首份国有大行半年报出炉:建设银行日赚9.25亿!近10年首降个人住房贷款规模
- 2999元 一加Ace 2 Pro明天开卖:88万人预约
- 《博德之门3》放弃XSS分屏
- “零元购”成为社会性问题 美国零售商们欲哭无泪:业绩大幅下滑
- 1TB不到300元!超低价高容量固态硬盘能买么?当然能
- 中航西飞:截至2023年8月18日,公司的股东人数是152,853户
- 瑞联新材:拟以5000万元-8000万元回购股份
手机

宁波环视信息科技有限公司(关于宁波环视信息科技有限公司简述)

原画梦app(原画梦)
- 宁波环视信息科技有限公司(关于宁波环视信息科技有限公司简述)
- 原画梦app(原画梦)
- 张家界市武陵源区成功举办首届洞穴联合救援演练
- 热门车讯沃尔沃首款纯电车型或将于2019年推出 采用掀背式设计
- 省广集团:拟投资改造深圳华强北项目
- 大爷游泳被游艇绞断下体 大爷受到什么伤害
家电
调试linux内核(2): poll系统调用的实现
linux内核为用户态进程提供了一组IO相关的系统调用: select/poll/epoll, 这三个系统调用功能类似, 在使用方法和性能等方面存在一些差异. 使用它们, 用户态的进程可以"监控"自己感兴趣的文件描述符, 当这些文件描述符的状态发生改变时, 比如可读或者可写了, 内核会通知进程去处理, 这里的文件描述符可以是socket, 设备文件, 管道等. 使用这组系统调用, 用户态可以实现事件循环机制, 比如redis源码中就基于此实现了自己内部使用的事件循环, 同样还有很多其他专门提供事件循环机制的开源库. 这里通过一个驱动模块实现的poll接口, 去分析内核中poll系统调用的实现原理. 主要讨论了以下3个问题:
(资料图片)
- 用户态进程如何使用poll系统调用?
- 内核如何处理poll系统调用?
- 怎样调试从进程发起poll调用到返回的过程?
问题1
用户态进程如何使用poll系统调用?
简单来说, 使用poll的时候, 进程需要告诉内核自己关心哪些文件描述符, 关心它们的什么事件, 这些都是通过参数传递给poll系统调用的. 下面是手册中对poll的详细说明:
POLL(2) Linux Programmer"s Manual POLL(2)NAME poll, ppoll - wait for some event on a file descriptorSYNOPSIS #include int poll(struct pollfd *fds, nfds_t nfds, int timeout); #define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask);DESCRIPTION poll() performs a similar task to select(2): it waits for one of a set of file descriptors to become ready to perform I/O. The Linux-specific epoll(7) API performs a similar task, but offers features beyond those found in poll(). The set of file descriptors to be monitored is specified in the fds argument, which is an array of structures of the following form: struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ }; The caller should specify the number of items in the fds array in nfds.
poll接受三个参数, 其中pollfd的数组用来告诉内核, 进程关心哪些文件描述符, 结构体的fd字段是文件描述符的值, events是关心的事件, 比如希望fd可读时收到内核通知, 就可以设为POLL_IN, 这个events字段支持位或, 也就是关心的多种事件可以用或运算一起计算出events的最终数值, revents字段表示poll系统调用返回之后, 在该fd上发生的事件. poll的第二和第三个参数分别表示数组的大小和超时时间, 其中timeout以毫秒为单位, 如果timeout==0, poll会立即返回, 如果timeout < 0, poll会一直等待, 直到fds中期待的事件发生, 或者进程收到信号, 或者其他原因进程退出了. 当fds中的事件没有发生或者超时时间没到时, 进程就会处于睡眠状态. poll的返回值反映了三种可能的结果, 1) 出错, 2) 超时, 3) 发生期待事件的fd的数量. 其他的信息可以自行阅读manual.
以下代码会用来发起poll调用, 然后调试poll的实现:
/*ignore include headers*/int main(int argc, char *argv[]){int dev_fd = open("/dev/cdev03", O_RDWR);if (dev_fd < 0) {perror("Can not open device file");return -1;}struct pollfd pollfd = {.fd = dev_fd,.events = POLL_IN,.revents = 0,};char buf[1024];int max_poll_calls = 3;while (max_poll_calls) {int ret = poll(&pollfd, 1, -1);if (ret == 1) {memset(buf, 0, 1024);read(dev_fd, buf, 1024);printf("poll_reader recv data: %s\n", buf);}max_poll_calls--;}close(dev_fd);return 0;}
代码中poll设备文件"/dev/cdev03"的状态变化, 在poll三次之后退出.
问题2
内核如何处理poll系统调用?
因为进程传递给内核的可能是多个文件描述符, 所以在poll的实现中也需要遍历这些fd并检查它们的状态, 实际poll的实现涉及到比较多的数据结构, 这里先简单概括一下进入到poll系统调用之后内核的处理逻辑:
# ATTENION: we are in poll syscall now0) 计算超时状态初始值;while True:for fd in fds:1) 获取当前fd的状态;2) 记录fd的状态;3) 对符合条件的fd计数;if 存在符合条件的fd 或者 超时时间到:break4) 调用schedule相关API, 让出CPU, 当前进程开始带有超时的睡眠;5) 更新超时状态;# 如果进程被唤醒, schedule调用就会返回, 进程将在内核态, 继续这个循环
以上就是poll实现中的核心逻辑, 当然, 实际情况还是会稍微复杂亿点的, 以上描述中省略了进程被信号唤醒等处理逻辑. 后面会用一个字符设备驱动, 跟踪这个实现过程, 下面是设备驱动和poll系统调用在交互过程中各自的职责划分:
- 内核怎么获取fd的状态?对于字符设备驱动, 它要实现file_operations中的poll接口, 内核在步骤1)会调用, 得到设备的状态
- 设备怎么通知进程设备的状态发生了变化?在设备驱动实现的poll接口被调用时, 会使用poll_wait传递给调用者一个等待队列, 调用驱动接口的上层代码在这个队列中插入元素, 通过这个元素, 可以间接找到睡眠的进程, 当有数据写入设备时, 驱动模块的write接口被调用, 驱动代码可以在write接口中对这个等待队列进行唤醒操作, 从而实现唤醒进程. 具体的数据结构细节在后面的调试过程中展开.
问题3
怎样调试从进程发起poll调用到返回的过程?
这里构造的场景如下:
- 实现一个字符设备驱动, 驱动中实现了poll, write, read接口;
- 在内核中插入该模块, 在/dev下生成设备文件节点;
- 启动一个用户态进程, 并让它后台运行, 在进程中打开设备文件, 对该文件进行poll操作, 开始时设备数据为空, 进程将睡眠
- 使用echo命令向设备文件写入数据, 驱动的write接口被调用, 睡眠的进程被唤醒, 并读取设备数据;
在对poll的实现有了一个基本了解之后, 调试面临的第一个问题就是找到这个系统调用的入口, 这里提供两个调试技巧:
- 你知道在linux内核中系统调用使用SYSCALL_DEFINEx宏定义, 可以直接在代码中用正则表达式SYSCALL_DEFINE.*poll去搜索poll系统调用的位置, 然后在入口打断点, 开始调试即可.
- 你不知道poll的入口在那, 但是在你的字符设备驱动中实现了poll接口, 这个接口一定会出现在poll系统调用的调用链上, 可以在你的驱动模块上打断点, 断点命中之后, 看调用栈找到syscall的入口, 再进一步调试. 这种方法需要借助内核提供的gdb脚本加载驱动模块的调试信息, 否则gdb无法获得指令和源文件中各行的对应信息以及其他的符号信息.
关于调试的环境问题, 可以参考之前的文章, 以下是调试过程的视频记录:
poll系统调用涉及到的重要数据结构, 以及它们之间的关系总结如下:
在逻辑上可以分成如图所示的两个部分, 分别和poll系统调用的上层实现以及驱动模块的poll接口实现相关. 各数据结构的作用如下:
进程进入poll系统调用时, 内核对poll_wqueues的各个成员进行初始化, 包括:
- 用一个默认的函数初始化pt的_qproc函数指针;
- 用current初始化polling_task, 记录发起poll系统调用的进程;
- 虚线框中的成员嵌套着wait_queue_entry, 这个被嵌套的数据类型, 是将来真正插入到驱动模块提供的等待队列wait_queue_head的节点;
当驱动模块的poll接口被上层调用时:
- 驱动代码需要调用poll_wait函数, 以自己维护的等待队列wait_queue_head作为参数, 并透传poll_table指针和file指针;
- 在poll_wait的实现中, 会检查poll_table的_qproc是否为空, 不为空则继续透传参数, 调用_qproc;
- 在_qproc中, 会从poll_wqueues中获取一个空闲的poll_table_entry, 初始化图中的三个成员, 其中的wait_queue_entry:
- private指针被设为poll_wqueues的地址, 这样将来被唤醒时就可以找到之前睡眠的进程, 也就是polling_task;
- func被设为一个默认的函数,将来这个节点所属的等待队列被唤醒时, func被调用, 根据private指针找到要唤醒的进程;
- 通过链表操作, 将节点插入到等待队列中;
- 在_qproc中, 会从poll_wqueues中获取一个空闲的poll_table_entry, 初始化图中的三个成员, 其中的wait_queue_entry:
- 在poll_wait的实现中, 会检查poll_table的_qproc是否为空, 不为空则继续透传参数, 调用_qproc;
- 驱动代码需要调用poll_wait函数, 以自己维护的等待队列wait_queue_head作为参数, 并透传poll_table指针和file指针;
当有数据写入设备时:驱动模块检测到设备有数据可读了, 需要唤醒传递给poll_wait的等待队列, 这时队列上每个节点的func都会被调用, 最终之前睡眠的进程被唤醒;
当设备可写时, 唤醒过程类似, 只是使用的队列不同.
概括下来:
- 驱动模块只要维护自己的等待队列, 在poll接口的实现中, 调用上层提供的poll_wait向队列中插入元素, 并返回当前的设备状态;
- 驱动的其他部分在合适的时机对等待队列执行唤醒操作;
- poll系统调用的上层实现代码, 负责维护一套数据结构, 记录插入到等待队列中的节点, 给节点进行必要的设置, 使得通过节点能够唤醒正确的进程;
总结
设备驱动的开发是在内核提供的框架下进行的, 为了降低驱动的开发难度, 快速支持各种新设备, 这套框架的设计必然要经得住考验, 这也导致驱动的开发存在很多模板一样的套路, 有人戏称为"完形填空". 但是以驱动开发为出发点, 深入了解内核的各个模块, 个人感觉是学习linux的一个很好的方式. 欢迎加入技术讨论qq群: 838923389 一起研究linux相关的底层技术.
关键词:
-
-
-
-
调试linux内核(2): poll系统调用的实现
灯火璀璨“夜经济” 激发消费新活力(全力拼经济 各地在行动)
好戏连台活力足 暑期文化消费热背后藏着什么“密码”?
五部门联合开展集中用餐单位食品安全问题专项治理行动
宁波环视信息科技有限公司(关于宁波环视信息科技有限公司简述)
五部门联合开展集中用餐单位食品安全问题专项治理行动
金奥博2023年上半年净利4654.12万 同比增加84.22%
落花寻(关于落花寻简述)
洪涛离职湖南卫视了吗(洪涛离职湖南卫视)
安居客上海二手房价格真的吗(安居客上海)
Microsoft Activation Scripts v1.8 一款开源的Windows/Office激活工具、无毒无捆绑
原画梦app(原画梦)
召回5万支!或有安全风险!很多人随身携带,快自查
张家界市武陵源区成功举办首届洞穴联合救援演练
最新!5名电诈犯罪嫌疑人从缅甸被押解回国
易联众:张曦辞任董事长 吴梁斌接任
青海互助高原特色冷凉蔬菜推介会:助产业发展 帮农民增收
首战遭遇卫冕冠军,武汉三镇队亚冠赛程出炉
一根晾衣杆 晒出新生活
浙商银行:8月23日融资买入6432.82万元,融资融券余额6.49亿元
当升科技上半年营收同比下降7.8% 净利润实现逆势增长 | 财报见闻
青海清洁能源装机规模突破4000万千瓦居中国首位
“双碳”拖累了经济发展吗?
Zoom 第二财季营收 11.387 亿美元 净利润同比增长 298%
途虎养车通过港交所上市聆讯,2023上半年全面盈利,收入超65亿
工银电子密码器激活码忘记了怎么办(工银电子密码器怎么激活)
大行评级|花旗:予国药控股“买入”评级 目标价28港元
漯河市郾城中学:情系舌尖安全 情筑和谐校园
pdf文件颜色加深怎么弄(pdf文件颜色加深)
机构:日元或取代日债成为推动日本央行调整政策的因素
格拉菲特酒店 格拉菲特
中医中药赋能妇产科健康事业发展 俞瑾全国名中医传承工作室揭牌
斗罗大陆:小舞雕塑售价高达四位数,质感和美杜莎相比哪个更优
高通亮出三款全新骁龙旗舰掌机处理器,GPU性能翻倍
电影《小丑》夺威尼斯最佳影片金狮奖,这下漫威和索尼该慌了
火炮兰的邀请函没有了(火炮兰的邀请函)
国瑞科技(300600.SZ)发布上半年业绩,净亏损1699.52万元,收窄32.42%
赛微电子(300456.SZ)发布上半年业绩,由盈转亏2744.08万元
8月汽车销量预计185万辆 新能源汽车占比创历史新高
助力乡村振兴,这两个高原村落有啥“致富经”?
美国敦促公民尽快离开白俄罗斯 发出最高安全警告
酒精冰淇淋,到底是酒还是冰淇淋?
桂林十八中临桂分校初中部招生 桂林十八中
双台风酝酿生成!月底冷空气要来?佛山未来天气……
美国7月销量榜:《遗迹2》登顶 硬件销量略微下滑
河北省上半年规上工业增加值同比增长7.2%
还没“干翻”滴滴,打车平台们又跳进新坑?
泛发型白癜风疾病应该怎么治疗
快讯2023-08-24 21:00:12
义乌首条“丹溪健康专线”开通
重磅!300余位专家学者齐聚西工大,聚焦临地安防!
热门车讯沃尔沃首款纯电车型或将于2019年推出 采用掀背式设计
朱国瑜的新浪微博(朱国瑜)
五矿地产上半年应占溢利1.12亿港元 同比上升24.4%
今日辟谣(2023年8月24日)
50岁体检必查10大项目(男性体检前注意事项)
牙签枪怎么做简单又好看(牙签枪怎么做简单)
靠什么留人才
“小米牌”汽车快了?!雷军和疑似测试车同时“现身”新疆,专属网站域名完成备案登记!
第三届全国高校教师教学创新大赛在杭州举办
人民网、新华网上半年扣非净利大增 加快推进人工智能等业务布局
三预警齐发!南方水汽充沛!川渝陕豫等地将有强降雨!
住建部就菏泽工地吊篮坠落致5死事故约谈山东省住建厅
酒驾后无证驾驶偏偏碰上事故,原来这是一起精心策划的“报复”
杭州亚运会、亚残运会举行赛会志愿者出征仪式
又有新台风生成!上海会受影响吗?下周天气如何?
金隅集团:上半年扣非后归属股东净亏损5.48亿元
探访北京智慧城市建设 丝路大V点赞高水平政务服务
北辰实业2023上半年扭亏为盈 股东应占利润1.33亿
美媒:美国最富有的污染“超级排放者”对延续气候危机有着不可推卸的责任!
重磅信号!证监会召开座谈会,事关中长期资金入市!
小米13T Pro真机曝光!后置徕卡三摄 预计9月初发布
首份国有大行半年报出炉:建设银行日赚9.25亿!近10年首降个人住房贷款规模
上半年实现稳健发展,蓝月亮(06993)2023年中期营收约22.23亿港元 毛利率55.2%
2999元 一加Ace 2 Pro明天开卖:88万人预约
《博德之门3》放弃XSS分屏
“零元购”成为社会性问题 美国零售商们欲哭无泪:业绩大幅下滑
1TB不到300元!超低价高容量固态硬盘能买么?当然能
爱德华兹:篮球靠5个人才能赢 我拿34分那场其他队友表现都很关键
伍家岗:污水臭气成困扰,市长热线解难题
电光科技(002730.SZ):公司没有生产适用于无人机产品
交通运输部:7月份交通运输经济继续恢复,主要指标同比均增长
力合科创: 半年报财务报表
炼化聚酯产业链中报扫描:低景气下的高速扩张
沈阳化工:孙公司拟约10.24亿元投建福建泉州24万吨/年聚醚多元醇项目
潮宏基(002345.SZ):上半年净利润2.09亿元 同比增长38.85%
儒竞科技(301525.SZ):回拨后网上发行的中签率为0.0289%
省广集团:拟投资改造深圳华强北项目
A股供气供热上市龙头企业一览(2023/8/21)
来伊份业绩变脸、万店计划落空,搞咖啡会有人买账吗?
中航西飞:截至2023年8月18日,公司的股东人数是152,853户
大爷游泳被游艇绞断下体 大爷受到什么伤害
广和通:拟以5000万元-1亿元回购公司股份
「走进区域看发展·中国式现代化的京津冀实践」“一年少跑3万公里”
13岁女孩雨中练古拳法肆意潇洒招式如行云流水般干净帅气网友点赞 具体是啥状况呢
支持更多上市公司回购股份
背靠腾讯、广汽,三年半亏损近20亿,如祺出行拟赴港上市
中国恒大:已对公司内控检讨整改,目前各区域公司资金一般由政府共管及统筹,全力配合保交楼相关工作
人民币围绕7.30上下波动
摩根大通图啥?新晋众泰汽车前十大流通股东!上半年卖了652辆