[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] Recuring timers



On Mon, Mar 29, 2010 at 12:36 PM, M P <buserror@xxxxxxxxx> wrote:
> Is there a way to install timers that are not one-shot ? currently I
> have to re-add the timer in the callback to make it restart, however,
> it creates obvious drift.
> I'm looking for a timer that restarts itself automatically...

If you're using Libevent 2.0.x, set the EV_PERSIST flag on the timer event.

If you're using Libevent 1.4.x or earlier, you'll have to fake it as
you describe above.  If you care about drift, you could implement a
quick-and-dirty persistent timer system with something like the
following (completely untested!) code:

#if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 0x02000100
struct recurring_timer {
    struct event ev;
    struct timeval tv_scheduled;
    struct timeval tv_interval;
    void (*timer_cb)(int fd, short what, void *user_data);
    void *user_data;
};

static void recurring_timer_cb(int fd, short what, void *arg)
{
    struct recurring_timer *timer = arg;
    struct timeval now, delta;
    evutil_gettimeofday(&now, NULL);
    /* pick the next time to run this event at based on its last scheduled
     * time.  This logic may or may not be what you want. */
    do {
        evutil_timeradd(&timer->tv_scheduled, &timer->tv_interval,
                        &timer->tv_scheduled);
    } while (evutil_timercmp(&now, &timer->tv_scheduled, <));

    /* delta = scheduled - now */
    evutil_timersub(&timer->tv_scheduled, &now, &delta);
    if (event_add(&timer->ev, &delta) < 0) {
        /* handle this error */
    }

    /* Run the user's callback */
    timer->timer_cb(-1, EV_TIMEOUT, timer->user_data);
}

void free_recurring_timer(struct recurring_timer *timer)
{
    event_del(&timer->ev);
    free(timer);
}

struct recurring_timer *new_recurring_timer(
                                            struct event_base *base,
                                            struct timeval *interval,
                                            void (*user_cb)(int, short, void *),
                                            void *user_data)
{
    struct recurring_timer *timer;
    if (!(timer = malloc(sizeof(*timer))))
        return NULL;

    evutil_gettimeofday(&timer->tv_scheduled, NULL);
    evutil_timeradd(&timer->tv_scheduled, interval, &timer->tv_scheduled);

    memcpy(&timer->tv_interval, interval, sizeof(*interval));

    timer->timer_cb = user_cb;
    timer->user_data = user_data;

    event_set(&timer->ev, -1, 0,  recurring_timer_cb, timer);
    if (base)
        event_base_set(base, &timer->ev);

    if (event_add(&timer->ev, interval) < 0) {
        free(timer);
        return NULL;
    }

    return timer;
}
#else
/* Looks like we have Libevent 2.0. */
#define recurring_timer event
#define free_recurring_timer(timer) event_free(timer)

struct recurring_timer *new_recurring_timer(
                              struct event_base *base,
                              struct timeval *interval,
                              void (*user_cb)(evutil_socket_t, short, void *),
                              void *user_data)
{
    struct event *ev;

    if (!(ev=event_new(base, -1, EV_PERSIST, user_cb, user_data)))
        return NULL;
    if (!(event_add(ev, interval))) {
        event_free(ev);
        return NULL;
    }
    return ev;
}
#endif


-- 
Nick
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.