⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rn_dev_epoll.c

📁 linux平台epoll封装
💻 C
字号:
/*-------------------------------------------------------------------------- Copyright 1999,2001, Dan Kegel http://www.kegel.com/ Copyright 2003 Ixia http://www.ixiacom.com/ See the file COPYING This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA--------------------------------------------------------------------------*/#include <rn_config.h>	/* must come first */#include <assert.h>#include <errno.h>#include <fcntl.h>#include <linux/poll.h>	/* careful - might be wrong */#include <rn_dev_epoll.h>#include <rn_dprint.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <unistd.h>#ifdef HAVE_LINUX_EVENTPOLL_H_EP_ALLOC#ifndef FALSE#define FALSE 0#define TRUE 1#endif/* FIXME: linux/eventpoll.h macros should take value of PAGE_SIZE at runtime */#define PAGE_SIZE sysconf(_SC_PAGESIZE)#include <linux/eventpoll.h>int rn_dev_epoll_init(struct rn_dev_epoll *this, int maxfds){	int i;	DPRINT("init()\n");	/* unfortunate kludge in epoll.  May be removed eventually. */	this->maxfds = maxfds;	this->m_fds_used = 0;	this->m_fds_alloc = 16;	this->m_fds = (rn_client_t *)malloc(sizeof(rn_client_t) * this->m_fds_alloc);	if (!this->m_fds)		return ENOMEM;		for (i=this->m_fds_used; i<this->m_fds_alloc; i++) {		this->m_fds[i].pfn = NULL;		this->m_fds[i].data = NULL;	}	if ((this->epfd = open("/dev/epoll", O_RDWR)) == -1) {		perror("open() /dev/epoll");		return -1;	}	if (ioctl(this->epfd, EP_ALLOC, this->maxfds)) {		perror("ioctl() /dev/epoll");		close(this->epfd);		return -1;	}	if ((this->epmap = (char *) mmap(NULL, EP_MAP_SIZE(this->maxfds), PROT_READ, MAP_PRIVATE, this->epfd, 0)) == (char *) -1) {		perror("mmap() /dev/epoll");		ioctl(this->epfd, EP_FREE, 0);		close(this->epfd);		return -1;	}	return 0;}void rn_dev_epoll_shutdown(struct rn_dev_epoll *this){	int i;	for (i=this->m_fds_alloc-1; (i >= 0) && (this->m_fds_used > 0); i--)		if (this->m_fds[i].pfn)			rn_dev_epoll_del(this, i);	if (this->m_fds) {		free(this->m_fds);		this->m_fds = NULL;	}	munmap(this->epmap, EP_MAP_SIZE(this->maxfds));	ioctl(this->epfd, EP_FREE, 0);	close(this->epfd);}int rn_dev_epoll_prepare_fd_for_add(int fd, int pid){		/* FIXME: This is correct right now on Linux. May not be so later on */	int flags = O_RDWR | O_NONBLOCK;		(void) pid;	if (fcntl(fd, F_SETFL, flags) < 0) {		int err = errno;		LOG_ERROR("fcntl(fd %d, F_SETFL, 0x%x) returns err %d\n",				fd, flags, err);		return err;	}	return 0;}int rn_dev_epoll_add(struct rn_dev_epoll *this,int fd, rn_callback_fn_t pfn, void *data){	int i, n;	int err;	struct pollfd pfd;	if (fd >= this->m_fds_alloc) {		rn_client_t *newfds;		n = this->m_fds_alloc * 2;		if (n < fd + 1)			n = fd + 1;		newfds = (rn_client_t *)realloc(this->m_fds, n * sizeof(rn_client_t));		if (!newfds)			return ENOMEM;		for (i=this->m_fds_alloc; i<n; i++) {			newfds[i].pfn = NULL;			newfds[i].data = NULL;		}		this->m_fds = newfds;		this->m_fds_alloc = n;	}	pfd.fd = fd;	pfd.events = POLLIN | POLLOUT | POLLERR | POLLHUP;	pfd.revents = 0;	if (write(this->epfd, &pfd, sizeof(pfd)) != sizeof(pfd)) {		err = errno;		LOG_ERROR("add: write(fd %d...) returns err %d\n",				fd, err);		return err;	}	this->m_fds_used++;	/* Start out claiming "all ready", and let user program try 	 * reading/writing/accept/connecting.  An EWOULDBLOCK should be harmless;	 * the user must then call clearReadiness() to tell us we were wrong.	 * This should handle the case where the fd is already ready for something	 * when we start.  (FIXME: Could call poll() here, instead.  Should we?)	 */	this->m_fds[fd].pfn = pfn;	this->m_fds[fd].data = data;	DPRINT("add(%d, %p, %p) this->m_fds_used %d\n", fd, pfn, data, this->m_fds_used);	return 0;}int rn_dev_epoll_del(struct rn_dev_epoll *this,int fd){	int err;	struct pollfd pfd;	DPRINT("del(fd %d)\n", fd);	/* Sanity checks */	if ((fd < 0) || (fd >= this->m_fds_alloc) || (this->m_fds_used == 0)) {		LOG_ERROR("del(fd %d): fd out of range\n", fd);		return EINVAL;	}	pfd.fd = fd;	pfd.events = POLLREMOVE;	pfd.revents = 0;	if (write(this->epfd, &pfd, sizeof(pfd)) != sizeof(pfd)) {		err = errno;		LOG_ERROR("del: write(fd %d, ...) returns err %d\n", fd, err);		return err;	}	this->m_fds[fd].pfn = NULL;	this->m_fds[fd].data = NULL;	this->m_fds_used--;	return 0;}/** Sleep at most timeout_millisec waiting for an I/O readiness event on the file descriptors we're watching.   Call each descriptor's pfn if it's ready. @return 0 on success, EWOULDBLOCK if no events ready, EBADF if you forgot to close an fd after rn_del() */int rn_dev_epoll_waitAndDispatchEvents(struct rn_dev_epoll *this, int timeout_millisec){	struct evpoll evp;	struct pollfd *pfds;	rn_pollevent_t event;	int nfds;	int saw_stale = FALSE;	int handled = FALSE;	evp.ep_timeout = timeout_millisec;	evp.ep_resoff = 0;	LOG_TRACE("Calling epoll...\n");	nfds = ioctl(this->epfd, EP_POLL, &evp);	LOG_TRACE("epoll returns %d fds\n", nfds);	pfds = (struct pollfd *) (this->epmap + evp.ep_resoff);	assert(nfds < MAX_FDS_IN_EVENTPOLL);	for (; nfds > 0; nfds--, pfds++) {		int fd = pfds->fd;		if ((fd < 0) || (fd >= this->m_fds_alloc) || (this->m_fds_used == 0) || !this->m_fds[fd].pfn) {			DPRINT("waitForEvents: ignoring event on fd %d.  alloc %d used %d\n", 				fd, this->m_fds_alloc, this->m_fds_used);			/* silently ignore.  Might be stale (aren't time skews fun?) */			saw_stale = TRUE;			continue;		}		event.fd = fd;		event.revents = pfds->revents & (POLLIN|POLLPRI|POLLOUT|POLLERR|POLLHUP|POLLNVAL);		event.client = this->m_fds[fd];		DPRINT("fd %d, revents %x\n", pfds->fd, pfds->revents);		event.client.pfn(&event);		handled = TRUE;	}	if (saw_stale)		return EBADF;	if (!handled)		return EWOULDBLOCK;	return 0;}#elseenum { foo } empty;	/* ansi c forbids empty files */#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -