]> granicus.if.org Git - libevent/commitdiff
initial support for signals (only for select now) based on code from
authorNiels Provos <provos@gmail.com>
Wed, 10 Apr 2002 00:31:31 +0000 (00:31 +0000)
committerNiels Provos <provos@gmail.com>
Wed, 10 Apr 2002 00:31:31 +0000 (00:31 +0000)
Dug Song <dugsong@monkey.org>

svn:r17

event.c
event.h
sample/Makefile.am
sample/signal-test.c [new file with mode: 0644]
select.c

diff --git a/event.c b/event.c
index b4272af443b97a875ae8fdf8633d949fe0213fff..64636c9f8759c5b5a171720b171c3401c01231a9 100644 (file)
--- 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 cdc8d2aa6e7dbeb187e3e696553b746d96ec2c3c..7420a938a2e6676ef9b6806094263bf0d62eb5f3 100644 (file)
--- 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 <sys/queue.h> */
 #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);
index c195d032b18c2b89272a88328e7b477f9f59a9e3..952702b784f79109399cba43baa9d1c6447bd6ac 100644 (file)
@@ -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 (file)
index 0000000..3e5145d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <event.h>
+
+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);
+}
+
index b1329886f78534ac83df4bc82a86eb9a83d6ff96..7489285b5bb92021b04b984f49e91eb91e6d578a 100644 (file)
--- a/select.c
+++ b/select.c
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/queue.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 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));
+}
+