明天《升级版全系列嵌入式视频_入门篇》新增一节视频:19.2_POLL机制

时长24分钟,免费观看

何为POLL机制?

给驱动程序加一个闹铃,让APP不必死等数据;

既可以快速把握POLL机制,更有对内核代码的详尽讲解

多种观看形式:

一,B站(关注UP主-韦东山,视频更新后会有通知)

19.2_POLL机制:

(复制到浏览器打开)

二,官网()(支持在线观看,爽歪歪)

19.2_POLL机制:

(复制到浏览器打开,或则从步入)

温情提示:

为便捷及时通知您,您须要支付1毛钱订阅该专栏,

之后依次填写年纪,职位等信息。辛苦了。没有您的容许我们不会外泄这种信息。

三,

百度云盘(适宜不便捷上网的朋友)

密码:6FJk

路径:

->04_快速入门(即将开始)

->02_嵌入式linux驱动开发基础知识

->19.驱动程序基石

下边是视频文稿:

19.2POLL机制

19.2.1适用场景

在上面引入中断时,我们当初举过一个反例:

linux select调用机制_调用机制什么意思_调用命令有几种方法

调用命令有几种方法_调用机制什么意思_linux select调用机制

母亲如何晓得厨房里孩子醒了?

①时不时进卧室看一下:查询方法

简单,而且累

②进去屋子陪孩子一起午睡,男孩醒了会叫醒她:休眠-唤起

不累,然而母亲干不了活了

③妈妈要干好多活,而且可以陪孩子睡一会,定个闹铃:poll形式

要浪费点时间linux select调用机制,并且可以继续干活。

母亲要么是被儿子叫醒,要么是被闹铃叫醒。

④妈妈在卧室干活,女儿醒了他会自己走出大门告诉母亲:异步通知

母亲、小孩互不耽搁

使用休眠-唤起的形式等待某个风波发生时,有一个缺点:等待的时间可能许久。我们可以加上一个超时时间,这时就可以使用poll机制。

①APP不晓得驱动程序中是否有数据,可以先调用poll函数查询一下,poll函数可以传入超时时间;

②APP步入内核态,调用到驱动程序的poll函数,假若有数据的话立即返回;

③如果发觉没有数据时就休眠一段时间;

④当有数据时,例如当按下按钮时,驱动程序的中断服务程序被调用linux系统镜像下载,它会记录数据、唤醒APP;

⑤当超时时间到了以后,内核也会唤起APP;

⑥APP按照poll函数的返回值就可以晓得是否有数据,假如有数据就调用read得到数据

19.2.2使用流程

母亲步入卧室时,会先看孩子醒没醒,闹铃响以后走出屋子之前又会再看孩子醒没醒。

注意:看了2次女儿!

POLL机制也是类似的,流程如下:

函数执行流程如上图①~⑧所示,重点从③开始看。假定一开始无按钮数据:

③APP调用poll以后,步入内核态;

④导致驱动程序的drv_poll被调用:

注意,drv_poll要把自己这个线程挂入等待队列wq中;假定不装入队列里,那之后发生中断时,中断服务程序去哪儿找到你嘛?

调用命令有几种方法_调用机制什么意思_linux select调用机制

drv_poll就会判定一下:有没有数据啊?返回这个状态。

⑤假设当前没有数据,则休眠一会;

⑥在休眠过程中,按下了键盘,发生了中断:

在中断服务程序里记录了键盘值,但是从wq中把线程唤起了。

⑦线程从休眠中被唤起,继续执行for循环,再度调用drv_poll:

drv_poll返回数据状态

⑧哦,你有数据,那从内核态返回到应用态吧

⑨APP调用read函数读数据

若果仍然没有数据,调用流程也是类似的,重点从③开始看,如下:

③APP调用poll以后,步入内核态;

④导致驱动程序的drv_poll被调用:

注意,drv_poll要把自己这个线程挂入等待队列wq中;假定不装入队列里,那之后发生中断时,中断服务程序去哪儿找到你嘛?

drv_poll就会判定一下:有没有数据啊?返回这个状态。

⑤假设当前没有数据,则休眠一会;

⑥在休眠过程中,始终没有按下了键盘,超时时间到:内核把这个线程唤起;

⑦线程从休眠中被唤起,继续执行for循环,再度调用drv_poll:

drv_poll返回数据状态

⑧哦,你还是没有数据linux手机,并且超时时间到了,那从内核态返回到应用态吧

⑨APP不能调用read函数读数据

注意几点:

①drv_poll要把线程挂入队列wq,而且并不是在drv_poll中步入休眠,而是在调用drv_poll以后休眠

②drv_poll要返回数据状态

③APP调用一次poll,有可能会造成drv_poll被调用2次

④线程被唤起的缘由有2:中断发生了去队列wq中把它唤起,超时时间到了内核把它唤起

⑤APP要判定poll返回的缘由:有数据,还是超时。有数据时再去调用read函数。

19.2.3驱动编程

使用poll机制时,驱动程序的核心就是提供对应的drv_poll函数。

linux select调用机制_调用机制什么意思_调用命令有几种方法

在drv_poll函数中要做2件事:

①把当前线程挂入队列wq:poll_wait

APP调用一次poll,可能造成drv_poll被调用2次,并且我们并不须要把当前线程挂入队列2次。

