/* * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu> * Copyright 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ #include"event2/event-config.h" #include"evconfig-private.h"
/* Since Linux 2.6.17, poll is able to report about peer half-closed connection using special POLLRDHUP flag on a read event.
*/ #if !defined(POLLRDHUP) #define POLLRDHUP 0 #define EARLY_CLOSE_IF_HAVE_RDHUP 0 #else #define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE #endif
struct pollidx { int idxplus1;
};
struct pollop { int event_count; /* Highest number alloc */ int nfds; /* Highest number used */ int realloc_copy; /* True iff we must realloc
* event_set_copy */ struct pollfd *event_set; struct pollfd *event_set_copy;
};
staticvoid *poll_init(struct event_base *); staticint poll_add(struct event_base *, int, short old, short events, void *idx); staticint poll_del(struct event_base *, int, short old, short events, void *idx); staticint poll_dispatch(struct event_base *, struct timeval *); staticvoid poll_dealloc(struct event_base *);
if (!(pollop = mm_calloc(1, sizeof(struct pollop)))) return (NULL);
evsig_init_(base);
evutil_weakrand_seed_(&base->weakrand_seed, 0);
return (pollop);
}
#ifdef CHECK_INVARIANTS staticvoid
poll_check_ok(struct pollop *pop)
{ int i, idx; struct event *ev;
for (i = 0; i < pop->fd_count; ++i) {
idx = pop->idxplus1_by_fd[i]-1; if (idx < 0) continue;
EVUTIL_ASSERT(pop->event_set[idx].fd == i);
} for (i = 0; i < pop->nfds; ++i) { struct pollfd *pfd = &pop->event_set[i];
EVUTIL_ASSERT(pop->idxplus1_by_fd[pfd->fd] == i+1);
}
} #else #define poll_check_ok(pop) #endif
staticint
poll_dispatch(struct event_base *base, struct timeval *tv)
{ int res, i, j, nfds; long msec = -1; struct pollop *pop = base->evbase; struct pollfd *event_set;
poll_check_ok(pop);
nfds = pop->nfds;
#ifndef EVENT__DISABLE_THREAD_SUPPORT if (base->th_base_lock) { /* If we're using this backend in a multithreaded setting, * then we need to work on a copy of event_set, so that we can * let other threads modify the main event_set while we're * polling. If we're not multithreaded, then we'll skip the
* copy step here to save memory and time. */ if (pop->realloc_copy) { struct pollfd *tmp = mm_realloc(pop->event_set_copy,
pop->event_count * sizeof(struct pollfd)); if (tmp == NULL) {
event_warn("realloc"); return -1;
}
pop->event_set_copy = tmp;
pop->realloc_copy = 0;
}
memcpy(pop->event_set_copy, pop->event_set, sizeof(struct pollfd)*nfds);
event_set = pop->event_set_copy;
} else {
event_set = pop->event_set;
} #else
event_set = pop->event_set; #endif
if (tv != NULL) {
msec = evutil_tv_to_msec_(tv); if (msec < 0 || msec > INT_MAX)
msec = INT_MAX;
}
EVBASE_RELEASE_LOCK(base, th_base_lock);
res = poll(event_set, nfds, msec);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
if (res == -1) { if (errno != EINTR) {
event_warn("poll"); return (-1);
}
i = evutil_weakrand_range_(&base->weakrand_seed, nfds); for (j = 0; j < nfds; j++) { int what; if (++i == nfds)
i = 0;
what = event_set[i].revents; if (!what) continue;
res = 0;
/* If the file gets closed notify */ if (what & (POLLHUP|POLLERR|POLLNVAL))
what |= POLLIN|POLLOUT; if (what & POLLIN)
res |= EV_READ; if (what & POLLOUT)
res |= EV_WRITE; if (what & POLLRDHUP)
res |= EV_CLOSED; if (res == 0) continue;
evmap_io_active_(base, event_set[i].fd, res);
}
return (0);
}
staticint
poll_add(struct event_base *base, int fd, short old, short events, void *idx_)
{ struct pollop *pop = base->evbase; struct pollfd *pfd = NULL; struct pollidx *idx = idx_; int i;
poll_check_ok(pop);
i = idx->idxplus1 - 1; if (i < 0) return (-1);
/* Do we still want to read or write? */
pfd = &pop->event_set[i]; if (events & EV_READ)
pfd->events &= ~POLLIN; if (events & EV_WRITE)
pfd->events &= ~POLLOUT; if (events & EV_CLOSED)
pfd->events &= ~POLLRDHUP;
poll_check_ok(pop); if (pfd->events) /* Another event cares about that fd. */ return (0);
/* Okay, so we aren't interested in that fd anymore. */
idx->idxplus1 = 0;
--pop->nfds; if (i != pop->nfds) { /* * Shift the last pollfd down into the now-unoccupied * position.
*/
memcpy(&pop->event_set[i], &pop->event_set[pop->nfds], sizeof(struct pollfd));
idx = evmap_io_get_fdinfo_(&base->io, pop->event_set[i].fd);
EVUTIL_ASSERT(idx);
EVUTIL_ASSERT(idx->idxplus1 == pop->nfds + 1);
idx->idxplus1 = i + 1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.