select和poll实现及驱动支持
1. 应用层接口
1.1 select
原型:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数:
nfds 是readfds、writefds、exceptfds中登记的文件描述符的最大值再加 1。
readfds 是监控文件非阻塞可读的描述符集合,也可以监控文件是否读到末尾(file descriptor is also ready on end-of-file)。
writefds 是监控文件非阻塞可写的描述符集合。
exceptfds 是监控文件异常的描述符集合。
timeout select超时时间,如果timeout里的值为0,则立即返回, 如果该参数为NULL,则一直阻塞直到事件出现,如果设置了超时时间,但是在超时之前有事件发生,select返回,那么timeout里的值是剩余的时间。
文件描述符集合可用宏操作:
void FD_SET(int fd, fd_set *set) 将fd设置到set集合中
void FD_CLR(int fd, fd_set *set) 将fd从集合set中清除
void FD_ZERO(fd_set *set) 清空set集合
int FD_ISSET(int fd, fd_set *set) 测试set集合中fd是否被设置来判断是否可读、可写、出现异常
返回值:
当成功时,select返回readfds, writefds, exceptfds三个集合中文件可操作的文件描述符的总数,也就是三个集合中所有位的设置总数。例如readfds和writefds中设置了同一个文件,当该文件同时可读可写时select返回,那么返回值就是2。
当错误时返回负数值,根据具体返回值进行处理。
当返回值是0时,表示超时。
1.2 poll
原型:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数:
fds 是一个结构体数组,结构体如下:
struct pollfd{
int fd; //监控的文件描述符
short events; //监控的事件,用下面的标志位标志,不能设置成最后三个错误标志位
short revents; //返回的事件,用下面的标志位标志,如果没有事件发生,这个成员会被清空
};
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通或优先级带数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLVAL 描述字不是一个打开的文件
nfds 是第一个元素的个数
timeout 超时时间,单位是毫秒,当设置成0,立即返回,设置成-1,会一直阻塞直到有事件发生
返回值:
成功返回正整数,表示所有事件的数量,包括正常的可读写事件和错误事件;
超时返回0;
出错返回-1,检查errno得到错误原因。
2. 内核中实现
2.1 select
select在内核中的入口在fs/select.c中:
SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
fd_set __user *, exp, struct timeval __user *, tvp)
{
struct timespec end_time, *to =