zoukankan      html  css  js  c++  java
  • 看看poll 事件掩码 --- review代码时发现掩码不分的错误

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

  • 相关阅读:
    时间管理(二):时间管理的六项基本原则
    时间管理(一): 达成目标需重视时间管理
    oracle 工作机制 如何工作的
    如何快速彻底删除 svn checkout出来的文件夹
    win7 安装oracle11g注意事项
    eclipse findbugs does not match outer scope rule: MutexSchedulingRule encounter a pro
    oracle ora12154 无法解析连接字符串
    oracle 动态执行表不可访问 异常处理
    log4j配置
    linux 永久 修改 主机名 ip
  • 原文地址:https://www.cnblogs.com/codestack/p/12817613.html
Copyright © 2011-2022 走看看