From 38e8a1c7b8b5fc0512d82e19c2da2c296e1826b2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 23 Jun 2020 10:04:54 +0200 Subject: [PATCH] MINOR: debug: add a new DEBUG_FD build option When DEBUG_FD is set at build time, we'll keep a counter of per-FD events in the fdtab. This counter is reported in "show fd" even for closed FDs if not zero. The purpose is to help spot situations where an apparently closed FD continues to be reported in loops, or where some events are dismissed. --- Makefile | 3 ++- include/haproxy/fd-t.h | 3 +++ include/haproxy/fd.h | 3 +++ src/cli.c | 17 +++++++++++++++-- src/ev_epoll.c | 3 +++ src/ev_evports.c | 3 +++ src/ev_kqueue.c | 3 +++ src/ev_poll.c | 3 +++ src/ev_select.c | 3 +++ src/fd.c | 3 +++ 10 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 9d8d350de4..d77900931b 100644 --- a/Makefile +++ b/Makefile @@ -213,7 +213,8 @@ SMALL_OPTS = # You can enable debugging on specific code parts by setting DEBUG=-DDEBUG_xxx. # Currently defined DEBUG macros include DEBUG_FULL, DEBUG_MEMORY, DEBUG_FSM, # DEBUG_HASH, DEBUG_AUTH, DEBUG_SPOE, DEBUG_UAF and DEBUG_THREAD, DEBUG_STRICT, -# DEBUG_DEV. Please check sources for exact meaning or do not use at all. +# DEBUG_DEV, DEBUG_FD. Please check sources for exact meaning or do not use at +# all. DEBUG = #### Trace options diff --git a/include/haproxy/fd-t.h b/include/haproxy/fd-t.h index 97b383cebf..6ff8ef135d 100644 --- a/include/haproxy/fd-t.h +++ b/include/haproxy/fd-t.h @@ -134,6 +134,9 @@ struct fdtab { unsigned char cloned:1; /* 1 if a cloned socket, requires EPOLL_CTL_DEL on close */ unsigned char initialized:1; /* 1 if init phase was done on this fd (e.g. set non-blocking) */ unsigned char et_possible:1; /* 1 if edge-triggered is possible on this FD */ +#ifdef DEBUG_FD + unsigned int event_count; /* number of events reported */ +#endif } THREAD_ALIGNED(64); /* polled mask, one bit per thread and per direction for each FD */ diff --git a/include/haproxy/fd.h b/include/haproxy/fd.h index f7af4e162d..7b77567fa1 100644 --- a/include/haproxy/fd.h +++ b/include/haproxy/fd.h @@ -446,6 +446,9 @@ static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), unsigned fdtab[fd].linger_risk = 0; fdtab[fd].cloned = 0; fdtab[fd].et_possible = 0; +#ifdef DEBUG_FD + fdtab[fd].event_count = 0; +#endif /* conn_fd_handler should support edge-triggered FDs */ if ((global.tune.options & GTUNE_FD_ET) && fdtab[fd].iocb == conn_fd_handler) diff --git a/src/cli.c b/src/cli.c index b8fac13a88..b9afc1b204 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1002,7 +1002,14 @@ static int cli_io_handler_show_fd(struct appctx *appctx) fdt = fdtab[fd]; - if (!fdt.owner) + /* When DEBUG_FD is set, we also report closed FDs that have a + * non-null event count to detect stuck ones. + */ + if (!fdt.owner +#ifdef DEBUG_FD + && !fdt.event_count +#endif + ) goto skip; // closed if (fdt.iocb == conn_fd_handler) { @@ -1038,7 +1045,10 @@ static int cli_io_handler_show_fd(struct appctx *appctx) fdt.iocb); resolve_sym_name(&trash, NULL, fdt.iocb); - if (fdt.iocb == conn_fd_handler) { + if (!fdt.owner) { + chunk_appendf(&trash, ")"); + } + else if (fdt.iocb == conn_fd_handler) { chunk_appendf(&trash, ") back=%d cflg=0x%08x", is_back, conn_flags); if (px) chunk_appendf(&trash, " px=%s", px->id); @@ -1061,6 +1071,9 @@ static int cli_io_handler_show_fd(struct appctx *appctx) li->bind_conf->frontend->id); } +#ifdef DEBUG_FD + chunk_appendf(&trash, " evcnt=%u", fdtab[fd].event_count); +#endif chunk_appendf(&trash, ")\n"); if (ci_putchk(si_ic(si), &trash) == -1) { diff --git a/src/ev_epoll.c b/src/ev_epoll.c index 92c000f859..ba7f2e030f 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -222,6 +222,9 @@ static void _do_poll(struct poller *p, int exp, int wake) e = epoll_events[count].events; fd = epoll_events[count].data.fd; +#ifdef DEBUG_FD + _HA_ATOMIC_ADD(&fdtab[fd].event_count, 1); +#endif if (!fdtab[fd].owner) { activity[tid].poll_dead_fd++; continue; diff --git a/src/ev_evports.c b/src/ev_evports.c index a00813584f..2ad546ff87 100644 --- a/src/ev_evports.c +++ b/src/ev_evports.c @@ -216,6 +216,9 @@ static void _do_poll(struct poller *p, int exp, int wake) fd = evports_evlist[i].portev_object; events = evports_evlist[i].portev_events; +#ifdef DEBUG_FD + _HA_ATOMIC_ADD(&fdtab[fd].event_count, 1); +#endif if (fdtab[fd].owner == NULL) { activity[tid].poll_dead_fd++; continue; diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index 539394e7fe..a67d05b267 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -183,6 +183,9 @@ static void _do_poll(struct poller *p, int exp, int wake) unsigned int n = 0; fd = kev[count].ident; +#ifdef DEBUG_FD + _HA_ATOMIC_ADD(&fdtab[fd].event_count, 1); +#endif if (!fdtab[fd].owner) { activity[tid].poll_dead_fd++; continue; diff --git a/src/ev_poll.c b/src/ev_poll.c index e63334e14a..b0b0e2bc4d 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -219,6 +219,9 @@ static void _do_poll(struct poller *p, int exp, int wake) int e = poll_events[count].revents; fd = poll_events[count].fd; +#ifdef DEBUG_FD + _HA_ATOMIC_ADD(&fdtab[fd].event_count, 1); +#endif if (!(e & ( POLLOUT | POLLIN | POLLERR | POLLHUP | POLLRDHUP ))) continue; diff --git a/src/ev_select.c b/src/ev_select.c index 544b7f2117..aca1ea8ec1 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -197,6 +197,9 @@ static void _do_poll(struct poller *p, int exp, int wake) for (count = BITS_PER_INT, fd = fds * BITS_PER_INT; count && fd < maxfd; count--, fd++) { unsigned int n = 0; +#ifdef DEBUG_FD + _HA_ATOMIC_ADD(&fdtab[fd].event_count, 1); +#endif if (!fdtab[fd].owner) { activity[tid].poll_dead_fd++; continue; diff --git a/src/fd.c b/src/fd.c index 60ad69901e..bf2383e4d7 100644 --- a/src/fd.c +++ b/src/fd.c @@ -322,6 +322,9 @@ static void fd_dodelete(int fd, int do_close) fdtab[fd].state = 0; +#ifdef DEBUG_FD + fdtab[fd].event_count = 0; +#endif port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port); fdinfo[fd].port_range = NULL; fdtab[fd].owner = NULL; -- 2.39.5