Browse Source

better destroy support, separate into default loop and additional loops

master
Marc Alexander Lehmann 14 years ago
parent
commit
0c25f49f94
  1. 327
      ev.c
  2. 34
      ev.h
  3. 33
      ev_epoll.c
  4. 25
      ev_kqueue.c
  5. 10
      ev_poll.c
  6. 16
      ev_select.c
  7. 12
      event.c

327
ev.c

@ -340,6 +340,21 @@ fd_enomem (EV_P)
}
}
/* susually called after fork if method needs to re-arm all fds from scratch */
static void
fd_rearm_all (EV_P)
{
int fd;
/* this should be highly optimised to not do anything but set a flag */
for (fd = 0; fd < anfdmax; ++fd)
if (anfds [fd].events)
{
anfds [fd].events = 0;
fd_change (fd);
}
}
/*****************************************************************************/
static void
@ -544,7 +559,7 @@ ev_method (EV_P)
return method;
}
inline int
static void
loop_init (EV_P_ int methods)
{
if (!method)
@ -562,12 +577,9 @@ loop_init (EV_P_ int methods)
now_floor = mn_now;
rtmn_diff = rt_now - mn_now;
if (pipe (sigpipe))
return 0;
if (methods == EVMETHOD_AUTO)
if (!enable_secure () && getenv ("LIBmethodS"))
methods = atoi (getenv ("LIBmethodS"));
if (!enable_secure () && getenv ("LIBEV_METHODS"))
methods = atoi (getenv ("LIBEV_METHODS"));
else
methods = EVMETHOD_ANY;
@ -584,87 +596,145 @@ loop_init (EV_P_ int methods)
#if EV_USE_SELECT
if (!method && (methods & EVMETHOD_SELECT)) method = select_init (EV_A_ methods);
#endif
}
}
if (method)
{
ev_watcher_init (&sigev, sigcb);
ev_set_priority (&sigev, EV_MAXPRI);
siginit (EV_A);
#ifndef WIN32
ev_signal_init (&childev, childcb, SIGCHLD);
ev_set_priority (&childev, EV_MAXPRI);
ev_signal_start (EV_A_ &childev);
ev_unref (EV_A); /* child watcher should not keep loop alive */
void
loop_destroy (EV_P)
{
#if EV_USE_KQUEUE
if (method == EVMETHOD_KQUEUE) kqueue_destroy (EV_A);
#endif
#if EV_USE_EPOLL
if (method == EVMETHOD_EPOLL ) epoll_destroy (EV_A);
#endif
#if EV_USEV_POLL
if (method == EVMETHOD_POLL ) poll_destroy (EV_A);
#endif
#if EV_USE_SELECT
if (method == EVMETHOD_SELECT) select_destroy (EV_A);
#endif
}
}
return method;
method = 0;
/*TODO*/
}
#if EV_MULTIPLICITY
void
loop_fork (EV_P)
{
/*TODO*/
#if EV_USE_EPOLL
if (method == EVMETHOD_EPOLL ) epoll_fork (EV_A);
#endif
#if EV_USE_KQUEUE
if (method == EVMETHOD_KQUEUE) kqueue_fork (EV_A);
#endif
}
#if EV_MULTIPLICITY
struct ev_loop *
ev_loop_new (int methods)
{
struct ev_loop *loop = (struct ev_loop *)calloc (1, sizeof (struct ev_loop));
if (loop_init (EV_A_ methods))
return loop;
loop_init (EV_A_ methods);
ev_loop_delete (loop);
if (ev_methods (EV_A))
return loop;
return 0;
}
void
ev_loop_delete (EV_P)
ev_loop_destroy (EV_P)
{
/*TODO*/
loop_destroy (EV_A);
free (loop);
}
void
ev_loop_fork (EV_P)
{
loop_fork (EV_A);
}
#endif
#if EV_MULTIPLICITY
struct ev_loop default_loop_struct;
static struct ev_loop *default_loop;
struct ev_loop *
#else
static int default_loop;
int
ev_init (int methods)
#endif
ev_default_loop (int methods)
{
return loop_init (methods);
}
if (sigpipe [0] == sigpipe [1])
if (pipe (sigpipe))
return 0;
if (!default_loop)
{
#if EV_MULTIPLICITY
struct ev_loop *loop = default_loop = &default_loop_struct;
#else
default_loop = 1;
#endif
/*****************************************************************************/
loop_init (EV_A_ methods);
void
ev_fork_prepare (void)
{
/* nop */
if (ev_method (EV_A))
{
ev_watcher_init (&sigev, sigcb);
ev_set_priority (&sigev, EV_MAXPRI);
siginit (EV_A);
#ifndef WIN32
ev_signal_init (&childev, childcb, SIGCHLD);
ev_set_priority (&childev, EV_MAXPRI);
ev_signal_start (EV_A_ &childev);
ev_unref (EV_A); /* child watcher should not keep loop alive */
#endif
}
else
default_loop = 0;
}
return default_loop;
}
void
ev_fork_parent (void)
ev_default_destroy (void)
{
/* nop */
struct ev_loop *loop = default_loop;
ev_ref (EV_A); /* child watcher */
ev_signal_stop (EV_A_ &childev);
ev_ref (EV_A); /* signal watcher */
ev_io_stop (EV_A_ &sigev);
close (sigpipe [0]); sigpipe [0] = 0;
close (sigpipe [1]); sigpipe [1] = 0;
loop_destroy (EV_A);
}
void
ev_fork_child (void)
ev_default_fork (EV_P)
{
/*TODO*/
#if !EV_MULTIPLICITY
#if EV_USE_EPOLL
if (method == EVMETHOD_EPOLL)
epoll_postfork_child (EV_A);
#endif
loop_fork (EV_A);
ev_io_stop (EV_A_ &sigev);
close (sigpipe [0]);
close (sigpipe [1]);
pipe (sigpipe);
ev_ref (EV_A); /* signal watcher */
siginit (EV_A);
#endif
}
/*****************************************************************************/
@ -1085,46 +1155,6 @@ ev_periodic_stop (EV_P_ struct ev_periodic *w)
ev_stop (EV_A_ (W)w);
}
#ifndef SA_RESTART
# define SA_RESTART 0
#endif
void
ev_signal_start (EV_P_ struct ev_signal *w)
{
if (ev_is_active (w))
return;
assert (("ev_signal_start called with illegal signal number", w->signum > 0));
ev_start (EV_A_ (W)w, 1);
array_needsize (signals, signalmax, w->signum, signals_init);
wlist_add ((WL *)&signals [w->signum - 1].head, (WL)w);
if (!w->next)
{
struct sigaction sa;
sa.sa_handler = sighandler;
sigfillset (&sa.sa_mask);
sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
sigaction (w->signum, &sa, 0);
}
}
void
ev_signal_stop (EV_P_ struct ev_signal *w)
{
ev_clear_pending (EV_A_ (W)w);
if (!ev_is_active (w))
return;
wlist_del ((WL *)&signals [w->signum - 1].head, (WL)w);
ev_stop (EV_A_ (W)w);
if (!signals [w->signum - 1].head)
signal (w->signum, SIG_DFL);
}
void
ev_idle_start (EV_P_ struct ev_idle *w)
{
@ -1191,9 +1221,55 @@ ev_check_stop (EV_P_ struct ev_check *w)
ev_stop (EV_A_ (W)w);
}
#ifndef SA_RESTART
# define SA_RESTART 0
#endif
void
ev_signal_start (EV_P_ struct ev_signal *w)
{
#if EV_MULTIPLICITY
assert (("signal watchers are only supported in the default loop", loop == default_loop));
#endif
if (ev_is_active (w))
return;
assert (("ev_signal_start called with illegal signal number", w->signum > 0));
ev_start (EV_A_ (W)w, 1);
array_needsize (signals, signalmax, w->signum, signals_init);
wlist_add ((WL *)&signals [w->signum - 1].head, (WL)w);
if (!w->next)
{
struct sigaction sa;
sa.sa_handler = sighandler;
sigfillset (&sa.sa_mask);
sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
sigaction (w->signum, &sa, 0);
}
}
void
ev_signal_stop (EV_P_ struct ev_signal *w)
{
ev_clear_pending (EV_A_ (W)w);
if (!ev_is_active (w))
return;
wlist_del ((WL *)&signals [w->signum - 1].head, (WL)w);
ev_stop (EV_A_ (W)w);
if (!signals [w->signum - 1].head)
signal (w->signum, SIG_DFL);
}
void
ev_child_start (EV_P_ struct ev_child *w)
{
#if EV_MULTIPLICITY
assert (("child watchers are only supported in the default loop", loop == default_loop));
#endif
if (ev_is_active (w))
return;
@ -1275,86 +1351,3 @@ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, vo
}
}
/*****************************************************************************/
#if 0
struct ev_io wio;
static void
sin_cb (struct ev_io *w, int revents)
{
fprintf (stderr, "sin %d, revents %d\n", w->fd, revents);
}
static void
ocb (struct ev_timer *w, int revents)
{
//fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data);
ev_timer_stop (w);
ev_timer_start (w);
}
static void
scb (struct ev_signal *w, int revents)
{
fprintf (stderr, "signal %x,%d\n", revents, w->signum);
ev_io_stop (&wio);
ev_io_start (&wio);
}
static void
gcb (struct ev_signal *w, int revents)
{
fprintf (stderr, "generic %x\n", revents);
}
int main (void)
{
ev_init (0);
ev_io_init (&wio, sin_cb, 0, EV_READ);
ev_io_start (&wio);
struct ev_timer t[10000];
#if 0
int i;
for (i = 0; i < 10000; ++i)
{
struct ev_timer *w = t + i;
ev_watcher_init (w, ocb, i);
ev_timer_init_abs (w, ocb, drand48 (), 0.99775533);
ev_timer_start (w);
if (drand48 () < 0.5)
ev_timer_stop (w);
}
#endif
struct ev_timer t1;
ev_timer_init (&t1, ocb, 5, 10);
ev_timer_start (&t1);
struct ev_signal sig;
ev_signal_init (&sig, scb, SIGQUIT);
ev_signal_start (&sig);
struct ev_check cw;
ev_check_init (&cw, gcb);
ev_check_start (&cw);
struct ev_idle iw;
ev_idle_init (&iw, gcb);
ev_idle_start (&iw);
ev_loop (0);
return 0;
}
#endif

