From b3d1c6a854e10d00bd79403ccd2f1b6790512f81 Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Fri, 28 Feb 2003 22:38:30 +0000 Subject: [PATCH] support poll(2) and split out the signal handling svn:r37 --- configure.in | 52 ++++++++--- event.c | 6 ++ poll.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++ select.c | 102 ++++----------------- signal.c | 165 ++++++++++++++++++++++++++++++++++ 5 files changed, 472 insertions(+), 96 deletions(-) create mode 100644 poll.c create mode 100644 signal.c diff --git a/configure.in b/configure.in index 661f8076..025ae34a 100644 --- a/configure.in +++ b/configure.in @@ -20,7 +20,7 @@ dnl Checks for libraries. dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(unistd.h sys/time.h sys/queue.h sys/event.h) +AC_CHECK_HEADERS(poll.h signal.h unistd.h sys/time.h sys/queue.h sys/event.h) if test "x$ac_cv_header_sys_queue_h" = "xyes"; then AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_EGREP_CPP(yes, @@ -30,7 +30,9 @@ if test "x$ac_cv_header_sys_queue_h" = "xyes"; then yes #endif ], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_TAILQFOREACH) ], AC_MSG_RESULT(no) + AC_DEFINE(HAVE_TAILQFOREACH, 1, + [Define if TAILQ_FOREACH is defined in ])], + AC_MSG_RESULT(no) ) fi @@ -42,7 +44,8 @@ if test "x$ac_cv_header_sys_time_h" = "xyes"; then #ifdef timeradd yes #endif -], [ AC_DEFINE(HAVE_TIMERADD) +], [ AC_DEFINE(HAVE_TIMERADD, 1, + [Define if timeradd is defined in ]) AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) ) fi @@ -53,19 +56,27 @@ AC_HEADER_TIME dnl Checks for library functions. AC_CHECK_FUNCS(gettimeofday) -AC_SUBST(LIBOBJS) +needsignal=no haveselect=no AC_CHECK_FUNCS(select, [haveselect=yes], ) if test "x$haveselect" = "xyes" ; then - LIBOBJS="$LIBOBJS select.o" + AC_LIBOBJ([select]) + needsignal=yes fi -neederr=no -AC_CHECK_FUNCS(warnx, , [neederr=yes]) -if test $neederr = yes; then - LIBOBJS="$LIBOBJS err.o" +havepoll=no +AC_CHECK_FUNCS(poll, [havepoll=yes], ) +if test "x$havepoll" = "xyes" ; then + AC_LIBOBJ([poll]) + needsignal=yes fi +if test "x$needsignal" = "xyes" ; then + AC_LIBOBJ([signal]) +fi + +AC_REPLACE_FUNCS(err) + havekqueue=no if test "x$ac_cv_header_sys_event_h" = "xyes"; then AC_CHECK_FUNCS(kqueue, [havekqueue=yes], ) @@ -117,9 +128,28 @@ main(int argc, char **argv) exit(0); }, [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_WORKING_KQUEUE) - LIBOBJS="$LIBOBJS kqueue.o"], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) + AC_DEFINE(HAVE_WORKING_KQUEUE, 1, + [Define if kqueue works correctly with pipes]) + AC_LIBOBJ([kqueue])], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) fi fi +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_CHECK_TYPE(u_int64_t, unsigned long long) +AC_CHECK_TYPE(u_int32_t, unsigned int) +AC_CHECK_TYPE(u_int16_t, unsigned short) +AC_CHECK_TYPE(u_int8_t, unsigned char) + +AC_MSG_CHECKING([for socklen_t]) +AC_TRY_COMPILE([ + #include + #include ], + [socklen_t x;], + AC_MSG_RESULT([yes]), + [AC_MSG_RESULT([no]) + AC_DEFINE(socklen_t, unsigned int, + [Define to unsigned int if you dont have it])] +) + AC_OUTPUT(Makefile test/Makefile sample/Makefile) diff --git a/event.c b/event.c index 30db339c..f657028b 100644 --- a/event.c +++ b/event.c @@ -59,6 +59,9 @@ #ifdef HAVE_SELECT extern struct eventop selectops; #endif +#ifdef HAVE_POLL +extern struct eventop pollops; +#endif #ifdef HAVE_WORKING_KQUEUE extern struct eventop kqops; #endif @@ -68,6 +71,9 @@ struct eventop *eventops[] = { #ifdef HAVE_WORKING_KQUEUE &kqops, #endif +#ifdef HAVE_POLL + &pollops, +#endif #ifdef HAVE_SELECT &selectops, #endif diff --git a/poll.c b/poll.c new file mode 100644 index 00000000..f84d3553 --- /dev/null +++ b/poll.c @@ -0,0 +1,243 @@ +/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ + +/* + * Copyright 2000-2003 Niels Provos + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Niels Provos. + * 4. 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 "config.h" + +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_LOG +#include "log.h" +#else +#define LOG_DBG(x) +#define log_error(x) perror(x) +#endif + +#include "event.h" + +extern struct event_list eventqueue; + +extern volatile sig_atomic_t evsignal_caught; + +struct pollop { + int event_count; /* Highest number alloc */ + struct pollfd *event_set; + struct event **event_back; + sigset_t evsigmask; +} pop; + +void evsignal_init(sigset_t *); +void evsignal_process(void); +int evsignal_recalc(sigset_t *); +int evsignal_deliver(void); +int evsignal_add(sigset_t *, struct event *); +int evsignal_del(sigset_t *, struct event *); + +void *poll_init (void); +int poll_add (void *, struct event *); +int poll_del (void *, struct event *); +int poll_recalc (void *, int); +int poll_dispatch (void *, struct timeval *); + +struct eventop pollops = { + "poll", + poll_init, + poll_add, + poll_del, + poll_recalc, + poll_dispatch +}; + +void * +poll_init(void) +{ + memset(&pop, 0, sizeof(pop)); + + evsignal_init(&pop.evsigmask); + + return (&pop); +} + +/* + * Called with the highest fd that we know about. If it is 0, completely + * recalculate everything. + */ + +int +poll_recalc(void *arg, int max) +{ + struct pollop *pop = arg; + + return (evsignal_recalc(&pop->evsigmask)); +} + +int +poll_dispatch(void *arg, struct timeval *tv) +{ + int res, i, count, sec, nfds; + struct event *ev, *next; + struct pollop *pop = arg; + + count = pop->event_count; + nfds = 0; + TAILQ_FOREACH(ev, &eventqueue, ev_next) { + if (nfds + 1 >= count) { + if (count < 32) + count = 32; + else + count *= 2; + + /* We need more file descriptors */ + pop->event_set = realloc(pop->event_set, + count * sizeof(struct pollfd)); + if (pop->event_set == NULL) { + log_error("realloc"); + return (-1); + } + pop->event_back = realloc(pop->event_back, + count * sizeof(struct event *)); + if (pop->event_back == NULL) { + log_error("realloc"); + return (-1); + } + pop->event_count = count; + } + if (ev->ev_events & EV_WRITE) { + struct pollfd *pfd = &pop->event_set[nfds]; + pfd->fd = ev->ev_fd; + pfd->events = POLLOUT; + pfd->revents = 0; + + pop->event_back[nfds] = ev; + + nfds++; + } + if (ev->ev_events & EV_READ) { + struct pollfd *pfd = &pop->event_set[nfds]; + + pfd->fd = ev->ev_fd; + pfd->events = POLLIN; + pfd->revents = 0; + + pop->event_back[nfds] = ev; + + nfds++; + } + } + + if (evsignal_deliver() == -1) + return (-1); + + sec = tv->tv_sec * 1000 + tv->tv_usec / 1000; + res = poll(pop->event_set, nfds, sec); + + if (evsignal_recalc(&pop->evsigmask) == -1) + return (-1); + + if (res == -1) { + if (errno != EINTR) { + log_error("poll"); + return (-1); + } + + evsignal_process(); + return (0); + } else if (evsignal_caught) + evsignal_process(); + + LOG_DBG((LOG_MISC, 80, __FUNCTION__": poll reports %d", + res)); + + if (res == 0) + return (0); + + for (i = 0; i < nfds; i++) { + res = 0; + if (pop->event_set[i].revents & POLLIN) + res = EV_READ; + else if (pop->event_set[i].revents & POLLOUT) + res = EV_WRITE; + if (res == 0) + continue; + + ev = pop->event_back[i]; + res &= ev->ev_events; + + if (res) { + if (!(ev->ev_events & EV_PERSIST)) + event_del(ev); + event_active(ev, res, 1); + } + } + + return (0); +} + +int +poll_add(void *arg, struct event *ev) +{ + struct pollop *pop = arg; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_add(&pop->evsigmask, ev)); + + return (0); +} + +/* + * Nothing to be done here. + */ + +int +poll_del(void *arg, struct event *ev) +{ + struct pollop *pop = arg; + + int signal; + + if (!(ev->ev_events & EV_SIGNAL)) + return (0); + + return (evsignal_del(&pop->evsigmask, ev)); +} diff --git a/select.c b/select.c index 138a3ace..bed15624 100644 --- a/select.c +++ b/select.c @@ -55,16 +55,13 @@ #include "event.h" -extern struct event_list timequeue; extern struct event_list eventqueue; -extern struct event_list signalqueue; #ifndef howmany #define howmany(x, y) (((x)+((y)-1))/(y)) #endif -short evsigcaught[NSIG]; -volatile sig_atomic_t signal_caught = 0; +extern volatile sig_atomic_t evsignal_caught; struct selectop { int event_fds; /* Highest fd in fd set */ @@ -74,9 +71,12 @@ struct selectop { sigset_t evsigmask; } sop; -void signal_process(void); -int signal_recalc(void); -int signal_deliver(void); +void evsignal_init(sigset_t *); +void evsignal_process(void); +int evsignal_recalc(void); +int evsignal_deliver(void); +int evsignal_add(sigset_t *, struct event *); +int evsignal_del(sigset_t *, struct event *); void *select_init (void); int select_add (void *, struct event *); @@ -98,7 +98,7 @@ select_init(void) { memset(&sop, 0, sizeof(sop)); - sigemptyset(&sop.evsigmask); + evsignal_init(&sop.evsigmask); return (&sop); } @@ -148,7 +148,7 @@ select_recalc(void *arg, int max) sop->event_fdsz = fdsz; } - return (signal_recalc()); + return (evsignal_recalc()); } int @@ -168,13 +168,13 @@ select_dispatch(void *arg, struct timeval *tv) FD_SET(ev->ev_fd, sop->event_readset); } - if (signal_deliver() == -1) + if (evsignal_deliver() == -1) return (-1); res = select(sop->event_fds + 1, sop->event_readset, sop->event_writeset, NULL, tv); - if (signal_recalc() == -1) + if (evsignal_recalc() == -1) return (-1); if (res == -1) { @@ -183,10 +183,10 @@ select_dispatch(void *arg, struct timeval *tv) return (-1); } - signal_process(); + evsignal_process(); return (0); - } else if (signal_caught) - signal_process(); + } else if (evsignal_caught) + evsignal_process(); LOG_DBG((LOG_MISC, 80, __FUNCTION__": select reports %d", res)); @@ -220,17 +220,8 @@ select_add(void *arg, struct event *ev) { struct selectop *sop = arg; - if (ev->ev_events & EV_SIGNAL) { - int signal; - - if (ev->ev_events & (EV_READ|EV_WRITE)) - errx(1, "%s: EV_SIGNAL incompatible use", - __FUNCTION__); - signal = EVENT_SIGNAL(ev); - sigaddset(&sop->evsigmask, signal); - - return (0); - } + if (ev->ev_events & EV_SIGNAL) + return (evsignal_add(&sop->evsigmask, ev)); /* * Keep track of the highest fd, so that we can calculate the size @@ -256,64 +247,5 @@ select_del(void *arg, struct event *ev) if (!(ev->ev_events & EV_SIGNAL)) return (0); - signal = EVENT_SIGNAL(ev); - sigdelset(&sop->evsigmask, signal); - - return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL)); + return (evsignal_del(&sop->evsigmask, ev)); } - -static void -signal_handler(int sig) -{ - evsigcaught[sig]++; - signal_caught = 1; -} - -int -signal_recalc(void) -{ - struct sigaction sa; - struct event *ev; - - if (sigprocmask(SIG_BLOCK, &sop.evsigmask, NULL) == -1) - return (-1); - - /* Reinstall our signal handler. */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_handler; - sa.sa_mask = sop.evsigmask; - sa.sa_flags |= SA_RESTART; - - TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { - if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1) - return (-1); - } - return (0); -} - -int -signal_deliver(void) -{ - return (sigprocmask(SIG_UNBLOCK, &sop.evsigmask, NULL)); - /* XXX - pending signals handled here */ -} - -void -signal_process(void) -{ - struct event *ev; - short ncalls; - - TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { - ncalls = evsigcaught[EVENT_SIGNAL(ev)]; - if (ncalls) { - if (!(ev->ev_events & EV_PERSIST)) - event_del(ev); - event_active(ev, EV_SIGNAL, ncalls); - } - } - - memset(evsigcaught, 0, sizeof(evsigcaught)); - signal_caught = 0; -} - diff --git a/signal.c b/signal.c new file mode 100644 index 00000000..8b638ff0 --- /dev/null +++ b/signal.c @@ -0,0 +1,165 @@ +/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ + +/* + * Copyright 2000-2002 Niels Provos + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Niels Provos. + * 4. 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 "config.h" + +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_LOG +#include "log.h" +#else +#define LOG_DBG(x) +#define log_error(x) perror(x) +#endif + +#include "event.h" + +extern struct event_list timequeue; +extern struct event_list eventqueue; +extern struct event_list signalqueue; + +short evsigcaught[NSIG]; +volatile sig_atomic_t evsignal_caught = 0; + +struct selectop { + int event_fds; /* Highest fd in fd set */ + int event_fdsz; + fd_set *event_readset; + fd_set *event_writeset; + sigset_t evsigmask; +} sop; + +void evsignal_process(void); +int evsignal_recalc(sigset_t *); +int evsignal_deliver(void); + +void +evsignal_init(sigset_t *evsigmask) +{ + sigemptyset(evsigmask); +} + +int +evsignal_add(sigset_t *evsigmask, struct event *ev) +{ + int signal; + + if (ev->ev_events & (EV_READ|EV_WRITE)) + errx(1, "%s: EV_SIGNAL incompatible use", __func__); + signal = EVENT_SIGNAL(ev); + sigaddset(evsigmask, signal); + + return (0); +} + +/* + * Nothing to be done here. + */ + +int +evsignal_del(sigset_t *evsigmask, struct event *ev) +{ + int signal; + + signal = EVENT_SIGNAL(ev); + sigdelset(evsigmask, signal); + + return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL)); +} + +static void +evsignal_handler(int sig) +{ + evsigcaught[sig]++; + evsignal_caught = 1; +} + +int +evsignal_recalc(sigset_t *evsigmask) +{ + struct sigaction sa; + struct event *ev; + + if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1) + return (-1); + + /* Reinstall our signal handler. */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = evsignal_handler; + sa.sa_mask = sop.evsigmask; + sa.sa_flags |= SA_RESTART; + + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1) + return (-1); + } + return (0); +} + +int +evsignal_deliver(void) +{ + return (sigprocmask(SIG_UNBLOCK, &sop.evsigmask, NULL)); + /* XXX - pending signals handled here */ +} + +void +evsignal_process(void) +{ + struct event *ev; + short ncalls; + + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + ncalls = evsigcaught[EVENT_SIGNAL(ev)]; + if (ncalls) { + if (!(ev->ev_events & EV_PERSIST)) + event_del(ev); + event_active(ev, EV_SIGNAL, ncalls); + } + } + + memset(evsigcaught, 0, sizeof(evsigcaught)); + evsignal_caught = 0; +} + -- 2.40.0