mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Introduced --with-libevent based on links code
I don't know how to deal with select's exception fds in libevent, so some functions may not work properly.
This commit is contained in:
parent
050f304161
commit
3b6ff1d22f
30
configure.in
30
configure.in
@ -1213,6 +1213,36 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
# ========
|
||||
# libevent
|
||||
# ========
|
||||
AC_ARG_WITH(libevent, [ --with-libevent compile with libevent],
|
||||
[if test "$withval" = yes; then enable_libevent=yes; else enable_libevent=no; fi])
|
||||
|
||||
cf_have_libevent=no
|
||||
if test "$enable_libevent" = yes; then
|
||||
AC_CHECK_HEADERS(event.h ev-event.h libev/event.h)
|
||||
if test "$ac_cv_header_event_h" = yes; then
|
||||
AC_CHECK_LIB(event, event_loop)
|
||||
if test "$ac_cv_lib_event_event_loop" = yes; then
|
||||
cf_have_libevent=libevent
|
||||
fi
|
||||
fi
|
||||
if test "$cf_have_libevent" = no; then
|
||||
if test "$ac_cv_header_event_h" = yes -o "$ac_cv_header_ev_event_h" = yes -o "$ac_cv_header_libev_event_h"; then
|
||||
AC_CHECK_LIB(ev, event_loop)
|
||||
if test "$ac_cv_lib_ev_event_loop" = yes; then
|
||||
cf_have_libevent=libev
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test "$cf_have_libevent" != no; then
|
||||
AC_HAVE_FUNCS(event_base_set event_get_version event_get_method event_base_free event_base_new event_reinit event_base_get_method event_config_set_flag event_get_struct_event_size)
|
||||
fi
|
||||
EL_LOG_CONFIG([CONFIG_LIBEVENT], [[libevent]], [[$cf_have_libevent]])
|
||||
|
||||
|
||||
# Final SSL setup
|
||||
|
||||
EL_CONFIG_DEPENDS(CONFIG_SSL, [CONFIG_OPENSSL CONFIG_GNUTLS CONFIG_NSS_COMPAT_OSSL], [SSL])
|
||||
|
@ -302,6 +302,7 @@ terminate_all_subsystems(void)
|
||||
unregister_modules_options(main_modules);
|
||||
done_options();
|
||||
done_event();
|
||||
terminate_select();
|
||||
terminate_osdep();
|
||||
#ifdef CONFIG_COMBINE
|
||||
free_combined();
|
||||
|
@ -31,6 +31,17 @@
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#if (defined(HAVE_EVENT_H) || defined(HAVE_EV_EVENT_H) || defined(HAVE_LIBEV_EVENT_H)) && (defined(HAVE_LIBEVENT) || defined(HAVE_LIBEV)) && !defined(OPENVMS) && !defined(DOS)
|
||||
#if defined(HAVE_EVENT_H)
|
||||
#include <event.h>
|
||||
#elif defined(HAVE_EV_EVENT_H)
|
||||
#include <ev-event.h>
|
||||
#else
|
||||
#include <libev/event.h>
|
||||
#endif
|
||||
#define USE_LIBEVENT
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
@ -59,11 +70,21 @@ do { \
|
||||
#define FD_SETSIZE 1024
|
||||
#endif
|
||||
|
||||
/*
|
||||
#define DEBUG_CALLS
|
||||
*/
|
||||
|
||||
static int n_threads = 0;
|
||||
|
||||
struct thread {
|
||||
select_handler_T read_func;
|
||||
select_handler_T write_func;
|
||||
select_handler_T error_func;
|
||||
void *data;
|
||||
#ifdef USE_LIBEVENT
|
||||
struct event *read_event;
|
||||
struct event *write_event;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OS_WIN32
|
||||
@ -72,7 +93,7 @@ struct thread {
|
||||
#define FD_SETSIZE 4096
|
||||
#endif
|
||||
|
||||
static struct thread threads[FD_SETSIZE];
|
||||
static struct thread *threads = NULL;
|
||||
|
||||
static fd_set w_read;
|
||||
static fd_set w_write;
|
||||
@ -138,6 +159,192 @@ check_bottom_halves(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
restrict_fds(void)
|
||||
{
|
||||
#if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
|
||||
#define RLIMIT_NOFILE RLIMIT_OFILE
|
||||
#endif
|
||||
#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
|
||||
struct rlimit limit;
|
||||
int rs;
|
||||
EINTRLOOP(rs, getrlimit(RLIMIT_NOFILE, &limit));
|
||||
if (rs)
|
||||
goto skip_limit;
|
||||
if (limit.rlim_cur > FD_SETSIZE) {
|
||||
limit.rlim_cur = FD_SETSIZE;
|
||||
EINTRLOOP(rs, setrlimit(RLIMIT_NOFILE, &limit));
|
||||
}
|
||||
skip_limit:;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_LIBEVENT
|
||||
|
||||
int event_enabled = 0;
|
||||
|
||||
#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 inline
|
||||
struct event *timer_event(struct timer *tm)
|
||||
{
|
||||
return (struct event *)((unsigned char *)tm - sizeof_struct_event);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EVENT_BASE_SET
|
||||
struct event_base *event_base;
|
||||
#endif
|
||||
|
||||
static void
|
||||
event_callback(int h, short ev, void *data)
|
||||
{
|
||||
#ifndef EV_PERSIST
|
||||
if (event_add((struct event *)data, NULL) == -1)
|
||||
elinks_internal("ERROR: event_add failed: %s", strerror(errno));
|
||||
#endif
|
||||
if (!(ev & EV_READ) == !(ev & EV_WRITE))
|
||||
elinks_internal("event_callback: invalid flags %d on handle %d", (int)ev, h);
|
||||
if (ev & EV_READ) {
|
||||
#if defined(HAVE_LIBEV)
|
||||
/* Old versions of libev badly interact with fork and fire
|
||||
* events spuriously. */
|
||||
if (ev_version_major() < 4 && !can_read(h)) return;
|
||||
#endif
|
||||
threads[h].read_func(threads[h].data);
|
||||
} else if (ev & EV_WRITE) {
|
||||
#if defined(HAVE_LIBEV)
|
||||
/* Old versions of libev badly interact with fork and fire
|
||||
* events spuriously. */
|
||||
if (ev_version_major() < 4 && !can_write(h)) return;
|
||||
#endif
|
||||
threads[h].write_func(threads[h].data);
|
||||
}
|
||||
check_bottom_halves();
|
||||
}
|
||||
|
||||
static void
|
||||
set_event_for_action(int h, void (*func)(void *), struct event **evptr, short evtype)
|
||||
{
|
||||
if (func) {
|
||||
if (!*evptr) {
|
||||
#ifdef EV_PERSIST
|
||||
evtype |= EV_PERSIST;
|
||||
#endif
|
||||
*evptr = mem_alloc(sizeof_struct_event);
|
||||
event_set(*evptr, h, evtype, event_callback, *evptr);
|
||||
#ifdef HAVE_EVENT_BASE_SET
|
||||
if (event_base_set(event_base, *evptr) == -1)
|
||||
elinks_internal("ERROR: event_base_set failed: %s, handle %d", strerror(errno), h);
|
||||
#endif
|
||||
}
|
||||
if (event_add(*evptr, NULL) == -1)
|
||||
elinks_internal("ERROR: event_add failed: %s, handle %d", strerror(errno), h);
|
||||
} else {
|
||||
if (*evptr) {
|
||||
if (event_del(*evptr) == -1)
|
||||
elinks_internal("ERROR: event_del failed: %s, handle %d", strerror(errno), h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_events_for_handle(int h)
|
||||
{
|
||||
set_event_for_action(h, threads[h].read_func, &threads[h].read_event, EV_READ);
|
||||
set_event_for_action(h, threads[h].write_func, &threads[h].write_event, EV_WRITE);
|
||||
}
|
||||
|
||||
static void
|
||||
enable_libevent(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (0 /* disable_libevent */)
|
||||
return;
|
||||
|
||||
#if !defined(NO_FORK_ON_EXIT) && defined(HAVE_KQUEUE) && !defined(HAVE_EVENT_REINIT)
|
||||
/* kqueue doesn't work after fork */
|
||||
if (!F)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_EVENT_CONFIG_SET_FLAG)
|
||||
{
|
||||
struct event_config *cfg;
|
||||
cfg = event_config_new();
|
||||
if (!cfg)
|
||||
return;
|
||||
if (event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK) == -1) {
|
||||
event_config_free(cfg);
|
||||
return;
|
||||
}
|
||||
event_base = event_base_new_with_config(cfg);
|
||||
event_config_free(cfg);
|
||||
if (!event_base)
|
||||
return;
|
||||
}
|
||||
#elif defined(HAVE_EVENT_BASE_NEW)
|
||||
event_base = event_base_new();
|
||||
if (!event_base)
|
||||
return;
|
||||
#elif defined(HAVE_EVENT_BASE_SET)
|
||||
event_base = event_init();
|
||||
if (!event_base)
|
||||
return;
|
||||
#else
|
||||
event_init();
|
||||
#endif
|
||||
event_enabled = 1;
|
||||
|
||||
for (i = 0; i < w_max; i++)
|
||||
set_events_for_handle(i);
|
||||
|
||||
/*
|
||||
foreach(tm, timers)
|
||||
set_event_for_timer(tm);
|
||||
*/
|
||||
set_events_for_timer();
|
||||
}
|
||||
|
||||
static void
|
||||
terminate_libevent(void)
|
||||
{
|
||||
int i;
|
||||
if (event_enabled) {
|
||||
for (i = 0; i < n_threads; i++) {
|
||||
set_event_for_action(i, NULL, &threads[i].read_event, EV_READ);
|
||||
if (threads[i].read_event)
|
||||
mem_free(threads[i].read_event);
|
||||
set_event_for_action(i, NULL, &threads[i].write_event, EV_WRITE);
|
||||
if (threads[i].write_event)
|
||||
mem_free(threads[i].write_event);
|
||||
}
|
||||
#ifdef HAVE_EVENT_BASE_FREE
|
||||
event_base_free(event_base);
|
||||
#endif
|
||||
event_enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_event_loop(int flags)
|
||||
{
|
||||
int e;
|
||||
#ifdef HAVE_EVENT_BASE_SET
|
||||
e = event_base_loop(event_base, flags);
|
||||
#else
|
||||
e = event_loop(flags);
|
||||
#endif
|
||||
if (e == -1)
|
||||
elinks_internal("ERROR: event_base_loop failed: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
select_handler_T
|
||||
get_handler(int fd, enum select_handler_type tp)
|
||||
{
|
||||
@ -183,11 +390,44 @@ set_handlers(int fd, select_handler_T read_func, select_handler_T write_func,
|
||||
error_func = NULL;
|
||||
}
|
||||
#endif /* __GNU__ */
|
||||
|
||||
#if defined(USE_POLL) && defined(USE_LIBEVENT)
|
||||
if (!event_enabled)
|
||||
#endif
|
||||
if (fd >= (int)FD_SETSIZE) {
|
||||
elinks_internal("too big handle %d", fd);
|
||||
return;
|
||||
}
|
||||
if (fd >= n_threads) {
|
||||
threads = mem_realloc(threads, (fd + 1) * sizeof(struct thread));
|
||||
memset(threads + n_threads, 0, (fd + 1 - n_threads) * sizeof(struct thread));
|
||||
n_threads = fd + 1;
|
||||
}
|
||||
|
||||
threads[fd].read_func = read_func;
|
||||
threads[fd].write_func = write_func;
|
||||
threads[fd].error_func = error_func;
|
||||
threads[fd].data = data;
|
||||
|
||||
if (read_func || write_func || error_func) {
|
||||
if (fd >= w_max) w_max = fd + 1;
|
||||
} else if (fd == w_max - 1) {
|
||||
int i;
|
||||
|
||||
for (i = fd - 1; i >= 0; i--)
|
||||
if (FD_ISSET(i, &w_read)
|
||||
|| FD_ISSET(i, &w_write)
|
||||
|| FD_ISSET(i, &w_error))
|
||||
break;
|
||||
w_max = i + 1;
|
||||
}
|
||||
|
||||
#ifdef USE_LIBEVENT
|
||||
if (event_enabled) {
|
||||
set_events_for_handle(fd);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (read_func) {
|
||||
FD_SET(fd, &w_read);
|
||||
} else {
|
||||
@ -208,19 +448,6 @@ set_handlers(int fd, select_handler_T read_func, select_handler_T write_func,
|
||||
FD_CLR(fd, &w_error);
|
||||
FD_CLR(fd, &x_error);
|
||||
}
|
||||
|
||||
if (read_func || write_func || error_func) {
|
||||
if (fd >= w_max) w_max = fd + 1;
|
||||
} else if (fd == w_max - 1) {
|
||||
int i;
|
||||
|
||||
for (i = fd - 1; i >= 0; i--)
|
||||
if (FD_ISSET(i, &w_read)
|
||||
|| FD_ISSET(i, &w_write)
|
||||
|| FD_ISSET(i, &w_error))
|
||||
break;
|
||||
w_max = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -241,6 +468,27 @@ select_loop(void (*init)(void))
|
||||
init();
|
||||
check_bottom_halves();
|
||||
|
||||
#ifdef USE_LIBEVENT
|
||||
enable_libevent();
|
||||
#if defined(USE_POLL)
|
||||
if (!event_enabled) {
|
||||
restrict_fds();
|
||||
}
|
||||
#endif
|
||||
if (event_enabled) {
|
||||
while (!program.terminate) {
|
||||
check_signals();
|
||||
if (1 /*(!F)*/) {
|
||||
do_event_loop(EVLOOP_NONBLOCK);
|
||||
check_signals();
|
||||
redraw_all_terminals();
|
||||
}
|
||||
if (program.terminate) break;
|
||||
do_event_loop(EVLOOP_ONCE);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
||||
while (!program.terminate) {
|
||||
struct timeval *timeout = NULL;
|
||||
int n, i, has_timer;
|
||||
@ -392,3 +640,12 @@ can_write(int fd)
|
||||
{
|
||||
return can_read_or_write(fd, 1);
|
||||
}
|
||||
|
||||
void
|
||||
terminate_select(void)
|
||||
{
|
||||
#ifdef USE_LIBEVENT
|
||||
terminate_libevent();
|
||||
#endif
|
||||
mem_free(threads);
|
||||
}
|
||||
|
@ -46,4 +46,5 @@ void set_handlers(int fd,
|
||||
int can_read(int fd);
|
||||
int can_write(int fd);
|
||||
|
||||
void terminate_select(void);
|
||||
#endif
|
||||
|
111
src/main/timer.c
111
src/main/timer.c
@ -4,6 +4,19 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if (defined(HAVE_EVENT_H) || defined(HAVE_EV_EVENT_H) || defined(HAVE_LIBEV_EVENT_H)) && (defined(HAVE_LIBEVENT) || defined(HAVE_LIBEV)) && !defined(OPENVMS) && !defined(DOS)
|
||||
#if defined(HAVE_EVENT_H)
|
||||
#include <event.h>
|
||||
#elif defined(HAVE_EV_EVENT_H)
|
||||
#include <ev-event.h>
|
||||
#else
|
||||
#include <libev/event.h>
|
||||
#endif
|
||||
#define USE_LIBEVENT
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "main/select.h"
|
||||
@ -68,6 +81,59 @@ check_timers(timeval_T *last_time)
|
||||
timeval_copy(last_time, &now);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
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
|
||||
@ -83,20 +149,34 @@ install_timer(timer_id_T *id, milliseconds_T delay, void (*func)(void *), void *
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
foreach (timer, timers) {
|
||||
if (timeval_cmp(&timer->interval, &new_timer->interval) >= 0)
|
||||
break;
|
||||
add_at_pos(timer->prev, new_timer);
|
||||
}
|
||||
|
||||
add_at_pos(timer->prev, new_timer);
|
||||
}
|
||||
|
||||
void
|
||||
@ -106,11 +186,16 @@ kill_timer(timer_id_T *id)
|
||||
|
||||
assert(id != NULL);
|
||||
if (*id == TIMER_ID_UNDEF) return;
|
||||
|
||||
timer = *id;
|
||||
del_from_list(timer);
|
||||
mem_free(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;
|
||||
}
|
||||
|
||||
@ -124,3 +209,15 @@ get_next_timer_time(timeval_T *t)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
set_events_for_timer(void)
|
||||
{
|
||||
#ifdef USE_LIBEVENT
|
||||
timer_id_T tm;
|
||||
|
||||
foreach(tm, timers)
|
||||
set_event_for_timer(tm);
|
||||
#endif
|
||||
}
|
||||
|
@ -22,5 +22,6 @@ void check_timers(timeval_T *last_time);
|
||||
void install_timer(timer_id_T *id, milliseconds_T delay, void (*)(void *), void *);
|
||||
void kill_timer(timer_id_T *id);
|
||||
int get_next_timer_time(timeval_T *t);
|
||||
void set_events_for_timer(void);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user