可以使用内核的函数poll_wait把线程挂入队列,假如线程早已在队列里了,它就不会再度挂入。

②返回设备状态:

APP调用poll函数时,有可能是查询“有没有数据可以读”:POLLIN,也有可能是查询“你有没有空间给我写数据”:POLLOUT。

所以drv_poll要返回自己的当前状态:(POLLIN|POLLRDNORM)或(POLLOUT|POLLWRNORM)。

POLLRDNORM等同于POLLIN,为了兼容个别APP把它们一起返回。

POLLWRNORM等同于POLLOUT,为了兼容个别APP把它们一起返回。

APP调用poll后,很有可能会休眠。对应的,在键盘驱动的中断服务程序中,也要有唤起操作。

驱动程序中poll的代码如下:

static unsigned int gpio_key_drv_poll(struct file *fp, poll_table * wait){  printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__);  poll_wait(fp, &gpio_key_wait, wait);  return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;}

19.2.4应用编程

注意:APP可以调用poll或select函数,这2个函数的作用是一样的。

poll/select函数可以检测多个文件,可以检测多种风波:

风波类型

说明

POLLIN

有数据可读

POLLRDNORM

等同于POLLIN

POLLRDBAND

Prioritybanddatacanbereadlinux select调用机制,有优先级较较高的“banddata”可读

Linux系统中极少使用这个风波

POLLPRI

高优先级数据可读

POLLOUT

可以写数据

POLLWRNORM

等同于POLLOUT

POLLWRBAND

Prioritydatamaybewritten

POLLERR

发生了错误

POLLHUP

挂起

POLLNVAL

无效的恳求,通常是fd未open

在调用poll函数时,要指明:

①你要检测哪一个文件:哪一个fd

②你想检测这个文件的哪种风波:是POLLIN、还是POLLOUT

最后,在poll函数返回时,要判定状态。

应用程序代码如下:

struct pollfd fds[1];int timeout_ms = 5000;int ret;

fds[0].fd = fd;fds[0].events = POLLIN;

ret = poll(fds, 1, timeout_ms);if ((ret == 1) && (fds[0].revents & POLLIN)){ read(fd, &val, 4); printf("get button : 0x%xn", val);}

19.2.5现场编程

看视频

19.2.6上机实验

看视频

19.2.7POLL机制的内核代码解读

LinuxAPP系统调用,基本都可以在它的名子前加上“sys_”前缀,这就是它在内核中对应的函数。例如系统调用open、read、write、poll,与之对应的内核函数为:sys_open、sys_read、sys_write、sys_poll。

对于系统调用poll或select,它们对应的内核函数都是sys_poll。剖析sys_poll,即可理解poll机制。

19.2.7.1sys_poll函数

sys_poll坐落fs/select.c文件中,代码如下:

SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,    int, timeout_msecs){  struct timespec64 end_time, *to = NULL;  int ret;

if (timeout_msecs >= 0) { to = &end_time; poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC, NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC)); }

ret = do_sys_poll(ufds, nfds, to);……

调用机制什么意思_调用命令有几种方法_linux select调用机制

SYSCALL_DEFINE3是一个宏,它定义于include/linux/syscalls.h,展开后就有sys_poll函数。

sys_poll对超时参数稍作处理后,直接调用do_sys_poll。

19.2.7.2do_sys_poll函数

do_sys_poll坐落fs/select.c文件中,我们忽视其他代码,只看关键部份:

int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,    struct timespec64 *end_time){……  poll_initwait(&table);  fdcount = do_poll(head, &table, end_time);  poll_freewait(&table);……}

poll_initwait函数十分简单,它初始化一个poll_wqueues变量table:

poll_initwait   init_poll_funcptr(&pwq->pt, __pollwait);      pt->qproc = qproc;

即table->pt->qproc=__pollwait,__pollwait将在驱动的poll函数里用到。

do_poll函数才是核心,继续看代码。

19.2.7.3do_poll函数

do_poll函数坐落fs/select.c文件中,这是POLL机制中最核心的代码,贴图如下:

linux select调用机制_调用命令有几种方法_调用机制什么意思

①从这儿开始,将会造成驱动程序的poll函数被第一次调用。

顺着②③④⑤,你可以听到:驱动程序里的poll_wait会调用__pollwait函数把线程装入某个队列。

当执行完①之后,在⑥或⑦处,pt->_qproc被设置为NULL,所以第二次调用驱动程序的poll时,不会再度把线程装入某个队列里。

⑧如果驱动程序的poll返回有效值,则count非0,跳出循环;

⑨否则休眠一段时间;当休眠时间到,或是被中断唤起时,会再度循环、再次调用驱动程序的poll。

回顾APP的代码,APP可以指定“想等待个别风波”,poll函数返回后,可以晓得“发生了什么风波”:

linux select调用机制_调用命令有几种方法_调用机制什么意思

驱动程序里如何彰显呢?在上上一个图中,看②位置处,细说如下:

调用命令有几种方法_linux select调用机制_调用机制什么意思

-☆END☆-

我是韦东山,10多年仍然在研究linux+ARM,希望我的分享对你有帮助,欢迎进店订阅我的付费内容:

往期好文:

欢迎加群与韦老师交流讨论:

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复