// Poll epoll and aio and handle any events. If can_sleep is true // and no aio events are expected, epoll will block. static void do_poll(bool can_sleep, struct timespec next_wakeup) { struct epoll_event epoll_events[MAX_EVENTS]; #if ENABLE_AIO struct io_event aio_events[MAX_EVENTS]; // We need to be careful to not let either aio or epoll events // starve the other. We do this by always doing nonblocking polls // of aio and only having epoll block if we aren't expecting aio // events. When both types of events are coming in, we switch // between processing the two types. // Poll for aio events. Don't block. int aio_cnt = io_getevents(state.aio_ctx, 0, MAX_EVENTS, aio_events, NULL); if (aio_cnt < 0) { fail2(1, -aio_cnt, "io_getevents"); } bool expect_aio = aio_cnt == MAX_EVENTS; for (int i = 0; i < aio_cnt; i++) { handle_aio_event(&aio_events[i]); } #else #define expect_aio 0 #endif // If we aren't expecting aio, block indefinitely, otherwise // just poll. int epoll_timeout = expect_aio || !can_sleep ? 0 : compute_timeout(next_wakeup); int epoll_cnt = epoll_wait(state.epoll_fd, epoll_events, MAX_EVENTS, epoll_timeout); for (int i = 0; i < epoll_cnt; i++) { #if ENABLE_AIO if (epoll_events[i].data.ptr == state.aio_dummy_event) { uint64_t eventfd_val; if (read(state.aio_eventfd, &eventfd_val, sizeof(eventfd_val)) < 0) fail(1, "eventfd read"); } else #endif { handle_epoll_event(&epoll_events[i]); } } }
int epoll_wait_call::get_current_events() { if (m_epfd_info->m_ready_fds.empty()) { return m_n_all_ready_fds; } vector<socket_fd_api *> socket_fd_vec; lock(); int i,r,w; i = r = w = m_n_all_ready_fds; socket_fd_api *p_socket_object; epoll_fd_rec fd_rec; ep_ready_fd_map_t::iterator iter = m_epfd_info->m_ready_fds.begin(); while (iter != m_epfd_info->m_ready_fds.end() && i < m_maxevents) { ep_ready_fd_map_t::iterator iter_cpy = iter; // for protection needs ++iter; p_socket_object = fd_collection_get_sockfd(iter_cpy->first); if (p_socket_object) { if(!m_epfd_info->get_fd_rec_by_fd(iter_cpy->first, fd_rec)) continue; m_events[i].events = 0; //initialize bool got_event = false; //epoll_wait will always wait for EPOLLERR and EPOLLHUP; it is not necessary to set it in events. uint32_t mutual_events = iter_cpy->second & (fd_rec.events | EPOLLERR | EPOLLHUP); //EPOLLHUP & EPOLLOUT are mutually exclusive. see poll man pages. epoll adapt poll behavior. if ((mutual_events & EPOLLHUP) && (mutual_events & EPOLLOUT)) { mutual_events &= ~EPOLLOUT; } if (mutual_events & EPOLLIN) { if (handle_epoll_event(p_socket_object->is_readable(NULL), EPOLLIN, iter_cpy, fd_rec, i)) { r++; got_event = true; } mutual_events &= ~EPOLLIN; } if (mutual_events & EPOLLOUT) { if (handle_epoll_event(p_socket_object->is_writeable(), EPOLLOUT, iter_cpy, fd_rec, i)) { w++; got_event = true; } mutual_events &= ~EPOLLOUT; } if (mutual_events) { if (handle_epoll_event(true, mutual_events, iter_cpy, fd_rec, i)) { got_event = true; } } if (got_event) { socket_fd_vec.push_back(p_socket_object); ++i; } } else { m_epfd_info->m_ready_fds.erase(iter_cpy); } } int ready_rfds = r - m_n_all_ready_fds; //MNY: not only rfds, different counters for read/write ? int ready_wfds = w - m_n_all_ready_fds; m_n_ready_rfds += ready_rfds; m_n_ready_wfds += ready_wfds; m_p_stats->n_iomux_rx_ready += ready_rfds; unlock(); /* * for checking ring migration we need a socket context. * in epoll we separate the rings from the sockets, so only here we access the sockets. * therefore, it is most convenient to check it here. * we need to move the ring migration to the epfd, going over the registered sockets, * when polling the rings was not fruitful. * this will be more similar to the behavior of select/poll. * see RM task 212058 */ for (unsigned int j = 0; j < socket_fd_vec.size(); j++) { socket_fd_vec[j]->consider_rings_migration(); } return (i); }