Blame src/vma/iomux/epfd_info.cpp

Packit 6d2c1b
/*
Packit 6d2c1b
 * Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved.
Packit 6d2c1b
 *
Packit 6d2c1b
 * This software is available to you under a choice of one of two
Packit 6d2c1b
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 6d2c1b
 * General Public License (GPL) Version 2, available from the file
Packit 6d2c1b
 * COPYING in the main directory of this source tree, or the
Packit 6d2c1b
 * BSD license below:
Packit 6d2c1b
 *
Packit 6d2c1b
 *     Redistribution and use in source and binary forms, with or
Packit 6d2c1b
 *     without modification, are permitted provided that the following
Packit 6d2c1b
 *     conditions are met:
Packit 6d2c1b
 *
Packit 6d2c1b
 *      - Redistributions of source code must retain the above
Packit 6d2c1b
 *        copyright notice, this list of conditions and the following
Packit 6d2c1b
 *        disclaimer.
Packit 6d2c1b
 *
Packit 6d2c1b
 *      - Redistributions in binary form must reproduce the above
Packit 6d2c1b
 *        copyright notice, this list of conditions and the following
Packit 6d2c1b
 *        disclaimer in the documentation and/or other materials
Packit 6d2c1b
 *        provided with the distribution.
Packit 6d2c1b
 *
Packit 6d2c1b
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 6d2c1b
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 6d2c1b
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 6d2c1b
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 6d2c1b
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 6d2c1b
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 6d2c1b
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 6d2c1b
 * SOFTWARE.
Packit 6d2c1b
 */
