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

📄 cl_poll.c

📁 linux集群服务器软件代码包
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: cl_poll.c,v 1.21 2004/02/17 22:11:58 lars Exp $ */#include <portability.h>#include <stdlib.h>#include <unistd.h>/* * Substitute poll(2) function using POSIX real time signals. * * The poll(2) system call often has significant latencies and realtime * impacts (probably because of its variable length argument list). * * These functions let us use real time signals and sigtimedwait(2) instead * of poll - for those files which work with real time signals. * In the 2.4 series of Linux kernels, this does *not* include FIFOs. * * NOTE:  We (have to) grab the SIGPOLL signal for our own purposes. *		Hope that's OK with you... * * Special caution:  We can only incompletely simulate the difference between * the level-triggered interface of poll(2) and the edge-triggered behavior * of I/O signals.  As a result you *must* read all previously-indicated * incoming data before calling cl_poll() again.  Otherwise you may miss * some incoming data (and possibly hang). * * * Copyright (C) 2003 IBM Corporation * * Author:	<alanr@unix.sh> * * This software licensed under the GNU LGPL. * * * This library is free software; you can redistribute it and/or * modify it under the terms of version 2.1 of the GNU Lesser General Public * License as published by the Free Software Foundation. *  * 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 * **************************************************************************/#define	__USE_GNU	1#	include <fcntl.h>#undef	__USE_GNU#include <errno.h>#include <string.h>#include <glib.h>#include <clplumbing/cl_log.h>#include <clplumbing/cl_poll.h>#include <clplumbing/cl_signal.h>/* Turn on to log odd realtime behavior */#define	TIME_CALLS	1#ifdef	TIME_CALLS#	include <clplumbing/longclock.h>#	include <clplumbing/cl_log.h>#endifstatic int	debug = 0;int	/* Slightly sleazy... */cl_glibpoll(GPollFD* ufds, guint nfsd, gint timeout){	(void)debug;	return cl_poll((struct pollfd*)ufds, nfsd, timeout);}#if defined (F_SETSIG) && defined(F_SETOWN) && defined (O_ASYNC)#	define HAVE_FCNTL_F_SETSIG#endif#ifndef HAVE_FCNTL_F_SETSIG/* * Dummy cl_poll() and cl_poll_ignore() functions for systems where * we don't have all the support we need. */intcl_poll(struct pollfd *fds, unsigned int nfds, int timeout){	return poll(fds, (nfds_t)nfds, timeout);}intcl_poll_ignore(int fd){	return 0;}#else /* HAVE_FCNTL_F_SETSIG */static void dump_fd_info(struct pollfd *fds, unsigned int nfds, int timeoutms);static void check_fd_info(struct pollfd *fds, unsigned int nfds);static void cl_real_poll_fd(int fd);static void cl_poll_sigpoll_overflow_sigaction(int nsig, siginfo_t* , void*);static void cl_poll_sigpoll_overflow(void);static int cl_poll_get_sigqlimit(void);typedef	unsigned char poll_bool;/* *	Here's our strategy: *	We have a set of signals which we use for these file descriptors, *	and we use sigtimedwait(2) to wait on information from these various *	signals. * *	If we are ever asked to wait for a particular signal, then we will *	enable signals for that file descriptor, and post the events in *	our own cache.  The next time you include that signal in a call *	to cl_poll(), you will get the information delivered *	to you in your cl_poll() call. * *	If you want to stop monitoring a particular file descriptor, use *	cl_poll_ignore() for that purpose.  Doing this is a good idea, but *	not fatal if omitted... *//* Information about a file descriptor we're monitoring */typedef struct poll_fd_info_s {	short		nsig;		/* Which signal goes with it? */	short		pendevents;	/* Pending events */}poll_info_t;static int		max_allocated = 0;static poll_bool*	is_monitored = NULL;	/* Sized by max_allocated */static poll_info_t*	monitorinfo = NULL;	/* Sized by max_allocated */static int		cl_nsig = 0;static gboolean		SigQOverflow = FALSE;static int	cl_init_poll_sig(struct pollfd *fds, unsigned int nfds);static short	cl_poll_assignsig(int fd);static void	cl_poll_sigaction(int nsig, siginfo_t* info, void* v);static int	cl_poll_prepsig(int nsig);/* *	SignalSet is the set of all file descriptors we're monitoring. * *	We monitor a file descriptor forever, unless you tell us not to *	by calling cl_poll_ignore(), or you (mistakenly) give it to *	us to look at in another poll call after you've closed it. */static sigset_t	SignalSet;/* Select the signal you want us to use (must be a RT signal) */intcl_poll_setsig(int nsig){	if (nsig < SIGRTMIN || nsig >= SIGRTMAX) {		errno = EINVAL;		return -1;	}	if (cl_poll_prepsig(nsig) < 0) {		return -1;	}	cl_nsig = nsig;	return 0;}/* *	It's harmless to call us multiple times on the same signal. */static intcl_poll_prepsig(int nsig){	static gboolean	setinityet=FALSE;		if (!setinityet) {		CL_SIGEMPTYSET(&SignalSet);		cl_signal_set_simple_action(SIGPOLL		,	cl_poll_sigpoll_overflow_sigaction		,	NULL);		setinityet = TRUE;	}	if (CL_SIGINTERRUPT(nsig, FALSE) < 0) {		cl_perror("sig_interrupt(%d, FALSE)", nsig);		return -1;	}	if (CL_SIGADDSET(&SignalSet, nsig) < 0) {		cl_perror("sig_addset(&SignalSet, %d)", nsig);		return -1;	}	if (CL_SIGPROCMASK(SIG_BLOCK, &SignalSet, NULL) < 0) {		cl_perror("sig_sigprocmask(SIG_BLOCK, sig %d)", nsig);		return -1;	}	if (debug) {		cl_log(LOG_DEBUG		,	"Signal %d belongs to us...", nsig);		cl_log(LOG_DEBUG, "cl_poll_prepsig(%d) succeeded.\n", nsig);	}		return 0;}#define	FD_CHUNKSIZE	64/* Set of events everyone must monitor whether they want to or not ;-) */#define	CONSTEVENTS	(POLLHUP|POLLERR|POLLNVAL)#define	RECORDFDEVENT(fd, flags) (monitorinfo[fd].pendevents |= (flags))/* * Initialized our poll-simulation data structures. * This means (among other things) registering any monitored * file descriptors. */static intcl_init_poll_sig(struct pollfd *fds, unsigned int nfds){	unsigned	j;	int		maxmonfd = -1;	int		nmatch = 0;	if (cl_nsig == 0) {		cl_nsig = ((SIGRTMIN+SIGRTMAX)/2);		if (cl_poll_setsig(cl_nsig) < 0) {			return -1;		}	}	for (j=0; j < nfds; ++j) {		const int fd = fds[j].fd;				if (fd > maxmonfd) {			maxmonfd = fd;		}	}	/* See if we need to malloc/realloc our data structures */	if (maxmonfd >= max_allocated) {		int	newsize;		int	growthamount;		newsize = ((maxmonfd + FD_CHUNKSIZE)/FD_CHUNKSIZE)		*	FD_CHUNKSIZE;		growthamount = newsize - max_allocated;		/* This can't happen ;-) */		if (growthamount <= 0 || newsize <= maxmonfd) {			errno = EINVAL;			return -1;		}		/* Allocate (more) memory! */		if ((is_monitored = (poll_bool*)realloc(is_monitored		,	newsize * sizeof(poll_bool))) == NULL		||	(monitorinfo = (poll_info_t*) realloc(monitorinfo		,	newsize * sizeof(poll_info_t))) == NULL) {			if (is_monitored) {				free(is_monitored);				is_monitored = NULL;			}			if (monitorinfo) {				free(monitorinfo);				monitorinfo = NULL;			}			max_allocated = 0;			errno = ENOMEM;			return -1;		}		memset(monitorinfo+max_allocated, 0		,	growthamount * sizeof(monitorinfo[0]));		memset(is_monitored+max_allocated, FALSE		,	growthamount*sizeof(is_monitored[0]));		max_allocated = newsize;	}	if (fds->events != 0 && debug) {		cl_log(LOG_DEBUG		,	"Current event mask for fd [0] {%d} 0x%x"		,	fds->fd, fds->events);	}	/*	 * Examine each fd for the following things:	 *	Is it already monitored?	 *		if not, set it up for monitoring.	 *	Do we have events for it?	 *		if so, post events...	 */	for (j=0; j < nfds; ++j) {		const int	fd = fds[j].fd;		poll_info_t*	moni = monitorinfo+fd;		short		nsig;		int		badfd = FALSE;		is_monitored[fd] = TRUE;		if (moni->nsig <= 0) {			nsig = cl_poll_assignsig(fd);			if (nsig < 0) {				RECORDFDEVENT(fd, POLLERR);				badfd = TRUE;			}else{				/* Use real poll(2) to get initial				 * event status				 */				moni->nsig = nsig;				cl_real_poll_fd(fd);			}		}else if (fcntl(fd, F_GETFD) < 0) {			cl_log(LOG_ERR, "bad fd(%d)", fd);			RECORDFDEVENT(fd, POLLNVAL);			badfd = TRUE;		}		/* Look for pending events... */		fds[j].revents = (moni->pendevents		&	(fds[j].events|CONSTEVENTS));		if (fds[j].revents) {			++nmatch;			moni->pendevents &= ~(fds[j].revents);			if (debug) {				cl_log(LOG_DEBUG				,	"revents for fd %d: 0x%x"				,	fds[j].fd, fds[j].revents);				cl_log(LOG_DEBUG				,	"events for fd %d: 0x%x"				,	fds[j].fd, fds[j].events);			}		}else if (fds[j].events && debug) {			cl_log(LOG_DEBUG			,	"pendevents for fd %d: 0x%x"			,	fds[j].fd, moni->pendevents);		}		if (badfd) {			cl_poll_ignore(fd);		}	}	if (nmatch != 0 && debug) {		cl_log(LOG_DEBUG, "Returning %d events from cl_init_poll_sig()"		,	nmatch);	}	return nmatch;}/* * Initialize our current state of the world with info from the * real poll(2) call. * * We call this when we first see a particular fd, and after a signal * queue overflow. */static voidcl_real_poll_fd(int fd){	struct pollfd	pfd[1];	if (fd >= max_allocated || !is_monitored[fd]) {		return;	}	if (debug) {		cl_log(LOG_DEBUG		,	"Calling poll(2) on fd %d", fd);	}	/* Get the current state of affaris from poll(2) */	pfd[0].fd = fd;	pfd[0].revents = 0;	pfd[0].events = ~0;	if (poll(pfd, 1, 0) >= 0) {		RECORDFDEVENT(fd, pfd[0].revents);		if (pfd[0].revents & (POLLNVAL|POLLERR)) {			cl_log(LOG_INFO, "cl_poll_real_fd(%d): error in revents [%d]"			,	fd, pfd[0].revents);		}		if (debug) {			cl_log(LOG_DEBUG			,	"Old news from poll(2) for fd %d: 0x%x"			,	fd, pfd[0].revents);		}	}else{		if (fcntl(fd, F_GETFL) < 0) {			cl_perror("cl_poll_real_fd(%d): F_GETFL failure"			,	fd);			RECORDFDEVENT(fd, POLLNVAL);		}else{			RECORDFDEVENT(fd, POLLERR);		}	}}/* * Assign a signal for monitoring the given file descriptor */static shortcl_poll_assignsig(int fd){	int		flags;

⌨️ 快捷键说明

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