Linux驱动之多路监听

时间:2021-09-14 23:36:49

Select/poll:IO多路监听

案例:一个应用程序如何去处理多个设备,例如网口,串口,按键数据

明确:对设备访问永远先open

方法一:串行+阻塞的方式:缺点:每当阻塞读取标准输入时如果用户不进行标准输入的操作,而此时客户端给服务器发送数据,导致服务器无法读取客户端发来的数据!

方法二、采用多线程或者多进程机制来实现读取:开辟多个线程,每一个线程处理一个设备,不会导致数据无法读取,但是系统的开销会增加。

方法三:采用linux系统提供的高级IO的处理机制

Select/poll:两者一样,主进程能够利用select或者polll能够对多个设备进行监听。

Select 函数原型:int  select(int nfds, fd_set * readfds, fd_set *writefds, fd_set * exceptfds,

Struct timeval * timeout);

函数功能:主进程利用此函数能够对多个设备进行监听,一旦发现监听的设备都不可用(不可读也不可写也没有异常),那么主进程进入休眠状态,一旦监听的设备中,只要有一个设备可以(可读或可写或没有异常)都会唤醒休眠的主进程,select也就会返回。注意这个函数仅仅起到一个监听的功能,数据的后续处理,例如读和写都是通过read、write、ioctl来。

分析以上的总结内容:1.多个设备就代表着有多个驱动程序;每一个设备都对应一个驱动程序;2.设备不可用代表着应用程序会到内核空间操作设备,只要在内核空间才有权限访问硬件设备。3.主进程休眠代表主进程进入内核空间进行休眠,在内核空间将利用等待队列机制让主进程休眠; 4.等待队列需要有一个等待队列头,唤醒休眠的进程,使用wake_up,这个函数只需传递一个等待队列头即可唤醒休眠进程;只要有一个设备可用都会唤醒休眠的进程,这句话的潜台词就是一个主进程分别被添加到被监听的设备对应的驱动程序定义的等待队列头中。

5.select函数引起的主进程休眠,假如底层驱动也有对应的select函数,那只需利用等待队列机制让主进程在底层驱动的select函数进行休眠操作即可。

参数说明:nfds:对设备的访问永远都是先open获取fd;监听的设备中,最大的文件描述符集合,用来保存描述监听的设备,里面存放时被监听设备的文件描述符;如果select要监听某一个设备,必须把这个设备的fd添加到对应的文件描述符集合中!readfds:读文件描述符集合指针,如果select要监听设备是否可读,需将设备的fd添加到这个集合中! Writefds:写文件描述符集合指针,如果select要监听设备是否可写,需将设备的fd添加到这个集合中! Exceptfds:异常文件描述符集合指针,如果select要监听设备是否有异常,需将设备的fd添加到这个集合中!

注意:一个设备的fd可以同时添加到三个集合中!

Timeout:指定监听的超时时间,如果此参数指定一个时间,例如5秒钟,select发现设备不可用,主进程进入休眠状态,如果5秒之内设备还不可用,5秒到期,主进程主动唤醒;如果此参数指定为NULL,休眠为永久休眠!

返回值有三种:-1表示出错 0表示没有文件描述符准备好正数表示已经准备好的描述符的数 FD_ISSET测试一指定位是否被设置,若fd在描述符中,则返回非0,否则返回0.

Int FD_ISSET(INT FD, fd_set *set);

Void FD_SET(int fd, fd_set * set); //添加一个新的被监听的设备

Void FD_ZERO(fd_set * set); //清空文件描述符集合; 注意:如果要重复监听,需要再次清空集合和添加监听设备!

Linux驱动之多路监听

Linux驱动之多路监听

Select系统调用过程:1.应用程序调用select,首先调用C库的select函数实现;2.C库的select保存select系统调用号到R7,调用SVC或者SWI触发软中断,至此由用户空间写入内核空间,ARM的工作模式由用户模式转变为SVC管理模式;3.调转到内核准备好的异常向量表的入口地址,根据R7保存的系统调用,以它为索引在系统调用表中找到对应的实现函数sys_selcect 4.select要完成:(1)把被监听的设备对应的驱动程序的poll函数挨个调用一遍,被监听的设备都不可用,他们的驱动的poll函数都返回0; (2)判断是否是驱动主动唤醒,还是超时唤醒,还是接收到信号唤醒;(3)如果既没有驱动主动唤醒,也没有超时唤醒,没有接收到信号,sys_select调用poll_schedule_timeput主动让进程进入休眠。 (4)假设被监听的设备中,有一个设备可用(可读可写或异常,硬件中断通过中断来判断),都会唤醒休眠的主进程;(5)sys_select的poll_schedule_timeout函数返回,不在休眠。(6)再次把被监听的设备驱动的poll函数挨个调用一遍,此时可用的设备对应的驱动Poll函数会返回非0 (7)if(ret || time_out || …) //ret = 1,立即返回到用户空间。

总结:1.明确本来应该底层驱动的poll函数利用等待队列机制让进程进行休眠,但是等待队列休眠9步骤并不是都是驱动的poll来编写,有一部分是内核sys_select来实现。

2.驱动Poll函数完成如下内容即可:(1)调用poll_wait,将当前进程添加到驱动定义的等待队列中(2)根据设备是否可用,决定返回0还是非03.明确:监听机制,底层poll函数不是必须的,如果要监听设备还是可以使用多线程机制也能完成监听;但是使用select/poll监听设备,驱动必须有poll实现!

案例:给之前的按键驱动添加被监听的机制,并且采用平台总线的软件实现。