事件 描述 是否可作为输入(events) 是否可作为输出(revents)
POLLIN 数据可读(包括普通数据&优先数据) 是 是
POLLOUT 数据可写(普通数据&优先数据) 是 是
POLLRDNORM 普通数据可读 是 是
POLLRDBAND 优先级带数据可读(linux不支持) 是 是
POLLPRI 高优先级数据可读,比如TCP带外数据 是 是
POLLWRNORM 普通数据可写 是 是
POLLWRBAND 优先级带数据可写 是 是
POLLRDHUP TCP连接被对端关闭,或者关闭了写操作,由GNU引入 是 是
POLLHUP 挂起 否 是
POLLERR 错误 否 是
POLLNVAL 文件描述符没有打开 否 是
/*
* Wait for a TCP event.
*
* Note that we don't need to lock the socket, as the upper poll layers
* take care of normal races (between the test and the event) and we don't
* go look at any of the socket buffers directly.
*/
unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
{
unsigned int mask;
struct sock *sk = sock->sk;
const struct tcp_sock *tp = tcp_sk(sk);
int state;
sock_rps_record_flow(sk);
sock_poll_wait(file, sk_sleep(sk), wait);
state = sk_state_load(sk);
if (state == TCP_LISTEN)
return inet_csk_listen_poll(sk);
/* Socket is not locked. We are protected from async events
* by poll logic and correct handling of state changes
* made by other threads is impossible in any case.
*/
mask = 0;
/*
* POLLHUP is certainly not done right. But poll() doesn't
* have a notion of HUP in just one direction, and for a
* socket the read side is more interesting.
*
* Some poll() documentation says that POLLHUP is incompatible
* with the POLLOUT/POLLWR flags, so somebody should check this
* all. But careful, it tends to be safer to return too many
* bits than too few, and you can easily break real applications
* if you don't tell them that something has hung up!
*
* Check-me.
*
* Check number 1. POLLHUP is _UNMASKABLE_ event (see UNIX98 and
* our fs/select.c). It means that after we received EOF,
* poll always returns immediately, making impossible poll() on write()
* in state CLOSE_WAIT. One solution is evident --- to set POLLHUP
* if and only if shutdown has been made in both directions.
* Actually, it is interesting to look how Solaris and DUX
* solve this dilemma. I would prefer, if POLLHUP were maskable,
* then we could set it on SND_SHUTDOWN. BTW examples given
* in Stevens' books assume exactly this behaviour, it explains
* why POLLHUP is incompatible with POLLOUT. --ANK
*
* NOTE. Check for TCP_CLOSE is added. The goal is to prevent
* blocking on fresh not-connected or disconnected socket. --ANK
*/
if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
mask |= POLLHUP;// pollHUP的由来 被关闭
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLIN | POLLRDNORM | POLLRDHUP; //关闭了 读端
/* Connected or passive Fast Open socket? */
if (state != TCP_SYN_SENT &&
(state != TCP_SYN_RECV || tp->fastopen_rsk)) {
int target = sock_rcvlowat(sk, 0, INT_MAX);
if (tp->urg_seq == tp->copied_seq &&
!sock_flag(sk, SOCK_URGINLINE) &&
tp->urg_data)
target++;
if (tp->rcv_nxt - tp->copied_seq >= target)
mask |= POLLIN | POLLRDNORM;
if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {//写端没有关闭
if (sk_stream_is_writeable(sk)) {
mask |= POLLOUT | POLLWRNORM;
} else { /* send SIGIO later */
sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
/* Race breaker. If space is freed after
* wspace test but before the flags are set,
* IO signal will be lost. Memory barrier
* pairs with the input side.
*/
smp_mb__after_atomic();
if (sk_stream_is_writeable(sk))
mask |= POLLOUT | POLLWRNORM;
}
} else
mask |= POLLOUT | POLLWRNORM;///写端关闭了
if (tp->urg_data & TCP_URG_VALID)
mask |= POLLPRI;//带外数据 oob
}
/* This barrier is coupled with smp_wmb() in tcp_reset() */
smp_rmb();
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR;//出现报错
return mask;
}
可见:poll 一个socket fd 时 ;对于写只需要关心:POLLOUT, 对于读端需要关心:POLLIN, POLLRDHUP(读端被关闭了), 异常情况下:tcpclose或者SHUTDOWN_MASK了, 需要关注POLLHUP 表示连接被挂起;还要错误事件POLLERR;
epoll:
struct epoll_event {
uint32_t events;
epoll_data_t data;
};
revents = event_list[i].events; //取出事件类型
if (revents & (EPOLLERR|EPOLLHUP)) { //例如对方close掉套接字,这里会感应到
process
}
if (revents & EPOLLRDHUP) {
读端被关闭了;处理这一次数据
}
if ((revents & (EPOLLERR|EPOLLHUP))
&& (revents & (EPOLLIN|EPOLLOUT)) == 0) {
出现错误的同时 也有读写数据;
则处理一次 读写数据
}
这次上次review新人代码时;发现新人对poll事件掩码不清楚,没有考虑到错误异常的情况,但是错误异常的时候,在水平触发条件下会一直触发唤醒事件导致cpu飙高
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子