select系统调用及驱动实现方法
一.系统提供select函数来实现多路复用输入/输出模型。原型:
#include linux/poll.h>
int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);
参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。
返回值正整数,表示满足的文件描述符的个数.
返回0,表示超时.
返回-1,且errno为 -EENTIR,表示select在阻塞时被信号中断.
返回-1,其他情况下的错误返回,会设置相应errno.
二.使用select进行I/O复用的方法
1.将需要监控的文件描述符加入文件描述符集合.
文件描述符集合结构:struct fd_set.内核提供了一些宏用来操作文件描述符集合:
FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
FD_SET(int fd,fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
2.调用select进行监控.
3.查看文件描述符的集合状态是否发生变化.
Select在返回之后,如果有满足条件的文件描述符,那么相应的fd_set会发生变化,其中包含的都是满足条件的fd,因此用FD_ISSET来判断某个fd是否满足要求.
三.select系统调用的实现
select系统调用由驱动的poll方法实现,原型为:
unsigned int poll(struct file *filp,poi_table *wait);
poll 设备方法负责完成:
1.使用poll_wait将等待队列添加到poll_table中.
void poll_wait(struct file *,wait_queue_head_t *,poll_table *);
2.返回描述设备是否可读或可写的掩码.
POLLIN 设备可读
POLLRDNORM 数据可读
POLLOUT 设备可写
POLLWRNORM 数据可写
设备可读一般返回(POLLIN|POLLRDNORM),设备可写一般返回(POLLOUT|POLLWRNORM).
四.POLL工作原理解析
在设备的poll方法的实现过程中,会发现并没有将进程阻塞的语句,这是因为Poll方法只是做一个登记,真正的阻塞在fs/select.c中的do_select函数.do_select是select系统调用对应的内核函数.do_select根据poll方法返回值来进行判断,如果条件不满足,那么do_select中会调用poll_schedule_timeout将进程设置为可中断睡眠.(待续...)