#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);Returns number of readf file descriptors, 0 on timeout, or -1 on error.
参数fds
列出了我们需要poll()
来检查的文件描述符。该参数为pollfd
结构体数组,其定义如下:
struct pollfd{int fd;short events;short revents;
};
参数nfds
指定了数组fds
中元素的个数。数据类型nfds_t
实际为无符号整型。
pollfd
结构体中的events
和revents
字段都是位掩码。调用者初始化events
来指定需要为描述符fd做检查的事件。
当poll()
返回时,revents
被设定以此来表示该文件描述符上实际发生的事件。
下表列出了可能会出现在events
和revents
字段中的位掩码。
-
该表中第一组位掩码(
POLLIN
,POLLRDNORM
,POLLRDBAND
,POLLPRI
以及POLLRDHUP
)同输入事件相关。 -
下一组掩码(
POLLOUT
,POLLWRNORM
以及POLLWRBAND
)同输出事件相关。 -
第三组掩码(
POLLERR
,POLLHUP
以及POLLNVAL
)是设定在revents
字段中用来返回有关文件描述符的附加信息。如果在events
中指定了这些位掩码,则者三位将被户卤鹅。 -
在Linux系统中,
poll()
不会用到最后一个位掩码POLLMSG
。
位掩码 | events中的输入 | 返回到revents | 描述 |
---|---|---|---|
POLLIN | ⚫ | ⚫ | 可读取非高优先级的数据 |
POLLRDNORM | ⚫ | ⚫ | 等同于POLLIN |
POLLRDBAND | ⚫ | ⚫ | 可读取优先级数据(Linux中不使用) |
POLLPRI | ⚫ | ⚫ | 可读取高优先级数据 |
POLLRDHUP | ⚫ | ⚫ | 对端套接字关闭 |
—————— | —————— | —————— | ———————————————— |
POLLOUT | ⚫ | ⚫ | 普通数据可写 |
POLLWRNORM | ⚫ | ⚫ | 等同于POLLOUT |
POLLWRBAND | ⚫ | ⚫ | 优先级数据可写入 |
—————— | —————— | —————— | ———————————————— |
POLLERR | ⚫ | 有错误发生 | |
POLLHUP | ⚫ | 出现挂断 | |
POLLNVAL | ⚫ | 文件描述符未打开| | |
—————— | —————— | —————— | ———————————————— |
POLLMSG | Linux中不使用(SUSv3中未指定) | |
如果我们对某个特定的文件描述符上的事件不感兴趣,可以将events
设为0。
另外,给fd
字段指定一个负值(例如,如果值为非零,取它的相反数)将导致对应的events
字段被忽略,且revents
字段将总是返回0.
这两种方法都可以用来(也许只是暂时的)关闭单个文件描述符的检查,而不需要重新建立整个fds
列表。
下面列出的是关于poll()
的Linux实现:
POLLIN
和POLLRDNORM
是同义词。POLLIUT
和POLLWRNORM
是同义词。- 一般来说,
POLLRDBAND
是不被使用的,也就是说它在events
字段中被忽略,也不会被设定到revents
字段中去。
唯一用到
POLLRDBAND
的地方是在实现DECnet网络协议的代码中(已过时)。
- 必须定义
_XOPEN_SOURCE
测试宏,这样才能在头文件<poll.h>
中得到常量POLLRDNORM
、POLLRDBAND
、POLLWRNORM
以及POLLWRBAND
的定义。 POLLRDHUP
是Linux专有的标志位。要在头文件<poll.h>
中得到它,必须定义_GNU_SOURCE
测试宏。- 如果指定的文件描述符在调用
poll()
时关闭了,则返回POLLNVAL
。
总结以上要点,poll()
真正关心的标志位就是POLLIN
、POLLOUT
、POLLPRI
、POLLRDHUP
、POLLHUP
以及POLLERR
。
timeout参数
参数timeout
决定了poll()
的阻塞行为,具体如下:
- 如果
timeout
等于 -1,poll()
会一直阻塞直到fds
数组中列出的文件描述符有一个达到就绪态(定义在对应的events
字段中)或者捕获到一个信号。 - 如果
timeout
等于0,poll()
不会阻塞——只是执行一次检查看看哪个文件描述符处于就绪态。 - 如果
timeout
大于0,poll()
至多阻塞timeout
毫秒,直到fds
列出的文件描述符中有一个达到就绪态,或者直到捕获到一个信号为止。
poll()的返回值
- 返回-1表示有错误发生。一种可能的错误是
EINTR
,表示该调用被一个信号处理例程中断。 (poll()
绝对不会自动恢复) - 返回0表示该调用在任意一个文件描述符称为就绪态之前就超时了。
- 返回正整数表示有一个或多个文件描述符处于就绪态了。返回值表示数组
fds
中拥有非零revents
字段的pollfd
结构体数量。
注意
select()
和poll()
返回正整数时的细小差别。
如果一个文件描述符在返回的描述符集中出现了不止依次,select()
会将同一个文件描述符计数多次。
而poll()
返回的是就绪的文件描述符个数,且一个文件描述符只会统计一次,就算在相应的revents
字段中设定了多个位掩码也是如此。
补充
- 在描述符数量很多时,
poll()
效率比select()
性能明显更好。 poll()
和select()
在大多数系统上不会自动重启,SA_RESTART
选项对它们不起作用(见APUE第3版p409)。
参考书籍
- UNIX环境高级编程 第3版
- Linux/UNIX系统编程手册