标签:open sch time 监测 数据 ini 等于 file div
应用程序访问1个设备文件时可用阻塞/非阻塞方式.如果是使用阻塞方式,则直接调用open()、read()、write(),但是在驱动程序层会判断是否可读/可写,如果不可读/不可写,则将当前进程休眠,直到被唤醒。如果是使用非阻塞方式,就需要采用poll/select机制,而且打开文件时标记文件的访问权限位为O_NONBLOCK。
1 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位
FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位
FD_ZERO(fd_set *set);用来清除描述词组set的全部位
如果参数timeout设为:NULL:则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件。0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。
1 int poll(struct pollfd *fds, nfds_t nfds, int timeout);这两个函数其实本质类似.
fds 可以传递多个结构体,也就是说可以监测多个驱动设备所产生的事件,只要有一个产生了请求事件,就能立即返回
struct pollfd {
int fd; /* 文件描述符 */
short events; /* 请求的事件类型,监视驱动文件的事件掩码 */
short revents; /* 驱动文件实际返回的事件 */
} ;
nfds 监测驱动文件的个数
timeout 超时时间,单位为ms
事件类型events 可以为下列值:
POLLIN 有数据可读
POLLRDNORM 有普通数据可读,等效与POLLIN
POLLPRI 有紧迫数据可读
POLLOUT 写数据不会导致阻塞
POLLER 指定的文件描述符发生错误
POLLHUP 指定的文件描述符挂起事件
POLLNVAL 无效的请求,打不开指定的文件描述符
返回值
有事件发生 返回revents域不为0的文件描述符个数(也就是说事件发生,或者错误报告)
超时 返回0;
失败 返回-1,并设置errno为错误类型
理解select模型:
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每个bit 可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
(1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。
(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(3)若再加入fd=2,fd=1,则set变为0001,0011
(4)执行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。
注意:没有事件 发生的fd=5被清空。
从内核态理解poll机制
我们从应用程序直接调用poll函数,系统会走以下流程
1 app:poll 2 kernel:sys_poll 3 do_sys_poll 4 poll_initwait(&table) 5 do_poll(nfds, head, &table, timeout) 6 for (;;) { 7 for (; pfd != pfd_end; pfd++) { /* 可以监测多个驱动设备所产生的事件 */ 8 if (do_pollfd(pfd, pt)) { 9 count++; 10 pt = NULL; 11 } 12 if (count || !*timeout || signal_pending(current)) 13 break; 14 __timeout = schedule_timeout(__timeout); 15 } 16 } 17 18 19 do_pollfd(pfd, pt){ 20 ... 21 if (file->f_op && file->f_op->poll) 22 mask = file->f_op->poll(file, pwait); 23 return mask; 24 ... 25 }基于内核源码版本为linux-2.6.22.6
使用poll_initwait(&table),就是将__pollwait设为回调函数,后面会去调用驱动程序的poll函数,poll函数调用pollwait就等于调用__pollwait,将当前进程加入到等待队列中。然后一直在循环,do_pollfd就是去调用驱动程序的poll函数,驱动程序的poll函数,poll函数开始调用pollwait就等于调用__pollwait回调函数,将当前进程加入到等待队列中,以便唤醒休眠后的当前进程。然后返回当前驱动设备的状态(mask).
如果do_pollfd返回的mask为非0,即count非0,就会马上返回,应用程序就可以使用FD_ISSET了解此时设备状态。当然,如果超时或者此进程有其他信号要处理超时,此进程有其他信号要处理,也会马上返回,但是应用程序使用FD_ISSET了解到此时设备状态还是不可用时,又继续轮询。如果do_pollfd返回的mask为0,而且未超时且未有其他信号发生,就会进程调度,让此进程休眠。在前面已经将此进程加入到驱动程序的等待队列中了,如果设备可用时,就会唤醒等待队列中的进程,也就唤醒了此进程,又去poll_initwait(&table).
参考:https://www.cnblogs.com/amanlikethis/p/6915485.html
http://www.cnblogs.com/shihaochangeworld/p/5747490.html
标签:open sch time 监测 数据 ini 等于 file div
原文地址:https://www.cnblogs.com/hwli/p/9218245.html