34
ev.h

@ -212,22 +212,29 @@ struct ev_child
int ev_version_major (void);
int ev_version_minor (void);
/* these three calls are suitable for plugging into pthread_atfork */
void ev_fork_prepare (void);
void ev_fork_parent (void);
void ev_fork_child (void);
ev_tstamp ev_time (void);
# if EV_MULTIPLICITY
/* the default loop is the only one that handles signals and child watchers */
/* you can call this as often as you like */
struct ev_loop *ev_default_loop (int methods); /* returns default loop */
/* create and destroy alternative loops that don't handle signals */
struct ev_loop *ev_loop_new (int methods);
void ev_loop_delete (EV_P);
void ev_loop_destroy (EV_P);
void ev_loop_fork (EV_P);
# else
int ev_init (int methods); /* returns ev_method */
int ev_default_loop (int methods); /* returns true when successful */
# endif
int ev_method (EV_P);
void ev_default_destroy (void); /* destroy the default loop */
/* this needs to be called after fork, to duplicate the default loop */
/* if you create alternative loops you have to call ev_loop_fork on them */
/* you can call it in either the parent or the child */
/* you can actually call it at any time, anywhere :) */
void ev_default_fork (void);
int ev_method (EV_P);
#endif
#define EVLOOP_NONBLOCK 1 /* do not block/wait */
@ -287,14 +294,12 @@ void ev_io_stop (EV_P_ struct ev_io *w);
void ev_timer_start (EV_P_ struct ev_timer *w);
void ev_timer_stop (EV_P_ struct ev_timer *w);
void ev_timer_again (EV_P_ struct ev_timer *w); /* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */
/* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */
void ev_timer_again (EV_P_ struct ev_timer *w);
void ev_periodic_start (EV_P_ struct ev_periodic *w);
void ev_periodic_stop (EV_P_ struct ev_periodic *w);
void ev_signal_start (EV_P_ struct ev_signal *w);
void ev_signal_stop (EV_P_ struct ev_signal *w);
void ev_idle_start (EV_P_ struct ev_idle *w);
void ev_idle_stop (EV_P_ struct ev_idle *w);
@ -304,6 +309,11 @@ void ev_prepare_stop (EV_P_ struct ev_prepare *w);
void ev_check_start (EV_P_ struct ev_check *w);
void ev_check_stop (EV_P_ struct ev_check *w);
/* only supported in the default loop */
void ev_signal_start (EV_P_ struct ev_signal *w);
void ev_signal_stop (EV_P_ struct ev_signal *w);
/* only supported in the default loop */
void ev_child_start (EV_P_ struct ev_child *w);
void ev_child_stop (EV_P_ struct ev_child *w);
#endif

