事件 描述 是否可作为输入(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飙高