Use eventfd() on Linux to wake up dupecheck when packets are available

This commit is contained in:
Heikki Hannikainen 2012-11-16 18:23:15 +02:00
parent 809691aa3d
commit a454f2332f
7 changed files with 93 additions and 4 deletions

View File

@ -9,6 +9,9 @@
/* POSIX capabilities */
#undef HAVE_CAPABILITY_H
/* Linux event fd support */
#undef HAVE_EVENTFD_H
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
@ -60,6 +63,9 @@
/* Define to 1 if you have the <sys/epoll.h> header file. */
#undef HAVE_SYS_EPOLL_H
/* Define to 1 if you have the <sys/eventfd.h> header file. */
#undef HAVE_SYS_EVENTFD_H
/* Define to 1 if you have the <sys/prctl.h> header file. */
#undef HAVE_SYS_PRCTL_H

View File

@ -35,6 +35,15 @@
#endif
#endif
#ifdef HAVE_EVENTFD_H
#include <sys/eventfd.h>
#ifdef EFD_NONBLOCK
#ifdef EFD_CLOEXEC
#define USE_EVENTFD
#endif
#endif
#endif
extern int fork_a_daemon; /* fork a daemon */
extern int dump_requests; /* print requests */

15
src/configure vendored
View File

@ -3536,6 +3536,21 @@ if test "x$ac_cv_lib_cap_cap_init" = x""yes; then :
fi
for ac_header in sys/eventfd.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "sys/eventfd.h" "ac_cv_header_sys_eventfd_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_eventfd_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_EVENTFD_H 1
_ACEOF
$as_echo "#define HAVE_EVENTFD_H /**/" >>confdefs.h
fi
done
for ac_header in alloca.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "alloca.h" "ac_cv_header_alloca_h" "$ac_includes_default"

View File

@ -69,6 +69,9 @@ AC_CHECK_HEADERS([sys/prctl.h], AC_DEFINE([HAVE_PRCTL_H], [], [Linux process con
AC_SUBST(LIBCAP)
AC_CHECK_LIB(cap,cap_init,[LIBCAP="-lcap"])
dnl Check for
AC_CHECK_HEADERS([sys/eventfd.h], AC_DEFINE([HAVE_EVENTFD_H], [], [Linux event fd support]))
dnl Checks for system headers
AC_CHECK_HEADERS([alloca.h], AC_DEFINE([HAVE_ALLOCA_H]))
AC_CHECK_HEADERS([poll.h], AC_DEFINE([HAVE_POLL_H]))

View File

@ -20,6 +20,10 @@
#include <stdlib.h>
#include <pthread.h>
#ifdef USE_EVENTFD
#include <sys/eventfd.h>
#endif
#include "dupecheck.h"
#include "config.h"
#include "hlog.h"
@ -59,6 +63,11 @@ cellarena_t *dupecheck_cells;
volatile uint32_t dupecheck_seqnum = -2000; // Explicit early wrap-around..
volatile uint32_t dupecheck_dupe_seqnum = -2000; // Explicit early wrap-around..
#ifdef USE_EVENTFD
int dupecheck_eventfd = -1;
struct pollfd dupecheck_eventfd_poll;
#endif
static int pbuf_seqnum_lag(const uint32_t seqnum, const uint32_t pbuf_seq)
{
// The lag calculation method takes care of the value space
@ -204,6 +213,18 @@ void dupecheck_init(void)
2048 /* 2 MB at the time */,
0 /* minfree */);
#endif
#ifdef USE_EVENTFD
dupecheck_eventfd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
if (dupecheck_eventfd < 0) {
hlog(LOG_ERR, "dupecheck: eventfd init failed: %s", strerror(errno));
exit(1);
}
dupecheck_eventfd_poll.fd = dupecheck_eventfd;
dupecheck_eventfd_poll.events = POLLIN;
hlog(LOG_DEBUG, "dupecheck: eventfd initialized on fd %d", dupecheck_eventfd);
#endif
}
static struct dupe_record_t *dupecheck_db_alloc(int len)
@ -790,14 +811,25 @@ static void dupecheck_thread(void)
// if (n > 0)
// hlog(LOG_DEBUG, "Dupecheck did analyze %d packets, found %d duplicates", n, pb_out_dupe_count);
/* sleep a little, if there was nothing to do */
if (n == 0)
if (n == 0) {
#ifdef USE_EVENTFD
int p = poll(&dupecheck_eventfd_poll, 1, 1000);
hlog(LOG_DEBUG, "dupecheck: poll returned %d", p);
if (p > 0) {
uint64_t u;
p = read(dupecheck_eventfd, &u, sizeof(uint64_t));
hlog(LOG_DEBUG, "dupecheck: eventfd read %d: %lu", p, u);
}
#else
poll(NULL, 0, 20); // 20 ms
#endif
}
}
hlog( LOG_INFO, "Dupecheck thread shut down; seqnum=%u/%u",
pbuf_seqnum_lag(dupecheck_seqnum,(uint32_t)-2000), // initial bias..
pbuf_seqnum_lag(dupecheck_dupe_seqnum,(uint32_t)-2000));
dupecheck_running = 0;
}
@ -827,6 +859,15 @@ void dupecheck_stop(void)
dupecheck_shutting_down = 1;
#ifdef USE_EVENTFD
/* wake up dupecheck from sleep */
uint64_t u = 1;
int i = write(dupecheck_eventfd, &u, sizeof(uint64_t));
if (i != sizeof(uint64_t)) {
hlog(LOG_ERR, "incoming_stop() failed to write to dupecheck_eventfd: %s", strerror(errno));
}
#endif
if ((e = pthread_join(dupecheck_th, NULL)))
hlog(LOG_ERR, "Could not pthread_join dupecheck_th: %s", strerror(e));
else

View File

@ -41,6 +41,8 @@ extern long long dupecheck_dupecount; /* statistics counter */
extern long long dupecheck_dupetypes[DTYPE_MAX+1];
extern long dupecheck_cellgauge; /* statistics gauge */
extern int dupecheck_eventfd;
extern int outgoing_lag_report(struct worker_t *self, int*lag, int*dupelag);
extern void dupecheck_init(void);

View File

@ -17,6 +17,9 @@
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
@ -35,6 +38,7 @@
#include "version.h"
#include "cellmalloc.h"
#include "messaging.h"
#include "dupecheck.h"
/* When adding labels here, remember to add the description strings in
* web/aprsc.js rx_err_strings
@ -394,8 +398,17 @@ void incoming_flush(struct worker_t *self)
self->pbuf_incoming_count += self->pbuf_incoming_local_count;
pthread_mutex_unlock(&self->pbuf_incoming_mutex);
// hlog( LOG_DEBUG, "incoming_flush() sent out %d packets, incoming_count %d",
// self->pbuf_incoming_local_count, incoming_count );
hlog( LOG_DEBUG, "incoming_flush() sent out %d packets",
self->pbuf_incoming_local_count );
#ifdef USE_EVENTFD
/* wake up dupecheck from sleep */
uint64_t u = 1;
int i = write(dupecheck_eventfd, &u, sizeof(uint64_t));
if (i != sizeof(uint64_t)) {
hlog(LOG_ERR, "incoming_flush() failed to write to dupecheck_eventfd: %s", strerror(errno));
}
#endif
/* clean the local lockfree queue */
self->pbuf_incoming_local = NULL;