33
ev_epoll.c

@ -45,20 +45,6 @@ epoll_modify (EV_P_ int fd, int oev, int nev)
epoll_ctl (epoll_fd, mode, fd, &ev);
}
static void
epoll_postfork_child (EV_P)
{
int fd;
epoll_fd = epoll_create (256);
fcntl (epoll_fd, F_SETFD, FD_CLOEXEC);
/* re-register interest in fds */
for (fd = 0; fd < anfdmax; ++fd)
if (anfds [fd].events)//D
epoll_modify (EV_A_ fd, EV_NONE, anfds [fd].events);
}
static void
epoll_poll (EV_P_ ev_tstamp timeout)
{
@ -105,3 +91,22 @@ epoll_init (EV_P_ int flags)
return EVMETHOD_EPOLL;
}
static void
epoll_destroy (EV_P)
{
close (epoll_fd);
free (epoll_events);
}
static void
epoll_fork (EV_P)
{
int fd;
epoll_fd = epoll_create (256);
fcntl (epoll_fd, F_SETFD, FD_CLOEXEC);
fd_rearm_all ();
}

25
ev_kqueue.c

@ -133,6 +133,8 @@ kqueue_init (EV_P_ int flags)
if ((kqueue_fd = kqueue ()) < 0)
return 0;
fcntl (kqueue_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */
/* Check for Mac OS X kqueue bug. */
ch.ident = -1;
ch.filter = EVFILT_READ;
@ -159,6 +161,29 @@ kqueue_init (EV_P_ int flags)
kqueue_eventmax = 64; /* intiial number of events receivable per poll */
kqueue_events = malloc (sizeof (struct kevent) * kqueue_eventmax);
kqueue_changes = 0;
kqueue_changemax = 0;
kqueue_changecnt = 0;
return EVMETHOD_KQUEUE;
}
static void
kqueue_destroy (EV_P)
{
close (kqueue_fd);
free (kqueue_events);
free (kqueue_changes);
}
static void
kqueue_fork (EV_P)
{
kqueue_fd = kqueue ();
fcntl (kqueue_fd, F_SETFD, FD_CLOEXEC);
/* re-register interest in fds */
fd_rearm_all ();
}

