mirror of
https://github.com/rkd77/elinks.git
synced 2024-10-13 05:43:37 -04:00
21d36fcbd1
When both --with-libev and --with-libevent are used, libev takes precedence.
236 lines
4.9 KiB
C
236 lines
4.9 KiB
C
/* Timers. */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
|
|
#if defined(HAVE_LIBEV) && !defined(OPENVMS) && !defined(DOS)
|
|
#ifdef HAVE_LIBEV_EVENT_H
|
|
#include <libev/event.h>
|
|
#elif defined(HAVE_EVENT_H)
|
|
#include <event.h>
|
|
#endif
|
|
#define USE_LIBEVENT
|
|
#endif
|
|
|
|
#if (defined(HAVE_EVENT_H) || defined(HAVE_EV_EVENT_H) || defined(HAVE_LIBEV_EVENT_H)) && defined(HAVE_LIBEVENT) && !defined(OPENVMS) && !defined(DOS)
|
|
#if defined(HAVE_EVENT_H)
|
|
#include <event.h>
|
|
#elif defined(HAVE_EV_EVENT_H)
|
|
#include <ev-event.h>
|
|
#endif
|
|
#define USE_LIBEVENT
|
|
#endif
|
|
|
|
#include "elinks.h"
|
|
|
|
#include "main/select.h"
|
|
#include "main/timer.h"
|
|
#include "util/error.h"
|
|
#include "util/lists.h"
|
|
#include "util/memory.h"
|
|
#include "util/time.h"
|
|
|
|
|
|
struct timer {
|
|
LIST_HEAD(struct timer);
|
|
|
|
timeval_T interval;
|
|
void (*func)(void *);
|
|
void *data;
|
|
};
|
|
|
|
/* @timers.next points to the timer with the smallest interval,
|
|
* @timers.next->next to the second smallest, and so on. */
|
|
static INIT_LIST_OF(struct timer, timers);
|
|
|
|
int
|
|
get_timers_count(void)
|
|
{
|
|
return list_size(&timers);
|
|
|
|
}
|
|
|
|
|
|
#ifdef HAVE_EVENT_BASE_SET
|
|
extern struct event_base *event_base;
|
|
#endif
|
|
|
|
#ifdef USE_LIBEVENT
|
|
extern int event_enabled;
|
|
#ifndef HAVE_EVENT_GET_STRUCT_EVENT_SIZE
|
|
#define sizeof_struct_event sizeof(struct event)
|
|
#else
|
|
#define sizeof_struct_event (event_get_struct_event_size())
|
|
#endif
|
|
|
|
static void
|
|
timer_callback(int h, short ev, void *data)
|
|
{
|
|
struct timer *tm = data;
|
|
tm->func(tm->data);
|
|
kill_timer(&tm);
|
|
check_bottom_halves();
|
|
}
|
|
|
|
|
|
static inline
|
|
struct event *timer_event(struct timer *tm)
|
|
{
|
|
return (struct event *)((unsigned char *)tm - sizeof_struct_event);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
check_timers(timeval_T *last_time)
|
|
{
|
|
timeval_T now;
|
|
timeval_T interval;
|
|
struct timer *timer;
|
|
|
|
timeval_now(&now);
|
|
timeval_sub(&interval, last_time, &now);
|
|
|
|
foreach (timer, timers) {
|
|
timeval_sub_interval(&timer->interval, &interval);
|
|
}
|
|
|
|
while (!list_empty(timers)) {
|
|
timer = timers.next;
|
|
|
|
if (timeval_is_positive(&timer->interval))
|
|
break;
|
|
|
|
del_from_list(timer);
|
|
/* At this point, *@timer is to be considered invalid
|
|
* outside timers.c; if anything e.g. passes it to
|
|
* @kill_timer, that's a bug. However, @timer->func
|
|
* and @check_bottom_halves can still call @kill_timer
|
|
* on other timers, so this loop must be careful not to
|
|
* keep pointers to them. (bug 868) */
|
|
timer->func(timer->data);
|
|
#ifdef USE_LIBEVENT
|
|
mem_free(timer_event(timer));
|
|
#else
|
|
mem_free(timer);
|
|
#endif
|
|
check_bottom_halves();
|
|
}
|
|
|
|
timeval_copy(last_time, &now);
|
|
}
|
|
|
|
|
|
static void
|
|
set_event_for_timer(timer_id_T tm)
|
|
{
|
|
#ifdef USE_LIBEVENT
|
|
struct timeval tv;
|
|
struct event *ev = timer_event(tm);
|
|
timeout_set(ev, timer_callback, tm);
|
|
#ifdef HAVE_EVENT_BASE_SET
|
|
if (event_base_set(event_base, ev) == -1)
|
|
elinks_internal("ERROR: event_base_set failed: %s", strerror(errno));
|
|
#endif
|
|
tv.tv_sec = tm->interval.sec;
|
|
tv.tv_usec = tm->interval.usec;
|
|
#if defined(HAVE_LIBEV)
|
|
if (!tm->interval.usec && ev_version_major() < 4) {
|
|
/* libev bug */
|
|
tv.tv_usec = 1;
|
|
}
|
|
#endif
|
|
if (timeout_add(ev, &tv) == -1)
|
|
elinks_internal("ERROR: timeout_add failed: %s", strerror(errno));
|
|
#endif
|
|
}
|
|
|
|
/* Install a timer that calls @func(@data) after @delay milliseconds.
|
|
* Store to *@id either the ID of the new timer, or TIMER_ID_UNDEF if
|
|
* the timer cannot be installed. (This function ignores the previous
|
|
* value of *@id in any case.)
|
|
*
|
|
* When @func is called, the timer ID has become invalid. @func
|
|
* should erase the expired timer ID from all variables, so that
|
|
* there's no chance it will be given to @kill_timer later. */
|
|
void
|
|
install_timer(timer_id_T *id, milliseconds_T delay, void (*func)(void *), void *data)
|
|
{
|
|
struct timer *new_timer, *timer;
|
|
|
|
assert(id && delay > 0);
|
|
|
|
#ifdef USE_LIBEVENT
|
|
unsigned char *q = mem_alloc(sizeof_struct_event + sizeof(struct timer));
|
|
new_timer = (struct timer *)(q + sizeof_struct_event);
|
|
#else
|
|
new_timer = mem_alloc(sizeof(*new_timer));
|
|
#endif
|
|
*id = (timer_id_T) new_timer; /* TIMER_ID_UNDEF is NULL */
|
|
if (!new_timer) return;
|
|
|
|
timeval_from_milliseconds(&new_timer->interval, delay);
|
|
new_timer->func = func;
|
|
new_timer->data = data;
|
|
#ifdef USE_LIBEVENT
|
|
if (event_enabled) {
|
|
set_event_for_timer(new_timer);
|
|
add_to_list(timers, new_timer);
|
|
} else
|
|
#endif
|
|
{
|
|
foreach (timer, timers) {
|
|
if (timeval_cmp(&timer->interval, &new_timer->interval) >= 0)
|
|
break;
|
|
}
|
|
|
|
add_at_pos(timer->prev, new_timer);
|
|
}
|
|
}
|
|
|
|
void
|
|
kill_timer(timer_id_T *id)
|
|
{
|
|
struct timer *timer;
|
|
|
|
assert(id != NULL);
|
|
if (*id == TIMER_ID_UNDEF) return;
|
|
timer = *id;
|
|
del_from_list(timer);
|
|
|
|
#ifdef USE_LIBEVENT
|
|
if (event_enabled) {
|
|
timeout_del(timer_event(timer));
|
|
}
|
|
mem_free(timer_event(timer));
|
|
#else
|
|
mem_free(timer);
|
|
#endif
|
|
*id = TIMER_ID_UNDEF;
|
|
}
|
|
|
|
int
|
|
get_next_timer_time(timeval_T *t)
|
|
{
|
|
if (!list_empty(timers)) {
|
|
timeval_copy(t, &((struct timer *) &timers)->next->interval);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
set_events_for_timer(void)
|
|
{
|
|
#ifdef USE_LIBEVENT
|
|
timer_id_T tm;
|
|
|
|
foreach(tm, timers)
|
|
set_event_for_timer(tm);
|
|
#endif
|
|
}
|