ipc/chromium/src/third_party/libevent/poll.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*	$OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
     3 /*
     4  * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
     5  * Copyright 2007-2012 Niels Provos and Nick Mathewson
     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 #include "event2/event-config.h"
    31 #include <sys/types.h>
    32 #ifdef _EVENT_HAVE_SYS_TIME_H
    33 #include <sys/time.h>
    34 #endif
    35 #include <sys/queue.h>
    36 #include <poll.h>
    37 #include <signal.h>
    38 #include <limits.h>
    39 #include <stdio.h>
    40 #include <stdlib.h>
    41 #include <string.h>
    42 #include <unistd.h>
    43 #include <errno.h>
    45 #include "event-internal.h"
    46 #include "evsignal-internal.h"
    47 #include "log-internal.h"
    48 #include "evmap-internal.h"
    49 #include "event2/thread.h"
    50 #include "evthread-internal.h"
    52 struct pollidx {
    53 	int idxplus1;
    54 };
    56 struct pollop {
    57 	int event_count;		/* Highest number alloc */
    58 	int nfds;			/* Highest number used */
    59 	int realloc_copy;		/* True iff we must realloc
    60 					 * event_set_copy */
    61 	struct pollfd *event_set;
    62 	struct pollfd *event_set_copy;
    63 };
    65 static void *poll_init(struct event_base *);
    66 static int poll_add(struct event_base *, int, short old, short events, void *_idx);
    67 static int poll_del(struct event_base *, int, short old, short events, void *_idx);
    68 static int poll_dispatch(struct event_base *, struct timeval *);
    69 static void poll_dealloc(struct event_base *);
    71 const struct eventop pollops = {
    72 	"poll",
    73 	poll_init,
    74 	poll_add,
    75 	poll_del,
    76 	poll_dispatch,
    77 	poll_dealloc,
    78 	0, /* doesn't need_reinit */
    79 	EV_FEATURE_FDS,
    80 	sizeof(struct pollidx),
    81 };
    83 static void *
    84 poll_init(struct event_base *base)
    85 {
    86 	struct pollop *pollop;
    88 	if (!(pollop = mm_calloc(1, sizeof(struct pollop))))
    89 		return (NULL);
    91 	evsig_init(base);
    93 	return (pollop);
    94 }
    96 #ifdef CHECK_INVARIANTS
    97 static void
    98 poll_check_ok(struct pollop *pop)
    99 {
   100 	int i, idx;
   101 	struct event *ev;
   103 	for (i = 0; i < pop->fd_count; ++i) {
   104 		idx = pop->idxplus1_by_fd[i]-1;
   105 		if (idx < 0)
   106 			continue;
   107 		EVUTIL_ASSERT(pop->event_set[idx].fd == i);
   108 	}
   109 	for (i = 0; i < pop->nfds; ++i) {
   110 		struct pollfd *pfd = &pop->event_set[i];
   111 		EVUTIL_ASSERT(pop->idxplus1_by_fd[pfd->fd] == i+1);
   112 	}
   113 }
   114 #else
   115 #define poll_check_ok(pop)
   116 #endif
   118 static int
   119 poll_dispatch(struct event_base *base, struct timeval *tv)
   120 {
   121 	int res, i, j, nfds;
   122 	long msec = -1;
   123 	struct pollop *pop = base->evbase;
   124 	struct pollfd *event_set;
   126 	poll_check_ok(pop);
   128 	nfds = pop->nfds;
   130 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
   131 	if (base->th_base_lock) {
   132 		/* If we're using this backend in a multithreaded setting,
   133 		 * then we need to work on a copy of event_set, so that we can
   134 		 * let other threads modify the main event_set while we're
   135 		 * polling. If we're not multithreaded, then we'll skip the
   136 		 * copy step here to save memory and time. */
   137 		if (pop->realloc_copy) {
   138 			struct pollfd *tmp = mm_realloc(pop->event_set_copy,
   139 			    pop->event_count * sizeof(struct pollfd));
   140 			if (tmp == NULL) {
   141 				event_warn("realloc");
   142 				return -1;
   143 			}
   144 			pop->event_set_copy = tmp;
   145 			pop->realloc_copy = 0;
   146 		}
   147 		memcpy(pop->event_set_copy, pop->event_set,
   148 		    sizeof(struct pollfd)*nfds);
   149 		event_set = pop->event_set_copy;
   150 	} else {
   151 		event_set = pop->event_set;
   152 	}
   153 #else
   154 	event_set = pop->event_set;
   155 #endif
   157 	if (tv != NULL) {
   158 		msec = evutil_tv_to_msec(tv);
   159 		if (msec < 0 || msec > INT_MAX)
   160 			msec = INT_MAX;
   161 	}
   163 	EVBASE_RELEASE_LOCK(base, th_base_lock);
   165 	res = poll(event_set, nfds, msec);
   167 	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
   169 	if (res == -1) {
   170 		if (errno != EINTR) {
   171 			event_warn("poll");
   172 			return (-1);
   173 		}
   175 		return (0);
   176 	}
   178 	event_debug(("%s: poll reports %d", __func__, res));
   180 	if (res == 0 || nfds == 0)
   181 		return (0);
   183 	i = random() % nfds;
   184 	for (j = 0; j < nfds; j++) {
   185 		int what;
   186 		if (++i == nfds)
   187 			i = 0;
   188 		what = event_set[i].revents;
   189 		if (!what)
   190 			continue;
   192 		res = 0;
   194 		/* If the file gets closed notify */
   195 		if (what & (POLLHUP|POLLERR))
   196 			what |= POLLIN|POLLOUT;
   197 		if (what & POLLIN)
   198 			res |= EV_READ;
   199 		if (what & POLLOUT)
   200 			res |= EV_WRITE;
   201 		if (res == 0)
   202 			continue;
   204 		evmap_io_active(base, event_set[i].fd, res);
   205 	}
   207 	return (0);
   208 }
   210 static int
   211 poll_add(struct event_base *base, int fd, short old, short events, void *_idx)
   212 {
   213 	struct pollop *pop = base->evbase;
   214 	struct pollfd *pfd = NULL;
   215 	struct pollidx *idx = _idx;
   216 	int i;
   218 	EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
   219 	if (!(events & (EV_READ|EV_WRITE)))
   220 		return (0);
   222 	poll_check_ok(pop);
   223 	if (pop->nfds + 1 >= pop->event_count) {
   224 		struct pollfd *tmp_event_set;
   225 		int tmp_event_count;
   227 		if (pop->event_count < 32)
   228 			tmp_event_count = 32;
   229 		else
   230 			tmp_event_count = pop->event_count * 2;
   232 		/* We need more file descriptors */
   233 		tmp_event_set = mm_realloc(pop->event_set,
   234 				 tmp_event_count * sizeof(struct pollfd));
   235 		if (tmp_event_set == NULL) {
   236 			event_warn("realloc");
   237 			return (-1);
   238 		}
   239 		pop->event_set = tmp_event_set;
   241 		pop->event_count = tmp_event_count;
   242 		pop->realloc_copy = 1;
   243 	}
   245 	i = idx->idxplus1 - 1;
   247 	if (i >= 0) {
   248 		pfd = &pop->event_set[i];
   249 	} else {
   250 		i = pop->nfds++;
   251 		pfd = &pop->event_set[i];
   252 		pfd->events = 0;
   253 		pfd->fd = fd;
   254 		idx->idxplus1 = i + 1;
   255 	}
   257 	pfd->revents = 0;
   258 	if (events & EV_WRITE)
   259 		pfd->events |= POLLOUT;
   260 	if (events & EV_READ)
   261 		pfd->events |= POLLIN;
   262 	poll_check_ok(pop);
   264 	return (0);
   265 }
   267 /*
   268  * Nothing to be done here.
   269  */
   271 static int
   272 poll_del(struct event_base *base, int fd, short old, short events, void *_idx)
   273 {
   274 	struct pollop *pop = base->evbase;
   275 	struct pollfd *pfd = NULL;
   276 	struct pollidx *idx = _idx;
   277 	int i;
   279 	EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
   280 	if (!(events & (EV_READ|EV_WRITE)))
   281 		return (0);
   283 	poll_check_ok(pop);
   284 	i = idx->idxplus1 - 1;
   285 	if (i < 0)
   286 		return (-1);
   288 	/* Do we still want to read or write? */
   289 	pfd = &pop->event_set[i];
   290 	if (events & EV_READ)
   291 		pfd->events &= ~POLLIN;
   292 	if (events & EV_WRITE)
   293 		pfd->events &= ~POLLOUT;
   294 	poll_check_ok(pop);
   295 	if (pfd->events)
   296 		/* Another event cares about that fd. */
   297 		return (0);
   299 	/* Okay, so we aren't interested in that fd anymore. */
   300 	idx->idxplus1 = 0;
   302 	--pop->nfds;
   303 	if (i != pop->nfds) {
   304 		/*
   305 		 * Shift the last pollfd down into the now-unoccupied
   306 		 * position.
   307 		 */
   308 		memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
   309 		       sizeof(struct pollfd));
   310 		idx = evmap_io_get_fdinfo(&base->io, pop->event_set[i].fd);
   311 		EVUTIL_ASSERT(idx);
   312 		EVUTIL_ASSERT(idx->idxplus1 == pop->nfds + 1);
   313 		idx->idxplus1 = i + 1;
   314 	}
   316 	poll_check_ok(pop);
   317 	return (0);
   318 }
   320 static void
   321 poll_dealloc(struct event_base *base)
   322 {
   323 	struct pollop *pop = base->evbase;
   325 	evsig_dealloc(base);
   326 	if (pop->event_set)
   327 		mm_free(pop->event_set);
   328 	if (pop->event_set_copy)
   329 		mm_free(pop->event_set_copy);
   331 	memset(pop, 0, sizeof(struct pollop));
   332 	mm_free(pop);
   333 }

mercurial