initial support for signals (only for select now) based on code from

Dug Song <dugsong@monkey.org>


svn:r17
This commit is contained in:
Niels Provos 2002-04-10 00:31:31 +00:00
parent dbaa408ea5
commit b855bc5500
5 changed files with 174 additions and 9 deletions

23
event.c
View File

@ -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;

View File

@ -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);

View 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 = *~

52
sample/signal-test.c Normal file
View File

@ -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);
}

View File

@ -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>
@ -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);
if ((res = select(sop->event_fds + 1, sop->event_readset,
sop->event_writeset, NULL, tv)) == -1) {
res = select(sop->event_fds + 1, sop->event_readset,
sop->event_writeset, NULL, tv);
if (signal_recalc() == -1)
return (-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));
}