Packit 6d2c1b
Packit 6d2c1b
#include <vma/sock/fd_collection.h>
Packit 6d2c1b
#include <vma/iomux/epfd_info.h>
Packit 6d2c1b
Packit 6d2c1b
#define MODULE_NAME "epfd_info:"
Packit 6d2c1b
Packit 6d2c1b
#define SUPPORTED_EPOLL_EVENTS (EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLRDHUP|EPOLLONESHOT|EPOLLET)
Packit 6d2c1b
Packit 6d2c1b
#define NUM_LOG_INVALID_EVENTS 10
Packit 6d2c1b
#define EPFD_MAX_OFFLOADED_STR 150
Packit 6d2c1b
Packit 6d2c1b
#define CQ_FD_MARK 0xabcd
Packit 6d2c1b
Packit 6d2c1b
int epfd_info::remove_fd_from_epoll_os(int fd)
Packit 6d2c1b
{
Packit 6d2c1b
	int ret = orig_os_api.epoll_ctl(m_epfd, EPOLL_CTL_DEL, fd, NULL);
Packit 6d2c1b
	BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
	if (ret < 0) {
Packit 6d2c1b
		__log_dbg("failed to remove fd=%d from os epoll epfd=%d (errno=%d %m)", fd, m_epfd, errno);
Packit 6d2c1b
	}
Packit 6d2c1b
	BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
	return ret;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
epfd_info::epfd_info(int epfd, int size) :
Packit 6d2c1b
	lock_mutex_recursive("epfd_info"), m_epfd(epfd), m_size(size), m_ring_map_lock("epfd_ring_map_lock"),
Packit 6d2c1b
	m_lock_poll_os("epfd_lock_poll_os"), m_sysvar_thread_mode(safe_mce_sys().thread_mode),
Packit 6d2c1b
	m_b_os_data_available(false)
Packit 6d2c1b
{
Packit 6d2c1b
	__log_funcall("");
Packit 6d2c1b
	int max_sys_fd = get_sys_max_fd_num();
Packit 6d2c1b
	if (m_size<=max_sys_fd)
Packit 6d2c1b
	{
Packit 6d2c1b
		m_size=max_sys_fd;
Packit 6d2c1b
		__log_dbg("using open files max limit of %d file descriptors", m_size);
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	m_ready_fds.set_id("epfd_info (%p) : m_ready_fds", this);
Packit 6d2c1b
Packit 6d2c1b
	m_p_offloaded_fds = new int[m_size];
Packit 6d2c1b
	m_n_offloaded_fds = 0;
Packit 6d2c1b
Packit 6d2c1b
	memset(&(m_local_stats.stats), 0, sizeof(m_local_stats.stats));
Packit 6d2c1b
Packit 6d2c1b
	/* This initialization is not needed (because it is also done in shmem) but for proper code
Packit 6d2c1b
	 * we do it in any case
Packit 6d2c1b
	 */
Packit 6d2c1b
	m_local_stats.enabled = true;
Packit 6d2c1b
	m_local_stats.epfd = m_epfd;
Packit 6d2c1b
Packit 6d2c1b
	m_stats = &m_local_stats;
Packit 6d2c1b
Packit 6d2c1b
	m_log_invalid_events = NUM_LOG_INVALID_EVENTS;
Packit 6d2c1b
Packit 6d2c1b
	vma_stats_instance_create_epoll_block(m_epfd, &(m_stats->stats));
Packit 6d2c1b
Packit 6d2c1b
	// Register this socket to read nonoffloaded data
Packit 6d2c1b
	g_p_event_handler_manager->update_epfd(m_epfd, EPOLL_CTL_ADD, EPOLLIN | EPOLLPRI | EPOLLONESHOT);
Packit 6d2c1b
Packit 6d2c1b
	wakeup_set_epoll_fd(m_epfd);
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
epfd_info::~epfd_info()
Packit 6d2c1b
{
Packit 6d2c1b
	__log_funcall("");
Packit 6d2c1b
	socket_fd_api* sock_fd;
Packit 6d2c1b
Packit 6d2c1b
	// Meny: going over all handled fds and removing epoll context.
Packit 6d2c1b
Packit 6d2c1b
	lock();
Packit 6d2c1b
Packit 6d2c1b
	while(!m_ready_fds.empty())
Packit 6d2c1b
	{
Packit 6d2c1b
		sock_fd = m_ready_fds.get_and_pop_front();
Packit 6d2c1b
		sock_fd->m_epoll_event_flags = 0;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	while(!m_fd_offloaded_list.empty())
Packit 6d2c1b
	{
Packit 6d2c1b
		sock_fd = m_fd_offloaded_list.get_and_pop_front();
Packit 6d2c1b
		sock_fd->m_fd_rec.reset();
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	for (int i = 0; i < m_n_offloaded_fds; i++) {
Packit 6d2c1b
		sock_fd = fd_collection_get_sockfd(m_p_offloaded_fds[i]);
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
		if (sock_fd) {
Packit 6d2c1b
			unlock();
Packit 6d2c1b
			m_ring_map_lock.lock();
Packit 6d2c1b
			sock_fd->remove_epoll_context(this);
Packit 6d2c1b
			m_ring_map_lock.unlock();
Packit 6d2c1b
			lock();
Packit 6d2c1b
		} else {
Packit 6d2c1b
			__log_err("Invalid temp_sock_fd_api==NULL. Deleted fds should have been removed from epfd.");
Packit 6d2c1b
		}
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	g_p_event_handler_manager->update_epfd(m_epfd, EPOLL_CTL_DEL, EPOLLIN | EPOLLPRI | EPOLLONESHOT);
Packit 6d2c1b
Packit 6d2c1b
	unlock();
Packit 6d2c1b
Packit 6d2c1b
	vma_stats_instance_remove_epoll_block(&m_stats->stats);
Packit 6d2c1b
	delete [] m_p_offloaded_fds;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int epfd_info::ctl(int op, int fd, epoll_event *event)
Packit 6d2c1b
{
Packit 6d2c1b
	int ret;
Packit 6d2c1b
	epoll_event event_dummy;
Packit 6d2c1b
	if (event == NULL) {
Packit 6d2c1b
		memset(&event_dummy, 0, sizeof(event_dummy));
Packit 6d2c1b
		event = &event_dummy;
Packit 6d2c1b
	}
Packit 6d2c1b
	
Packit 6d2c1b
	// YossiE TODO make "event table" - and add index in that table instead
Packit 6d2c1b
	// of real event (in orig_os_api.epoll_ctl). must have this because fd's can
Packit 6d2c1b
	// be added after the cq.
Packit 6d2c1b
	lock();
Packit 6d2c1b
	
Packit 6d2c1b
	switch (op) {
Packit 6d2c1b
	case EPOLL_CTL_ADD:
Packit 6d2c1b
		ret = add_fd(fd, event);
Packit 6d2c1b
		break;
Packit 6d2c1b
	case EPOLL_CTL_DEL:
Packit 6d2c1b
		ret = del_fd(fd);
Packit 6d2c1b
		break;
Packit 6d2c1b
	case EPOLL_CTL_MOD:
Packit 6d2c1b
		ret = mod_fd(fd, event);
Packit 6d2c1b
		break;
Packit 6d2c1b
	default:
Packit 6d2c1b
		errno = EINVAL;
Packit 6d2c1b
		ret = -1;
Packit 6d2c1b
		break;
Packit 6d2c1b
	}
Packit 6d2c1b
	
Packit 6d2c1b
	unlock();
Packit 6d2c1b
	return ret;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::get_offloaded_fds_arr_and_size(int **p_p_num_offloaded_fds,
Packit 6d2c1b
					       int **p_p_offloadded_fds)
Packit 6d2c1b
{
Packit 6d2c1b
	*p_p_num_offloaded_fds = &m_n_offloaded_fds;
Packit 6d2c1b
	*p_p_offloadded_fds = m_p_offloaded_fds;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
bool epfd_info::is_cq_fd(uint64_t data)
Packit 6d2c1b
{
Packit 6d2c1b
	if ((data >> 32) != CQ_FD_MARK)
Packit 6d2c1b
		return false;
Packit 6d2c1b
Packit 6d2c1b
	lock();
Packit 6d2c1b
	//todo consider making m_ready_cq_fd_q a set instead of queue
Packit 6d2c1b
	m_ready_cq_fd_q.push_back((int)(data & 0xffff));
Packit 6d2c1b
	unlock();
Packit 6d2c1b
Packit 6d2c1b
	return true;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int epfd_info::add_fd(int fd, epoll_event *event)
Packit 6d2c1b
{
Packit 6d2c1b
	int ret;
Packit 6d2c1b
	epoll_fd_rec fd_rec;
Packit 6d2c1b
	epoll_event evt = {0, {0}};
Packit 6d2c1b
Packit 6d2c1b
	bool is_offloaded = false;
Packit 6d2c1b
	
Packit 6d2c1b
	__log_funcall("fd=%d", fd);
Packit 6d2c1b
Packit 6d2c1b
	socket_fd_api* temp_sock_fd_api = fd_collection_get_sockfd(fd);
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->get_type()== FD_TYPE_SOCKET) {
Packit 6d2c1b
		is_offloaded = true;
Packit 6d2c1b
	}
Packit 6d2c1b
	
Packit 6d2c1b
	// Make sure that offloaded fd has a correct event mask
Packit 6d2c1b
	if (is_offloaded) {
Packit 6d2c1b
		if (m_log_invalid_events && (event->events & ~SUPPORTED_EPOLL_EVENTS)) {
Packit 6d2c1b
			__log_dbg("invalid event mask 0x%x for offloaded fd=%d", event->events, fd);
Packit 6d2c1b
			__log_dbg("(event->events & ~%s)=0x%x", TO_STR(SUPPORTED_EPOLL_EVENTS),
Packit 6d2c1b
			          event->events & ~SUPPORTED_EPOLL_EVENTS);
Packit 6d2c1b
			m_log_invalid_events--;
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->skip_os_select()) {
Packit 6d2c1b
		__log_dbg("fd=%d must be skipped from os epoll()", fd);
Packit 6d2c1b
		// Checking for duplicate fds
Packit 6d2c1b
		if (get_fd_rec(fd)) {
Packit 6d2c1b
			errno = EEXIST;
Packit 6d2c1b
			__log_dbg("epoll_ctl: fd=%d is already registered with this epoll instance %d (errno=%d %m)", fd, m_epfd, errno);
Packit 6d2c1b
			return -1;
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
	else {
Packit 6d2c1b
		// Add an event which indirectly point to our event
Packit 6d2c1b
		evt.events = event->events;
Packit 6d2c1b
		evt.data.u64 = 0; //zero all data
Packit 6d2c1b
		evt.data.fd = fd;
Packit 6d2c1b
		ret = orig_os_api.epoll_ctl(m_epfd, EPOLL_CTL_ADD, fd, &evt);
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
		if (ret < 0) {
Packit 6d2c1b
			__log_dbg("failed to add fd=%d to epoll epfd=%d (errno=%d %m)", fd, m_epfd, errno);
Packit 6d2c1b
			return ret;
Packit 6d2c1b
		}
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	fd_rec.events = event->events;
Packit 6d2c1b
	fd_rec.epdata = event->data;
Packit 6d2c1b
Packit 6d2c1b
	if (is_offloaded) {  // TODO: do we need to handle offloading only for one of read/write?
Packit 6d2c1b
		if (m_n_offloaded_fds >= m_size) {
Packit 6d2c1b
			__log_dbg("Reached max fds for epoll (%d)", m_size);
Packit 6d2c1b
			errno = ENOMEM;
Packit 6d2c1b
			return -1;
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		//NOTE: when supporting epoll on epfd, need to add epfd ring list
Packit 6d2c1b
		//NOTE: when having rings in pipes, need to overload add_epoll_context
Packit 6d2c1b
		unlock();
Packit 6d2c1b
		m_ring_map_lock.lock();
Packit 6d2c1b
		ret = temp_sock_fd_api->add_epoll_context(this);
Packit 6d2c1b
		m_ring_map_lock.unlock();
Packit 6d2c1b
		lock();
Packit 6d2c1b
Packit 6d2c1b
		if (ret < 0) {
Packit 6d2c1b
			switch (errno) {
Packit 6d2c1b
			case EEXIST:
Packit 6d2c1b
				__log_dbg("epoll_ctl: fd=%d is already registered with this epoll instance %d (errno=%d %m)", fd, m_epfd, errno);
Packit 6d2c1b
				break;
Packit 6d2c1b
			case ENOMEM:
Packit 6d2c1b
				__log_dbg("epoll_ctl: fd=%d is already registered with another epoll instance %d, cannot register to epoll %d (errno=%d %m)", fd, temp_sock_fd_api->get_epoll_context_fd(), m_epfd, errno);
Packit 6d2c1b
				break;
Packit 6d2c1b
			default:
Packit 6d2c1b
				__log_dbg("epoll_ctl: failed to add fd=%d to epoll epfd=%d (errno=%d %m)", fd, m_epfd, errno);
Packit 6d2c1b
				break;
Packit 6d2c1b
			}
Packit 6d2c1b
			return ret;
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		m_p_offloaded_fds[m_n_offloaded_fds] = fd;
Packit 6d2c1b
		++m_n_offloaded_fds;
Packit 6d2c1b
Packit 6d2c1b
		m_fd_offloaded_list.push_back(temp_sock_fd_api);
Packit 6d2c1b
		fd_rec.offloaded_index = m_n_offloaded_fds;
Packit 6d2c1b
		temp_sock_fd_api->m_fd_rec = fd_rec;
Packit 6d2c1b
Packit 6d2c1b
		// if the socket is ready, add it to ready events
Packit 6d2c1b
		uint32_t events = 0;
Packit 6d2c1b
		if ((event->events & EPOLLIN) && temp_sock_fd_api->is_readable(NULL, NULL)) {
Packit 6d2c1b
			events |=  EPOLLIN;
Packit 6d2c1b
		}
Packit 6d2c1b
		if ((event->events & EPOLLOUT) && temp_sock_fd_api->is_writeable()) {
Packit 6d2c1b
			// MNY: udp_socket is always ready to write. Both VMA and the OS will notify it.
Packit 6d2c1b
			// Can't remove notification in VMA in case user decides to skip the OS using VMA params.
Packit 6d2c1b
			// Meaning: user will get 2 ready WRITE events on startup of socket
Packit 6d2c1b
			events |= EPOLLOUT;
Packit 6d2c1b
		}
Packit 6d2c1b
		if (events != 0) {
Packit 6d2c1b
			insert_epoll_event(temp_sock_fd_api, events);
Packit 6d2c1b
		}
Packit 6d2c1b
		else{
Packit 6d2c1b
			do_wakeup();
Packit 6d2c1b
		}
Packit 6d2c1b
	} else {
Packit 6d2c1b
		fd_rec.offloaded_index = -1;
Packit 6d2c1b
		m_fd_non_offloaded_map[fd] = fd_rec;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	__log_func("fd %d added in epfd %d with events=%#x and data=%#x", 
Packit 6d2c1b
		   fd, m_epfd, event->events, event->data);
Packit 6d2c1b
	return 0;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::increase_ring_ref_count(ring* ring)
Packit 6d2c1b
{
Packit 6d2c1b
	m_ring_map_lock.lock();
Packit 6d2c1b
	ring_map_t::iterator iter = m_ring_map.find(ring);
Packit 6d2c1b
	if (iter != m_ring_map.end()) {
Packit 6d2c1b
		//increase ref count
Packit 6d2c1b
		iter->second++;
Packit 6d2c1b
	} else {
Packit 6d2c1b
		m_ring_map[ring] = 1;
Packit 6d2c1b
Packit 6d2c1b
		// add cq channel fd to the epfd
Packit 6d2c1b
		int num_ring_rx_fds = ring->get_num_resources();
Packit 6d2c1b
		int *ring_rx_fds_array = ring->get_rx_channel_fds();
Packit 6d2c1b
		for (int i = 0; i < num_ring_rx_fds; i++) {
Packit 6d2c1b
			epoll_event evt = {0, {0}};
Packit 6d2c1b
			evt.events = EPOLLIN | EPOLLPRI;
Packit 6d2c1b
			int fd = ring_rx_fds_array[i];
Packit 6d2c1b
			evt.data.u64 = (((uint64_t)CQ_FD_MARK << 32) | fd);
Packit 6d2c1b
			int ret = orig_os_api.epoll_ctl(m_epfd, EPOLL_CTL_ADD, fd, &evt);
Packit 6d2c1b
			BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
			if (ret < 0) {
Packit 6d2c1b
				__log_dbg("failed to add cq fd=%d to epoll epfd=%d (errno=%d %m)",
Packit 6d2c1b
						fd, m_epfd, errno);
Packit 6d2c1b
			} else {
Packit 6d2c1b
				__log_dbg("add cq fd=%d to epfd=%d", fd, m_epfd);
Packit 6d2c1b
			}
Packit 6d2c1b
			BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
	m_ring_map_lock.unlock();
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::decrease_ring_ref_count(ring* ring)
Packit 6d2c1b
{
Packit 6d2c1b
	m_ring_map_lock.lock();
Packit 6d2c1b
	ring_map_t::iterator iter = m_ring_map.find(ring);
Packit 6d2c1b
	BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
	if (iter == m_ring_map.end()) {
Packit 6d2c1b
		__log_err("expected to find ring %p here!", ring);
Packit 6d2c1b
		m_ring_map_lock.unlock();
Packit 6d2c1b
		return;
Packit 6d2c1b
	}
Packit 6d2c1b
	BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
Packit 6d2c1b
	//decrease ref count
Packit 6d2c1b
	iter->second--;
Packit 6d2c1b
Packit 6d2c1b
	if (iter->second == 0) {
Packit 6d2c1b
		m_ring_map.erase(iter);
Packit 6d2c1b
Packit 6d2c1b
		// remove cq channel fd from the epfd
Packit 6d2c1b
		int num_ring_rx_fds = ring->get_num_resources();
Packit 6d2c1b
		int *ring_rx_fds_array = ring->get_rx_channel_fds();
Packit 6d2c1b
		for (int i = 0; i < num_ring_rx_fds; i++) {
Packit 6d2c1b
			// delete cq fd from epfd
Packit 6d2c1b
			int ret = orig_os_api.epoll_ctl(m_epfd, EPOLL_CTL_DEL, ring_rx_fds_array[i], NULL);
Packit 6d2c1b
			BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
			if (ret < 0) {
Packit 6d2c1b
				__log_dbg("failed to remove cq fd=%d from epfd=%d (errno=%d %m)",
Packit 6d2c1b
						ring_rx_fds_array[i], m_epfd, errno);
Packit 6d2c1b
			} else {
Packit 6d2c1b
				__log_dbg("remove cq fd=%d from epfd=%d", ring_rx_fds_array[i], m_epfd);
Packit 6d2c1b
			}
Packit 6d2c1b
			BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
	m_ring_map_lock.unlock();
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
/*
Packit 6d2c1b
 * del_fd have two modes:
Packit 6d2c1b
 * 1. not passthrough (default) - remove the fd from the epfd, both from OS epfd and VMA epfd
Packit 6d2c1b
 * 2. passthrough - remove the fd as offloaded fd, and keep it only on OS epfd if it was there.
Packit 6d2c1b
 *    this is a 1 way direction from both offloaded/not-offloaded to not-offloaded only.
Packit 6d2c1b
 */
Packit 6d2c1b
int epfd_info::del_fd(int fd, bool passthrough)
Packit 6d2c1b
{
Packit 6d2c1b
	__log_funcall("fd=%d", fd);
Packit 6d2c1b
Packit 6d2c1b
	epoll_fd_rec* fi;
Packit 6d2c1b
	socket_fd_api* temp_sock_fd_api = fd_collection_get_sockfd(fd);
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->skip_os_select()) {
Packit 6d2c1b
		__log_dbg("fd=%d must be skipped from os epoll()", fd);
Packit 6d2c1b
	}
Packit 6d2c1b
	else if (!passthrough) {
Packit 6d2c1b
		remove_fd_from_epoll_os(fd);
Packit 6d2c1b
	}
Packit 6d2c1b
	
Packit 6d2c1b
	fi = get_fd_rec(fd);
Packit 6d2c1b
	if (!fi) {
Packit 6d2c1b
		errno = ENOENT;
Packit 6d2c1b
		return -1;
Packit 6d2c1b
	}
Packit 6d2c1b
	
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->get_epoll_context_fd() == m_epfd) {
Packit 6d2c1b
		m_fd_offloaded_list.erase(temp_sock_fd_api);
Packit 6d2c1b
		if (passthrough) {
Packit 6d2c1b
			// In case the socket is not offloaded we must copy it to the non offloaded sockets map.
Packit 6d2c1b
			// This can happen after bind(), listen() or accept() calls.
Packit 6d2c1b
			m_fd_non_offloaded_map[fd] = *fi;
Packit 6d2c1b
			m_fd_non_offloaded_map[fd].offloaded_index = -1;
Packit 6d2c1b
		}
Packit 6d2c1b
	} else {
Packit 6d2c1b
		fd_info_map_t::iterator fd_iter = m_fd_non_offloaded_map.find(fd);
Packit 6d2c1b
		if (fd_iter != m_fd_non_offloaded_map.end()) {
Packit 6d2c1b
			m_fd_non_offloaded_map.erase(fd_iter);
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->ep_ready_fd_node.is_list_member()) {
Packit 6d2c1b
		temp_sock_fd_api->m_epoll_event_flags = 0;
Packit 6d2c1b
		m_ready_fds.erase(temp_sock_fd_api);
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	// handle offloaded fds
Packit 6d2c1b
	if (fi->offloaded_index > 0) {
Packit 6d2c1b
Packit 6d2c1b
		//check if the index of fd, which is being removed, is the last one.
Packit 6d2c1b
		//if does, it is enough to decrease the val of m_n_offloaded_fds in order
Packit 6d2c1b
		//to shrink the offloaded fds array.
Packit 6d2c1b
		if (fi->offloaded_index < m_n_offloaded_fds) {
Packit 6d2c1b
			// remove fd and replace by last fd
Packit 6d2c1b
			m_p_offloaded_fds[fi->offloaded_index - 1] =
Packit 6d2c1b
					m_p_offloaded_fds[m_n_offloaded_fds - 1];
Packit 6d2c1b
Packit 6d2c1b
			socket_fd_api* last_socket = fd_collection_get_sockfd(m_p_offloaded_fds[m_n_offloaded_fds - 1]);
Packit 6d2c1b
			if (last_socket && last_socket->get_epoll_context_fd() == m_epfd) {
Packit 6d2c1b
				last_socket->m_fd_rec.offloaded_index = fi->offloaded_index;
Packit 6d2c1b
			} else {
Packit 6d2c1b
				__log_warn("Failed to update the index of offloaded fd: %d last_socket %p\n",
Packit 6d2c1b
						m_p_offloaded_fds[m_n_offloaded_fds - 1], last_socket);
Packit 6d2c1b
			}
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		--m_n_offloaded_fds;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	if (temp_sock_fd_api) {
Packit 6d2c1b
		temp_sock_fd_api->m_fd_rec.reset();
Packit 6d2c1b
		unlock();
Packit 6d2c1b
		m_ring_map_lock.lock();
Packit 6d2c1b
		temp_sock_fd_api->remove_epoll_context(this);
Packit 6d2c1b
		m_ring_map_lock.unlock();
Packit 6d2c1b
		lock();
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	__log_func("fd %d removed from epfd %d", fd, m_epfd);
Packit 6d2c1b
	return 0;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int epfd_info::mod_fd(int fd, epoll_event *event)
Packit 6d2c1b
{
Packit 6d2c1b
	epoll_event evt;
Packit 6d2c1b
	epoll_fd_rec* fd_rec;
Packit 6d2c1b
	int ret;
Packit 6d2c1b
Packit 6d2c1b
	__log_funcall("fd=%d", fd);
Packit 6d2c1b
	// find the fd in local table
Packit 6d2c1b
	fd_rec = get_fd_rec(fd);
Packit 6d2c1b
	if (!fd_rec) {
Packit 6d2c1b
		errno = ENOENT;
Packit 6d2c1b
		return -1;
Packit 6d2c1b
	}
Packit 6d2c1b
	
Packit 6d2c1b
	socket_fd_api* temp_sock_fd_api = fd_collection_get_sockfd(fd);
Packit 6d2c1b
	// check if fd is offloaded that new event mask is OK 
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->m_fd_rec.offloaded_index > 0) {
Packit 6d2c1b
		if (m_log_invalid_events && (event->events & ~SUPPORTED_EPOLL_EVENTS)) {
Packit 6d2c1b
			__log_dbg("invalid event mask 0x%x for offloaded fd=%d", event->events, fd);
Packit 6d2c1b
			__log_dbg("(event->events & ~%s)=0x%x", TO_STR(SUPPORTED_EPOLL_EVENTS),
Packit 6d2c1b
					event->events & ~SUPPORTED_EPOLL_EVENTS);
Packit 6d2c1b
			m_log_invalid_events--;
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->skip_os_select()) {
Packit 6d2c1b
		__log_dbg("fd=%d must be skipped from os epoll()", fd);
Packit 6d2c1b
	}
Packit 6d2c1b
	else {
Packit 6d2c1b
		// modify fd
Packit 6d2c1b
		evt.events = event->events;
Packit 6d2c1b
		evt.data.u64 = 0; //zero all data
Packit 6d2c1b
		evt.data.fd = fd;
Packit 6d2c1b
		ret = orig_os_api.epoll_ctl(m_epfd, EPOLL_CTL_MOD, fd, &evt);
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
		if (ret < 0) {
Packit 6d2c1b
			__log_err("failed to modify fd=%d in epoll epfd=%d (errno=%d %m)", fd, m_epfd, errno);
Packit 6d2c1b
			return ret;
Packit 6d2c1b
		}
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	// modify fd data in local table
Packit 6d2c1b
	fd_rec->epdata = event->data;
Packit 6d2c1b
	fd_rec->events = event->events;
Packit 6d2c1b
	
Packit 6d2c1b
	bool is_offloaded = temp_sock_fd_api && temp_sock_fd_api->get_type()== FD_TYPE_SOCKET;
Packit 6d2c1b
Packit 6d2c1b
	uint32_t events = 0;
Packit 6d2c1b
	if (is_offloaded) {
Packit 6d2c1b
		// if the socket is ready, add it to ready events
Packit 6d2c1b
		if ((event->events & EPOLLIN) && temp_sock_fd_api->is_readable(NULL, NULL)) {
Packit 6d2c1b
			events |=  EPOLLIN;
Packit 6d2c1b
		}
Packit 6d2c1b
		if ((event->events & EPOLLOUT) && temp_sock_fd_api->is_writeable()) {
Packit 6d2c1b
			// MNY: udp_socket is always ready to write. Both VMA and the OS will notify it.
Packit 6d2c1b
			// Can't remove notification in VMA in case user decides to skip the OS using VMA params.
Packit 6d2c1b
			// Meaning: user will get 2 ready WRITE events on startup of socket
Packit 6d2c1b
			events |= EPOLLOUT;
Packit 6d2c1b
		}
Packit 6d2c1b
		if (events != 0) {
Packit 6d2c1b
			insert_epoll_event(temp_sock_fd_api, events);
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	if (event->events == 0 || events == 0) {
Packit 6d2c1b
		if (temp_sock_fd_api && temp_sock_fd_api->ep_ready_fd_node.is_list_member()) {
Packit 6d2c1b
			temp_sock_fd_api->m_epoll_event_flags = 0;
Packit 6d2c1b
			m_ready_fds.erase(temp_sock_fd_api);
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	__log_func("fd %d modified in epfd %d with events=%#x and data=%#x", 
Packit 6d2c1b
		   fd, m_epfd, event->events, event->data);
Packit 6d2c1b
	return 0;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
epoll_fd_rec* epfd_info::get_fd_rec(int fd)
Packit 6d2c1b
{
Packit 6d2c1b
	epoll_fd_rec* fd_rec = NULL;
Packit 6d2c1b
	socket_fd_api* temp_sock_fd_api = fd_collection_get_sockfd(fd);
Packit 6d2c1b
	lock();
Packit 6d2c1b
Packit 6d2c1b
	if (temp_sock_fd_api && temp_sock_fd_api->get_epoll_context_fd() == m_epfd) {
Packit 6d2c1b
		fd_rec = &temp_sock_fd_api->m_fd_rec;
Packit 6d2c1b
	} else {
Packit 6d2c1b
		fd_info_map_t::iterator iter = m_fd_non_offloaded_map.find(fd);
Packit 6d2c1b
		if (iter != m_fd_non_offloaded_map.end()) {
Packit 6d2c1b
			fd_rec = &iter->second;
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	unlock();
Packit 6d2c1b
	return fd_rec;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::fd_closed(int fd, bool passthrough)
Packit 6d2c1b
{
Packit 6d2c1b
	lock();
Packit 6d2c1b
	if (get_fd_rec(fd)) {
Packit 6d2c1b
		del_fd(fd, passthrough);
Packit 6d2c1b
	}
Packit 6d2c1b
	unlock();
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::insert_epoll_event_cb(socket_fd_api* sock_fd, uint32_t event_flags)
Packit 6d2c1b
{
Packit 6d2c1b
	lock();
Packit 6d2c1b
	//EPOLLHUP | EPOLLERR are reported without user request
Packit 6d2c1b
	if (event_flags & (sock_fd->m_fd_rec.events | EPOLLHUP | EPOLLERR)) {
Packit 6d2c1b
		insert_epoll_event(sock_fd, event_flags);
Packit 6d2c1b
	}
Packit 6d2c1b
	unlock();
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::insert_epoll_event(socket_fd_api *sock_fd, uint32_t event_flags)
Packit 6d2c1b
{
Packit 6d2c1b
	// assumed lock
Packit 6d2c1b
	if (sock_fd->ep_ready_fd_node.is_list_member()) {
Packit 6d2c1b
		sock_fd->m_epoll_event_flags |= event_flags;
Packit 6d2c1b
	}
Packit 6d2c1b
	else {
Packit 6d2c1b
		sock_fd->m_epoll_event_flags = event_flags;
Packit 6d2c1b
		m_ready_fds.push_back(sock_fd);
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	do_wakeup();
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::remove_epoll_event(socket_fd_api *sock_fd, uint32_t event_flags)
Packit 6d2c1b
{
Packit 6d2c1b
	sock_fd->m_epoll_event_flags &= ~event_flags;
Packit 6d2c1b
	if (sock_fd->m_epoll_event_flags == 0) {
Packit 6d2c1b
		m_ready_fds.erase(sock_fd);
Packit 6d2c1b
	}
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
epoll_stats_t *epfd_info::stats()
Packit 6d2c1b
{
Packit 6d2c1b
	return m_stats;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int epfd_info::ring_poll_and_process_element(uint64_t *p_poll_sn, void* pv_fd_ready_array/* = NULL*/)
Packit 6d2c1b
{
Packit 6d2c1b
	__log_func("");
Packit 6d2c1b
Packit 6d2c1b
	int ret_total = 0;
Packit 6d2c1b
Packit 6d2c1b
	if (m_ring_map.empty()) {
Packit 6d2c1b
		return ret_total;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	m_ring_map_lock.lock();
Packit 6d2c1b
Packit 6d2c1b
	for (ring_map_t::iterator iter = m_ring_map.begin(); iter != m_ring_map.end(); iter++) {
Packit 6d2c1b
		int ret = iter->first->poll_and_process_element_rx(p_poll_sn, pv_fd_ready_array);
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
		if (ret < 0 && errno != EAGAIN) {
Packit 6d2c1b
			__log_err("Error in ring->poll_and_process_element() of %p (errno=%d %m)", iter->first, errno);
Packit 6d2c1b
			m_ring_map_lock.unlock();
Packit 6d2c1b
			return ret;
Packit 6d2c1b
		}
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
		if (ret > 0)
Packit 6d2c1b
			__log_func("ring[%p] Returned with: %d (sn=%d)", iter->first, ret, *p_poll_sn);
Packit 6d2c1b
		ret_total += ret;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	m_ring_map_lock.unlock();
Packit 6d2c1b
Packit 6d2c1b
	if (m_sysvar_thread_mode == THREAD_MODE_PLENTY && ret_total == 0 && errno == EAGAIN) pthread_yield();
Packit 6d2c1b
Packit 6d2c1b
	if (ret_total) {
Packit 6d2c1b
		__log_func("ret_total=%d", ret_total);
Packit 6d2c1b
	} else {
Packit 6d2c1b
		__log_funcall("ret_total=%d", ret_total);
Packit 6d2c1b
	}
Packit 6d2c1b
	return ret_total;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int epfd_info::ring_request_notification(uint64_t poll_sn)
Packit 6d2c1b
{
Packit 6d2c1b
	__log_func("");
Packit 6d2c1b
	int ret_total = 0;
Packit 6d2c1b
Packit 6d2c1b
	if (m_ring_map.empty()) {
Packit 6d2c1b
		return ret_total;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	m_ring_map_lock.lock();
Packit 6d2c1b
Packit 6d2c1b
	for (ring_map_t::iterator iter = m_ring_map.begin(); iter != m_ring_map.end(); iter++) {
Packit 6d2c1b
		int ret = iter->first->request_notification(CQT_RX, poll_sn);
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
		if (ret < 0) {
Packit 6d2c1b
			__log_err("Error ring[%p]->request_notification() (errno=%d %m)", iter->first, errno);
Packit 6d2c1b
			m_ring_map_lock.unlock();
Packit 6d2c1b
			return ret;
Packit 6d2c1b
		}
Packit 6d2c1b
		BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
		__log_func("ring[%p] Returned with: %d (sn=%d)", iter->first, ret, poll_sn);
Packit 6d2c1b
		ret_total += ret;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	m_ring_map_lock.unlock();
Packit 6d2c1b
Packit 6d2c1b
	return ret_total;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int epfd_info::ring_wait_for_notification_and_process_element(uint64_t *p_poll_sn, void* pv_fd_ready_array /* = NULL*/)
Packit 6d2c1b
{
Packit 6d2c1b
	__log_func("");
Packit 6d2c1b
	int ret_total = 0;
Packit 6d2c1b
Packit 6d2c1b
	while (!m_ready_cq_fd_q.empty()) {
Packit 6d2c1b
Packit 6d2c1b
		lock();
Packit 6d2c1b
		if (m_ready_cq_fd_q.empty()) {
Packit 6d2c1b
			unlock();
Packit 6d2c1b
			break;
Packit 6d2c1b
		}
Packit 6d2c1b
		int fd = m_ready_cq_fd_q.back();
Packit 6d2c1b
		m_ready_cq_fd_q.pop_back();
Packit 6d2c1b
		unlock();
Packit 6d2c1b
Packit 6d2c1b
		cq_channel_info* p_cq_ch_info = g_p_fd_collection->get_cq_channel_fd(fd);
Packit 6d2c1b
		if (p_cq_ch_info) {
Packit 6d2c1b
			ring* p_ready_ring = p_cq_ch_info->get_ring();
Packit 6d2c1b
			// Handle the CQ notification channel
Packit 6d2c1b
			int ret = p_ready_ring->wait_for_notification_and_process_element(fd, p_poll_sn, pv_fd_ready_array);
Packit 6d2c1b
			if (ret < 0) {
Packit 6d2c1b
				if (errno == EAGAIN) {
Packit 6d2c1b
					__log_dbg("Error in ring->wait_for_notification_and_process_element() of %p (errno=%d %m)", p_ready_ring, errno);
Packit 6d2c1b
				}
Packit 6d2c1b
				else {
Packit 6d2c1b
					__log_err("Error in ring->wait_for_notification_and_process_element() of %p (errno=%d %m)", p_ready_ring, errno);
Packit 6d2c1b
				}
Packit 6d2c1b
				continue;
Packit 6d2c1b
			}
Packit 6d2c1b
			if (ret > 0) {
Packit 6d2c1b
				__log_func("ring[%p] Returned with: %d (sn=%d)", p_ready_ring, ret, *p_poll_sn);
Packit 6d2c1b
			}
Packit 6d2c1b
			ret_total += ret;
Packit 6d2c1b
		}
Packit 6d2c1b
		else {
Packit 6d2c1b
			__log_dbg("failed to find channel fd. removing cq fd=%d from epfd=%d", fd, m_epfd);
Packit 6d2c1b
			BULLSEYE_EXCLUDE_BLOCK_START
Packit 6d2c1b
			if ((orig_os_api.epoll_ctl(m_epfd, EPOLL_CTL_DEL,
Packit 6d2c1b
					fd, NULL)) && (!(errno == ENOENT || errno == EBADF))) {
Packit 6d2c1b
				__log_err("failed to del cq channel fd=%d from os epfd=%d (errno=%d %m)", fd, m_epfd, errno);
Packit 6d2c1b
			}
Packit 6d2c1b
			BULLSEYE_EXCLUDE_BLOCK_END
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	if (ret_total) {
Packit 6d2c1b
		__log_func("ret_total=%d", ret_total);
Packit 6d2c1b
	} else {
Packit 6d2c1b
		__log_funcall("ret_total=%d", ret_total);
Packit 6d2c1b
	}
Packit 6d2c1b
	return ret_total;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::clean_obj()
Packit 6d2c1b
{
Packit 6d2c1b
	if (g_p_fd_collection)
Packit 6d2c1b
		g_p_fd_collection->remove_epfd_from_list(this);
Packit 6d2c1b
	cleanable_obj::clean_obj();
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::statistics_print(vlog_levels_t log_level /* = VLOG_DEBUG */)
Packit 6d2c1b
{
Packit 6d2c1b
	size_t num_rings, num_ready_fds, num_ready_cq_fd;
Packit 6d2c1b
	int offloaded_str_place, i = 0;
Packit 6d2c1b
	char offloaded_str[VLOGGER_STR_SIZE];
Packit 6d2c1b
Packit 6d2c1b
	// Prepare data
Packit 6d2c1b
	num_rings = m_ring_map.size();
Packit 6d2c1b
	iomux_func_stats_t temp_iomux_stats = m_stats->stats;
Packit 6d2c1b
	num_ready_fds = m_ready_fds.size();
Packit 6d2c1b
	num_ready_cq_fd = m_ready_cq_fd_q.size();
Packit 6d2c1b
Packit 6d2c1b
	// Epoll data
Packit 6d2c1b
	vlog_printf(log_level, "Fd number : %d\n", m_epfd);
Packit 6d2c1b
	vlog_printf(log_level, "Size : %d\n", m_size);
Packit 6d2c1b
Packit 6d2c1b
	vlog_printf(log_level, "Offloaded Fds : %d\n", m_n_offloaded_fds);
Packit 6d2c1b
Packit 6d2c1b
	while (i < m_n_offloaded_fds) {
Packit 6d2c1b
		memset(offloaded_str, 0, sizeof(offloaded_str));
Packit 6d2c1b
		for (offloaded_str_place = 0; offloaded_str_place < EPFD_MAX_OFFLOADED_STR && i < m_n_offloaded_fds; i++) {
Packit 6d2c1b
			int n = snprintf(&offloaded_str[offloaded_str_place], sizeof(offloaded_str) - offloaded_str_place - 1, " %d", m_p_offloaded_fds[i]);
Packit 6d2c1b
			if (!likely((0 < n) && (n < (int)(sizeof(offloaded_str) - offloaded_str_place - 1)))) {
Packit 6d2c1b
				break;
Packit 6d2c1b
			}
Packit 6d2c1b
			offloaded_str_place += n;
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		offloaded_str[offloaded_str_place] = '\0';
Packit 6d2c1b
		vlog_printf(log_level, "Offloaded Fds list: %s\n", offloaded_str);
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	vlog_printf(log_level, "Number of rings : %u\n", num_rings);
Packit 6d2c1b
	vlog_printf(log_level, "Number of ready Fds : %u\n", num_ready_fds);
Packit 6d2c1b
	vlog_printf(log_level, "Number of ready CQ Fds : %u\n", num_ready_cq_fd);
Packit 6d2c1b
Packit 6d2c1b
	if (temp_iomux_stats.n_iomux_os_rx_ready || temp_iomux_stats.n_iomux_rx_ready || temp_iomux_stats.n_iomux_timeouts || temp_iomux_stats.n_iomux_errors ||
Packit 6d2c1b
			temp_iomux_stats.n_iomux_poll_miss || temp_iomux_stats.n_iomux_poll_hit) {
Packit 6d2c1b
Packit 6d2c1b
		vlog_printf(log_level, "Polling CPU : %d%%\n", temp_iomux_stats.n_iomux_polling_time);
Packit 6d2c1b
Packit 6d2c1b
		if (temp_iomux_stats.threadid_last != 0)
Packit 6d2c1b
			vlog_printf(log_level, "Thread Id : %5u\n", temp_iomux_stats.threadid_last);
Packit 6d2c1b
Packit 6d2c1b
		if (temp_iomux_stats.n_iomux_os_rx_ready || temp_iomux_stats.n_iomux_rx_ready)
Packit 6d2c1b
			vlog_printf(log_level, "Rx fds ready : %u / %u [os/offload]\n", temp_iomux_stats.n_iomux_os_rx_ready, temp_iomux_stats.n_iomux_rx_ready);
Packit 6d2c1b
Packit 6d2c1b
		if (temp_iomux_stats.n_iomux_poll_miss + temp_iomux_stats.n_iomux_poll_hit) {
Packit 6d2c1b
			double iomux_poll_hit = (double)temp_iomux_stats.n_iomux_poll_hit;
Packit 6d2c1b
			double iomux_poll_hit_percentage = (iomux_poll_hit / (iomux_poll_hit + (double)temp_iomux_stats.n_iomux_poll_miss)) * 100;
Packit 6d2c1b
			vlog_printf(log_level, "Polls [miss/hit] : %u / %u (%2.2f%%)\n", temp_iomux_stats.n_iomux_poll_miss, temp_iomux_stats.n_iomux_poll_hit, iomux_poll_hit_percentage);
Packit 6d2c1b
Packit 6d2c1b
			if (temp_iomux_stats.n_iomux_timeouts)
Packit 6d2c1b
				vlog_printf(log_level, "Timeouts : %u\n", temp_iomux_stats.n_iomux_timeouts);
Packit 6d2c1b
Packit 6d2c1b
			if (temp_iomux_stats.n_iomux_errors)
Packit 6d2c1b
				vlog_printf(log_level, "Errors : %u\n", temp_iomux_stats.n_iomux_errors);
Packit 6d2c1b
		}
Packit 6d2c1b
	}
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::set_os_data_available()
Packit 6d2c1b
{
Packit 6d2c1b
	auto_unlocker locker(m_lock_poll_os);
Packit 6d2c1b
	m_b_os_data_available = true;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
void epfd_info::register_to_internal_thread()
Packit 6d2c1b
{
Packit 6d2c1b
	auto_unlocker locker(m_lock_poll_os);
Packit 6d2c1b
	m_b_os_data_available = false;
Packit 6d2c1b
Packit 6d2c1b
	// Reassign EPOLLIN event
Packit 6d2c1b
	g_p_event_handler_manager->update_epfd(m_epfd, EPOLL_CTL_MOD, EPOLLIN | EPOLLPRI | EPOLLONESHOT);
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
bool epfd_info::get_and_unset_os_data_available()
Packit 6d2c1b
{
Packit 6d2c1b
	auto_unlocker locker(m_lock_poll_os);
Packit 6d2c1b
	bool ret = m_b_os_data_available;
Packit 6d2c1b
	m_b_os_data_available = false;
Packit 6d2c1b
	return ret;
Packit 6d2c1b
}