10
ev_poll.c

@ -101,5 +101,15 @@ poll_init (EV_P_ int flags)
method_modify = poll_modify;
method_poll = poll_poll;
pollidxs = 0; pollidxmax = 0;
polls = 0; pollsmax = 0; pollscnt = 0;
return EVMETHOD_POLL;
}
static void
poll_destroy (EV_P)
{
free (pollidxs);
free (polls);
}

16
ev_select.c

@ -128,6 +128,22 @@ select_init (EV_P_ int flags)
method_modify = select_modify;
method_poll = select_poll;
vec_max = 0;
vec_ri = 0;
vec_ri = 0;
vec_wo = 0;
vec_wo = 0;
return EVMETHOD_SELECT;
}
static void
select_destroy (EV_P)
{
free (vec_ri);
free (vec_ro);
free (vec_wi);
free (vec_wo);
}

12
event.c

@ -32,6 +32,7 @@
#include <stddef.h>
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>
#include "event.h"
@ -49,7 +50,7 @@ struct event_base
int dummy;
};
static struct event_base x_base, *x_cur;
static struct event_base *x_cur;
static void
tv_set (struct timeval *tv, ev_tstamp at)
@ -82,9 +83,14 @@ const char *event_get_method (void)
void *event_init (void)
{
#if EV_MULTIPLICITY
x_cur = (struct event_base *)ev_loop_new (EVMETHOD_AUTO);
if (x_cur)
x_cur = (struct event_base *)ev_loop_new (EVMETHOD_AUTO);
else
x_cur = ev_default_loop (EVMETHOD_AUTO);
#else
x_cur = &x_base;
assert (("multiple event bases not supported when not compiled with EV_MULTIPLICITY", !x_cur));
x_cur = (struct event_base *)ev_default_loop (EVMETHOD_AUTO);
#endif
return x_cur;

Loading…
Cancel
Save