File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libevent / poll.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:02:54 2012 UTC (12 years, 4 months ago) by misho
Branches: libevent, MAIN
CVS tags: v1_4_14bp0, v1_4_14b, HEAD
libevent

    1: /*	$OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
    2: 
    3: /*
    4:  * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
    5:  * All rights reserved.
    6:  *
    7:  * Redistribution and use in source and binary forms, with or without
    8:  * modification, are permitted provided that the following conditions
    9:  * are met:
   10:  * 1. Redistributions of source code must retain the above copyright
   11:  *    notice, this list of conditions and the following disclaimer.
   12:  * 2. Redistributions in binary form must reproduce the above copyright
   13:  *    notice, this list of conditions and the following disclaimer in the
   14:  *    documentation and/or other materials provided with the distribution.
   15:  * 3. The name of the author may not be used to endorse or promote products
   16:  *    derived from this software without specific prior written permission.
   17:  *
   18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28:  */
   29: #ifdef HAVE_CONFIG_H
   30: #include "config.h"
   31: #endif
   32: 
   33: #include <sys/types.h>
   34: #ifdef HAVE_SYS_TIME_H
   35: #include <sys/time.h>
   36: #else
   37: #include <sys/_libevent_time.h>
   38: #endif
   39: #include <sys/queue.h>
   40: #include <poll.h>
   41: #include <signal.h>
   42: #include <stdio.h>
   43: #include <stdlib.h>
   44: #include <string.h>
   45: #include <unistd.h>
   46: #include <errno.h>
   47: #ifdef CHECK_INVARIANTS
   48: #include <assert.h>
   49: #endif
   50: 
   51: #include "event.h"
   52: #include "event-internal.h"
   53: #include "evsignal.h"
   54: #include "log.h"
   55: 
   56: struct pollop {
   57: 	int event_count;		/* Highest number alloc */
   58: 	int nfds;                       /* Size of event_* */
   59: 	int fd_count;                   /* Size of idxplus1_by_fd */
   60: 	struct pollfd *event_set;
   61: 	struct event **event_r_back;
   62: 	struct event **event_w_back;
   63: 	int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
   64: 			      * that 0 (which is easy to memset) can mean
   65: 			      * "no entry." */
   66: };
   67: 
   68: static void *poll_init	(struct event_base *);
   69: static int poll_add		(void *, struct event *);
   70: static int poll_del		(void *, struct event *);
   71: static int poll_dispatch	(struct event_base *, void *, struct timeval *);
   72: static void poll_dealloc	(struct event_base *, void *);
   73: 
   74: const struct eventop pollops = {
   75: 	"poll",
   76: 	poll_init,
   77: 	poll_add,
   78: 	poll_del,
   79: 	poll_dispatch,
   80: 	poll_dealloc,
   81:     0
   82: };
   83: 
   84: static void *
   85: poll_init(struct event_base *base)
   86: {
   87: 	struct pollop *pollop;
   88: 
   89: 	/* Disable poll when this environment variable is set */
   90: 	if (evutil_getenv("EVENT_NOPOLL"))
   91: 		return (NULL);
   92: 
   93: 	if (!(pollop = calloc(1, sizeof(struct pollop))))
   94: 		return (NULL);
   95: 
   96: 	evsignal_init(base);
   97: 
   98: 	return (pollop);
   99: }
  100: 
  101: #ifdef CHECK_INVARIANTS
  102: static void
  103: poll_check_ok(struct pollop *pop)
  104: {
  105: 	int i, idx;
  106: 	struct event *ev;
  107: 
  108: 	for (i = 0; i < pop->fd_count; ++i) {
  109: 		idx = pop->idxplus1_by_fd[i]-1;
  110: 		if (idx < 0)
  111: 			continue;
  112: 		assert(pop->event_set[idx].fd == i);
  113: 		if (pop->event_set[idx].events & POLLIN) {
  114: 			ev = pop->event_r_back[idx];
  115: 			assert(ev);
  116: 			assert(ev->ev_events & EV_READ);
  117: 			assert(ev->ev_fd == i);
  118: 		}
  119: 		if (pop->event_set[idx].events & POLLOUT) {
  120: 			ev = pop->event_w_back[idx];
  121: 			assert(ev);
  122: 			assert(ev->ev_events & EV_WRITE);
  123: 			assert(ev->ev_fd == i);
  124: 		}
  125: 	}
  126: 	for (i = 0; i < pop->nfds; ++i) {
  127: 		struct pollfd *pfd = &pop->event_set[i];
  128: 		assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
  129: 	}
  130: }
  131: #else
  132: #define poll_check_ok(pop)
  133: #endif
  134: 
  135: static int
  136: poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
  137: {
  138: 	int res, i, j, msec = -1, nfds;
  139: 	struct pollop *pop = arg;
  140: 
  141: 	poll_check_ok(pop);
  142: 
  143: 	if (tv != NULL)
  144: 		msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
  145: 
  146: 	nfds = pop->nfds;
  147: 	res = poll(pop->event_set, nfds, msec);
  148: 
  149: 	if (res == -1) {
  150: 		if (errno != EINTR) {
  151:                         event_warn("poll");
  152: 			return (-1);
  153: 		}
  154: 
  155: 		evsignal_process(base);
  156: 		return (0);
  157: 	} else if (base->sig.evsignal_caught) {
  158: 		evsignal_process(base);
  159: 	}
  160: 
  161: 	event_debug(("%s: poll reports %d", __func__, res));
  162: 
  163: 	if (res == 0 || nfds == 0)
  164: 		return (0);
  165: 
  166: 	i = random() % nfds;
  167: 	for (j = 0; j < nfds; j++) {
  168: 		struct event *r_ev = NULL, *w_ev = NULL;
  169: 		int what;
  170: 		if (++i == nfds)
  171: 			i = 0;
  172: 		what = pop->event_set[i].revents;
  173: 
  174: 		if (!what)
  175: 			continue;
  176: 
  177: 		res = 0;
  178: 
  179: 		/* If the file gets closed notify */
  180: 		if (what & (POLLHUP|POLLERR))
  181: 			what |= POLLIN|POLLOUT;
  182: 		if (what & POLLIN) {
  183: 			res |= EV_READ;
  184: 			r_ev = pop->event_r_back[i];
  185: 		}
  186: 		if (what & POLLOUT) {
  187: 			res |= EV_WRITE;
  188: 			w_ev = pop->event_w_back[i];
  189: 		}
  190: 		if (res == 0)
  191: 			continue;
  192: 
  193: 		if (r_ev && (res & r_ev->ev_events)) {
  194: 			event_active(r_ev, res & r_ev->ev_events, 1);
  195: 		}
  196: 		if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
  197: 			event_active(w_ev, res & w_ev->ev_events, 1);
  198: 		}
  199: 	}
  200: 
  201: 	return (0);
  202: }
  203: 
  204: static int
  205: poll_add(void *arg, struct event *ev)
  206: {
  207: 	struct pollop *pop = arg;
  208: 	struct pollfd *pfd = NULL;
  209: 	int i;
  210: 
  211: 	if (ev->ev_events & EV_SIGNAL)
  212: 		return (evsignal_add(ev));
  213: 	if (!(ev->ev_events & (EV_READ|EV_WRITE)))
  214: 		return (0);
  215: 
  216: 	poll_check_ok(pop);
  217: 	if (pop->nfds + 1 >= pop->event_count) {
  218: 		struct pollfd *tmp_event_set;
  219: 		struct event **tmp_event_r_back;
  220: 		struct event **tmp_event_w_back;
  221: 		int tmp_event_count;
  222: 
  223: 		if (pop->event_count < 32)
  224: 			tmp_event_count = 32;
  225: 		else
  226: 			tmp_event_count = pop->event_count * 2;
  227: 
  228: 		/* We need more file descriptors */
  229: 		tmp_event_set = realloc(pop->event_set,
  230: 				 tmp_event_count * sizeof(struct pollfd));
  231: 		if (tmp_event_set == NULL) {
  232: 			event_warn("realloc");
  233: 			return (-1);
  234: 		}
  235: 		pop->event_set = tmp_event_set;
  236: 
  237: 		tmp_event_r_back = realloc(pop->event_r_back,
  238: 			    tmp_event_count * sizeof(struct event *));
  239: 		if (tmp_event_r_back == NULL) {
  240: 			/* event_set overallocated; that's okay. */
  241: 			event_warn("realloc");
  242: 			return (-1);
  243: 		}
  244: 		pop->event_r_back = tmp_event_r_back;
  245: 
  246: 		tmp_event_w_back = realloc(pop->event_w_back,
  247: 			    tmp_event_count * sizeof(struct event *));
  248: 		if (tmp_event_w_back == NULL) {
  249: 			/* event_set and event_r_back overallocated; that's
  250: 			 * okay. */
  251: 			event_warn("realloc");
  252: 			return (-1);
  253: 		}
  254: 		pop->event_w_back = tmp_event_w_back;
  255: 
  256: 		pop->event_count = tmp_event_count;
  257: 	}
  258: 	if (ev->ev_fd >= pop->fd_count) {
  259: 		int *tmp_idxplus1_by_fd;
  260: 		int new_count;
  261: 		if (pop->fd_count < 32)
  262: 			new_count = 32;
  263: 		else
  264: 			new_count = pop->fd_count * 2;
  265: 		while (new_count <= ev->ev_fd)
  266: 			new_count *= 2;
  267: 		tmp_idxplus1_by_fd =
  268: 			realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
  269: 		if (tmp_idxplus1_by_fd == NULL) {
  270: 			event_warn("realloc");
  271: 			return (-1);
  272: 		}
  273: 		pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
  274: 		memset(pop->idxplus1_by_fd + pop->fd_count,
  275: 		       0, sizeof(int)*(new_count - pop->fd_count));
  276: 		pop->fd_count = new_count;
  277: 	}
  278: 
  279: 	i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
  280: 	if (i >= 0) {
  281: 		pfd = &pop->event_set[i];
  282: 	} else {
  283: 		i = pop->nfds++;
  284: 		pfd = &pop->event_set[i];
  285: 		pfd->events = 0;
  286: 		pfd->fd = ev->ev_fd;
  287: 		pop->event_w_back[i] = pop->event_r_back[i] = NULL;
  288: 		pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
  289: 	}
  290: 
  291: 	pfd->revents = 0;
  292: 	if (ev->ev_events & EV_WRITE) {
  293: 		pfd->events |= POLLOUT;
  294: 		pop->event_w_back[i] = ev;
  295: 	}
  296: 	if (ev->ev_events & EV_READ) {
  297: 		pfd->events |= POLLIN;
  298: 		pop->event_r_back[i] = ev;
  299: 	}
  300: 	poll_check_ok(pop);
  301: 
  302: 	return (0);
  303: }
  304: 
  305: /*
  306:  * Nothing to be done here.
  307:  */
  308: 
  309: static int
  310: poll_del(void *arg, struct event *ev)
  311: {
  312: 	struct pollop *pop = arg;
  313: 	struct pollfd *pfd = NULL;
  314: 	int i;
  315: 
  316: 	if (ev->ev_events & EV_SIGNAL)
  317: 		return (evsignal_del(ev));
  318: 
  319: 	if (!(ev->ev_events & (EV_READ|EV_WRITE)))
  320: 		return (0);
  321: 
  322: 	poll_check_ok(pop);
  323: 	i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
  324: 	if (i < 0)
  325: 		return (-1);
  326: 
  327: 	/* Do we still want to read or write? */
  328: 	pfd = &pop->event_set[i];
  329: 	if (ev->ev_events & EV_READ) {
  330: 		pfd->events &= ~POLLIN;
  331: 		pop->event_r_back[i] = NULL;
  332: 	}
  333: 	if (ev->ev_events & EV_WRITE) {
  334: 		pfd->events &= ~POLLOUT;
  335: 		pop->event_w_back[i] = NULL;
  336: 	}
  337: 	poll_check_ok(pop);
  338: 	if (pfd->events)
  339: 		/* Another event cares about that fd. */
  340: 		return (0);
  341: 
  342: 	/* Okay, so we aren't interested in that fd anymore. */
  343: 	pop->idxplus1_by_fd[ev->ev_fd] = 0;
  344: 
  345: 	--pop->nfds;
  346: 	if (i != pop->nfds) {
  347: 		/* 
  348: 		 * Shift the last pollfd down into the now-unoccupied
  349: 		 * position.
  350: 		 */
  351: 		memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
  352: 		       sizeof(struct pollfd));
  353: 		pop->event_r_back[i] = pop->event_r_back[pop->nfds];
  354: 		pop->event_w_back[i] = pop->event_w_back[pop->nfds];
  355: 		pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
  356: 	}
  357: 
  358: 	poll_check_ok(pop);
  359: 	return (0);
  360: }
  361: 
  362: static void
  363: poll_dealloc(struct event_base *base, void *arg)
  364: {
  365: 	struct pollop *pop = arg;
  366: 
  367: 	evsignal_dealloc(base);
  368: 	if (pop->event_set)
  369: 		free(pop->event_set);
  370: 	if (pop->event_r_back)
  371: 		free(pop->event_r_back);
  372: 	if (pop->event_w_back)
  373: 		free(pop->event_w_back);
  374: 	if (pop->idxplus1_by_fd)
  375: 		free(pop->idxplus1_by_fd);
  376: 
  377: 	memset(pop, 0, sizeof(struct pollop));
  378: 	free(pop);
  379: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>