+/*
+ * Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT
+ * OWNER OR CONTRIBUTORS 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 <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
+#include <stddef.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
-#define HAVE_EPOLL 1
-
#ifndef HAVE_MONOTONIC
# ifdef CLOCK_MONOTONIC
# define HAVE_MONOTONIC 1
if ((cnt) > cur) \
{ \
int newcnt = cur ? cur << 1 : 16; \
- fprintf (stderr, "resize(" # base ") from %d to %d\n", cur, newcnt);\
base = realloc (base, sizeof (*base) * (newcnt)); \
init (base + cur, newcnt - cur); \
cur = newcnt; \
static void
event (W w, int events)
{
- w->pending = ++pendingcnt;
- array_needsize (pendings, pendingmax, pendingcnt, );
- pendings [pendingcnt - 1].w = w;
- pendings [pendingcnt - 1].events = events;
+ if (w->active)
+ {
+ w->pending = ++pendingcnt;
+ array_needsize (pendings, pendingmax, pendingcnt, );
+ pendings [pendingcnt - 1].w = w;
+ pendings [pendingcnt - 1].events = events;
+ }
}
static void
event (events [i], type);
}
+/* called on EBADF to verify fds */
+static void
+fd_recheck ()
+{
+ int fd;
+
+ for (fd = 0; fd < anfdmax; ++fd)
+ if (anfds [fd].wev)
+ if (fcntl (fd, F_GETFD) == -1 && errno == EBADF)
+ while (anfds [fd].head)
+ evio_stop (anfds [fd].head);
+}
+
/*****************************************************************************/
static struct ev_timer **timers;
static struct ev_idle **idles;
static int idlemax, idlecnt;
+static struct ev_prepare **prepares;
+static int preparemax, preparecnt;
+
static struct ev_check **checks;
static int checkmax, checkcnt;
static void
call_pending ()
{
- int i;
-
- for (i = 0; i < pendingcnt; ++i)
+ while (pendingcnt)
{
- ANPENDING *p = pendings + i;
+ ANPENDING *p = pendings + --pendingcnt;
if (p->w)
{
p->w->cb (p->w, p->events);
}
}
-
- pendingcnt = 0;
}
static void
{
struct ev_timer *w = timers [0];
+ event ((W)w, EV_TIMEOUT);
+
/* first reschedule or stop timer */
if (w->repeat)
{
}
else
evtimer_stop (w); /* nonrepeating: stop timer */
-
- event ((W)w, EV_TIMEOUT);
}
}
double block;
ev_loop_done = flags & EVLOOP_ONESHOT ? 1 : 0;
- if (checkcnt)
- {
- queue_events ((W *)checks, checkcnt, EV_CHECK);
- call_pending ();
- }
-
do
{
+ /* queue check watchers (and execute them) */
+ if (preparecnt)
+ {
+ queue_events ((W *)prepares, preparecnt, EV_PREPARE);
+ call_pending ();
+ }
+
/* update fd-related kernel structures */
fd_reify ();
/* calculate blocking time */
- /* we only need this for !monotonic clock, but as we always have timers, we just calculate it every time */
+ /* we only need this for !monotonic clockor timers, but as we basically
+ always have timers, we just calculate it always */
ev_now = ev_time ();
if (flags & EVLOOP_NONBLOCK || idlecnt)
time_update ();
/* queue pending timers and reschedule them */
- periodics_reify (); /* absolute timers first */
- timers_reify (); /* relative timers second */
+ timers_reify (); /* relative timers called last */
+ periodics_reify (); /* absolute timers called first */
/* queue idle watchers unless io or timers are pending */
if (!pendingcnt)
queue_events ((W *)idles, idlecnt, EV_IDLE);
- /* queue check and possibly idle watchers */
- queue_events ((W *)checks, checkcnt, EV_CHECK);
+ /* queue check watchers, to be executed first */
+ if (checkcnt)
+ queue_events ((W *)checks, checkcnt, EV_CHECK);
call_pending ();
}
}
}
+static void
+ev_clear (W w)
+{
+ if (w->pending)
+ {
+ pendings [w->pending - 1].w = 0;
+ w->pending = 0;
+ }
+}
+
static void
ev_start (W w, int active)
{
- w->pending = 0;
w->active = active;
}
static void
ev_stop (W w)
{
- if (w->pending)
- pendings [w->pending - 1].w = 0;
-
w->active = 0;
}
void
evio_stop (struct ev_io *w)
{
+ ev_clear ((W)w);
if (!ev_is_active (w))
return;
fdchanges [fdchangecnt - 1] = w->fd;
}
-
void
evtimer_start (struct ev_timer *w)
{
void
evtimer_stop (struct ev_timer *w)
{
+ ev_clear ((W)w);
if (!ev_is_active (w))
return;
void
evperiodic_stop (struct ev_periodic *w)
{
+ ev_clear ((W)w);
if (!ev_is_active (w))
return;
void
evsignal_stop (struct ev_signal *w)
{
+ ev_clear ((W)w);
if (!ev_is_active (w))
return;
void evidle_stop (struct ev_idle *w)
{
+ ev_clear ((W)w);
+ if (ev_is_active (w))
+ return;
+
idles [w->active - 1] = idles [--idlecnt];
ev_stop ((W)w);
}
+void evprepare_start (struct ev_prepare *w)
+{
+ if (ev_is_active (w))
+ return;
+
+ ev_start ((W)w, ++preparecnt);
+ array_needsize (prepares, preparemax, preparecnt, );
+ prepares [preparecnt - 1] = w;
+}
+
+void evprepare_stop (struct ev_prepare *w)
+{
+ ev_clear ((W)w);
+ if (ev_is_active (w))
+ return;
+
+ prepares [w->active - 1] = prepares [--preparecnt];
+ ev_stop ((W)w);
+}
+
void evcheck_start (struct ev_check *w)
{
if (ev_is_active (w))
void evcheck_stop (struct ev_check *w)
{
+ ev_clear ((W)w);
+ if (ev_is_active (w))
+ return;
+
checks [w->active - 1] = checks [--checkcnt];
ev_stop ((W)w);
}
/*****************************************************************************/
+struct ev_once
+{
+ struct ev_io io;
+ struct ev_timer to;
+ void (*cb)(int revents, void *arg);
+ void *arg;
+};
+
+static void
+once_cb (struct ev_once *once, int revents)
+{
+ void (*cb)(int revents, void *arg) = once->cb;
+ void *arg = once->arg;
+
+ evio_stop (&once->io);
+ evtimer_stop (&once->to);
+ free (once);
+
+ cb (revents, arg);
+}
+
+static void
+once_cb_io (struct ev_io *w, int revents)
+{
+ once_cb ((struct ev_once *)(((char *)w) - offsetof (struct ev_once, io)), revents);
+}
+
+static void
+once_cb_to (struct ev_timer *w, int revents)
+{
+ once_cb ((struct ev_once *)(((char *)w) - offsetof (struct ev_once, to)), revents);
+}
+
+void
+ev_once (int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg)
+{
+ struct ev_once *once = malloc (sizeof (struct ev_once));
+
+ if (!once)
+ cb (EV_ERROR, arg);
+ else
+ {
+ once->cb = cb;
+ once->arg = arg;
+
+ evw_init (&once->io, once_cb_io);
+
+ if (fd >= 0)
+ {
+ evio_set (&once->io, fd, events);
+ evio_start (&once->io);
+ }
+
+ evw_init (&once->to, once_cb_to);
+
+ if (timeout >= 0.)
+ {
+ evtimer_set (&once->to, timeout, 0.);
+ evtimer_start (&once->to);
+ }
+ }
+}
+
+/*****************************************************************************/
+
#if 0
struct ev_io wio;