poll()系统调用是System V的多元I/O解决方案,它解决了select()的几个不足。
用户空间调用的poll函数定义如下:
#include <sys/poll.h>
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
和select()不一样,poll()没有使用低效的三个基于位的文件描述符set,而是采用了一个单独的结构体pollfd数组,由fds指针指向这个组。
1. pollfd结构体定义如下:
#include <sys/poll.h>
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};
每一个pollfd 结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。
每个结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域。
revents域是文件描述符的操作结果事件掩码。内核在调用返回时设置这个域。
events域中请求的任何事件都可能在revents域中返回。
合法的事件如下:
POLLIN 有数据可读。
POLLRDNORM 有普通数据可读。
POLLRDBAND 有优先数据可读。
POLLPRI 有紧迫数据可读。
POLLOUT 写数据不会导致阻塞。
POLLWRNORM 写普通数据不会导致阻塞。
POLLWRBAND 写优先数据不会导致阻塞。
POLLMSG SIGPOLL消息可用。
此外,revents域中还可能返回下列事件:
POLLER 指定的文件描述符发生错误。
POLLHUP 指定的文件描述符挂起事件。
POLLNVAL 指定的文件描述符非法。
2. timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。
timeout指定为负数值表示无限超时;
timeout为0指示 poll调用立即返回并列出准备好I/O的文件描述符,但并不等待其它的事件。这种情况下,poll()就像它的名字那样,一旦选举出来,立即返回。
3. poll()返回值:
调用成功时,poll()返回结构体中revents域不为0的文件描述符个数;
如果在超时前没有任何事件发生,poll()返回0;
失败时,poll()返回-1,并设置errno为下列值之一:
EBADF 一个或多个结构体中指定的文件描述符无效。
EFAULT fds指针指向的地址超出进程的地址空间。
EINTR 请求的事件之前产生一个信号,调用可以重新发起。
EINVAL nfds参数超出PLIMIT_NOFILE值。
ENOMEM 可用内存不足,无法完成请求。
4. poll 用户空间编程示例:
/*linux poll用法*/
#include <sys/poll.h>
#include <stdio.h>
#include <unistd.h> /* STDIN_FILENO */
#define TIMEOUT 1000
int main(void)
{
struct pollfd fds[2];
int ret;
int i = 0;
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
fds[1].fd = STDOUT_FILENO;
fds[1].events = POLLOUT;
while(i<5){
ret = poll(fds,2,TIMEOUT*1000);
if(ret == -1){
perror("poll");
return 1;
}
if(!ret){
printf("%d seconds elapsed. \n",TIMEOUT);
}
if(fds[0].revents & POLLIN){
printf("stdin is readable\n");
}
if(fds[1].revents & POLLOUT){\
printf("stdout is writeable\n");
}
i++;
}
return 0;
}