diff --git a/Makefile b/Makefile index 9d8d350de..d77900931 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 97b383ceb..6ff8ef135 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 f7af4e162..7b77567fa 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 b8fac13a8..b9afc1b20 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 92c000f85..ba7f2e030 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 a00813584..2ad546ff8 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 539394e7f..a67d05b26 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 e63334e14..b0b0e2bc4 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 544b7f211..aca1ea8ec 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 60ad69901..bf2383e4d 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;