From: Niels Provos Date: Wed, 10 Apr 2002 00:31:31 +0000 (+0000) Subject: initial support for signals (only for select now) based on code from X-Git-Tag: release-1.1b~152 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b855bc55000e64d0adb12822fcf8b8117e8f3309;p=libevent initial support for signals (only for select now) based on code from Dug Song svn:r17 --- diff --git a/event.c b/event.c index b4272af4..64636c9f 100644 --- a/event.c +++ b/event.c @@ -81,6 +81,7 @@ void event_queue_remove(struct event *, int); static RB_HEAD(event_tree, event) timetree; static struct event_list activequeue; +struct event_list signalqueue; struct event_list eventqueue; static struct timeval event_tv; @@ -111,6 +112,7 @@ event_init(void) RB_INIT(&timetree); TAILQ_INIT(&eventqueue); TAILQ_INIT(&activequeue); + TAILQ_INIT(&signalqueue); evbase = NULL; for (i = 0; eventops[i] && !evbase; i++) { @@ -129,7 +131,7 @@ int event_haveevents(void) { return (RB_ROOT(&timetree) || TAILQ_FIRST(&eventqueue) || - TAILQ_FIRST(&activequeue)); + TAILQ_FIRST(&signalqueue) || TAILQ_FIRST(&activequeue)); } void @@ -285,6 +287,11 @@ event_add(struct event *ev, struct timeval *tv) !(ev->ev_flags & EVLIST_INSERTED)) { event_queue_insert(ev, EVLIST_INSERTED); + return (evsel->add(evbase, ev)); + } else if ((ev->ev_events & EV_SIGNAL) && + !(ev->ev_flags & EVLIST_SIGNAL)) { + event_queue_insert(ev, EVLIST_SIGNAL); + return (evsel->add(evbase, ev)); } @@ -308,6 +315,9 @@ event_del(struct event *ev) if (ev->ev_flags & EVLIST_INSERTED) { event_queue_remove(ev, EVLIST_INSERTED); return (evsel->del(evbase, ev)); + } else if (ev->ev_flags & EVLIST_SIGNAL) { + event_queue_remove(ev, EVLIST_SIGNAL); + return (evsel->del(evbase, ev)); } return (0); @@ -323,12 +333,13 @@ event_active(struct event *ev, int res) int timeout_next(struct timeval *tv) { + struct timeval dflt = TIMEOUT_DEFAULT; + struct timeval now; struct event *ev; if ((ev = RB_MIN(event_tree, &timetree)) == NULL) { - timerclear(tv); - tv->tv_sec = TIMEOUT_DEFAULT; + *tv = dflt; return (0); } @@ -419,6 +430,9 @@ event_queue_remove(struct event *ev, int queue) case EVLIST_ACTIVE: TAILQ_REMOVE(&activequeue, ev, ev_active_next); break; + case EVLIST_SIGNAL: + TAILQ_REMOVE(&signalqueue, ev, ev_signal_next); + break; case EVLIST_TIMEOUT: RB_REMOVE(event_tree, &timetree, ev); break; @@ -442,6 +456,9 @@ event_queue_insert(struct event *ev, int queue) case EVLIST_ACTIVE: TAILQ_INSERT_TAIL(&activequeue, ev, ev_active_next); break; + case EVLIST_SIGNAL: + TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next); + break; case EVLIST_TIMEOUT: timeout_insert(ev); break; diff --git a/event.h b/event.h index cdc8d2aa..7420a938 100644 --- a/event.h +++ b/event.h @@ -36,6 +36,7 @@ extern "C" { #define EVLIST_TIMEOUT 0x01 #define EVLIST_INSERTED 0x02 +#define EVLIST_SIGNAL 0x04 #define EVLIST_ACTIVE 0x08 #define EVLIST_INIT 0x80 @@ -45,6 +46,7 @@ extern "C" { #define EV_TIMEOUT 0x01 #define EV_READ 0x02 #define EV_WRITE 0x04 +#define EV_SIGNAL 0x08 /* Fix so that ppl dont have to run with */ #ifndef TAILQ_ENTRY @@ -69,6 +71,7 @@ struct { \ struct event { TAILQ_ENTRY (event) ev_next; TAILQ_ENTRY (event) ev_active_next; + TAILQ_ENTRY (event) ev_signal_next; RB_ENTRY (event) ev_timeout_node; int ev_fd; @@ -83,6 +86,9 @@ struct event { int ev_flags; }; +#define EVENT_SIGNAL(ev) ev->ev_fd +#define EVENT_FD(ev) ev->ev_fd + #ifdef _EVENT_DEFINED_TQENTRY #undef TAILQ_ENTRY #undef _EVENT_DEFINED_TQENTRY @@ -103,7 +109,7 @@ struct eventop { int (*dispatch)(void *, struct timeval *); }; -#define TIMEOUT_DEFAULT 5 +#define TIMEOUT_DEFAULT {0, 250000L} void event_init(void); int event_dispatch(void); diff --git a/sample/Makefile.am b/sample/Makefile.am index c195d032..952702b7 100644 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -3,9 +3,10 @@ AUTOMAKE_OPTIONS = foreign no-dependencies LDADD = -L.. -levent CPPFPLAGS = -I.. -noinst_PROGRAMS = event-test time-test +noinst_PROGRAMS = event-test time-test signal-test event_test_sources = event-test.c time_test_sources = time-test.c +signal_test_sources = signal-test.c DISTCLEANFILES = *~ diff --git a/sample/signal-test.c b/sample/signal-test.c new file mode 100644 index 00000000..3e5145dd --- /dev/null +++ b/sample/signal-test.c @@ -0,0 +1,52 @@ +/* + * Compile with: + * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int called = 0; + +void +signal_cb(int fd, short event, void *arg) +{ + struct event *signal = arg; + + printf("%s: got signal %d\n", __FUNCTION__, EVENT_SIGNAL(signal)); + + if (called >= 2) + event_del(signal); + + called++; +} + +int +main (int argc, char **argv) +{ + struct event signal_int; + + /* Initalize the event library */ + event_init(); + + /* Initalize one event */ + event_set(&signal_int, SIGINT, EV_SIGNAL, signal_cb, &signal_int); + + event_add(&signal_int, NULL); + + event_dispatch(); + + return (0); +} + diff --git a/select.c b/select.c index b1329886..7489285b 100644 --- a/select.c +++ b/select.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -49,19 +50,25 @@ extern struct event_list timequeue; extern struct event_list eventqueue; -extern struct event_list addqueue; +extern struct event_list signalqueue; #ifndef howmany #define howmany(x, y) (((x)+((y)-1))/(y)) #endif +int evsigcaught[NSIG]; + 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 signal_process(void); +int signal_recalc(void); + void *select_init (void); int select_add (void *, struct event *); int select_del (void *, struct event *); @@ -82,6 +89,8 @@ select_init(void) { memset(&sop, 0, sizeof(sop)); + sigemptyset(&sop.evsigmask); + return (&sop); } @@ -130,7 +139,7 @@ select_recalc(void *arg, int max) sop->event_fdsz = fdsz; } - return (0); + return (signal_recalc()); } int @@ -150,9 +159,16 @@ select_dispatch(void *arg, struct timeval *tv) FD_SET(ev->ev_fd, sop->event_readset); } + if (signal_deliver() == -1) + return (-1); + + res = select(sop->event_fds + 1, sop->event_readset, + sop->event_writeset, NULL, tv); + + if (signal_recalc() == -1) + return (-1); - if ((res = select(sop->event_fds + 1, sop->event_readset, - sop->event_writeset, NULL, tv)) == -1) { + if (res == -1) { if (errno != EINTR) { log_error("select"); return (-1); @@ -184,6 +200,8 @@ select_dispatch(void *arg, struct timeval *tv) sop->event_fds = maxfd; + signal_process(); + return (0); } @@ -192,6 +210,18 @@ 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); + } + /* * Keep track of the highest fd, so that we can calculate the size * of the fd_sets for select(2) @@ -209,5 +239,64 @@ select_add(void *arg, struct event *ev) int select_del(void *arg, struct event *ev) { + struct selectop *sop = arg; + + int signal; + + 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)); +} + +static void +signal_handler(int sig) +{ + evsigcaught[sig]++; +} + +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; + + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + if (evsigcaught[EVENT_SIGNAL(ev)]) + event_active(ev, EV_SIGNAL); + } + + memset(evsigcaught, 0, sizeof(evsigcaught)); +} +