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.
diff --git a/Makefile b/Makefile
index 9d8d350..d779009 100644
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,8 @@
# 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 97b383c..6ff8ef1 100644
--- a/include/haproxy/fd-t.h
+++ b/include/haproxy/fd-t.h
@@ -134,6 +134,9 @@
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 f7af4e1..7b77567 100644
--- a/include/haproxy/fd.h
+++ b/include/haproxy/fd.h
@@ -446,6 +446,9 @@
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 b8fac13..b9afc1b 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -1002,7 +1002,14 @@
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 @@
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 @@
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 92c000f..ba7f2e0 100644
--- a/src/ev_epoll.c
+++ b/src/ev_epoll.c
@@ -222,6 +222,9 @@
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 a008135..2ad546f 100644
--- a/src/ev_evports.c
+++ b/src/ev_evports.c
@@ -216,6 +216,9 @@
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 539394e..a67d05b 100644
--- a/src/ev_kqueue.c
+++ b/src/ev_kqueue.c
@@ -183,6 +183,9 @@
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 e63334e..b0b0e2b 100644
--- a/src/ev_poll.c
+++ b/src/ev_poll.c
@@ -219,6 +219,9 @@
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 544b7f2..aca1ea8 100644
--- a/src/ev_select.c
+++ b/src/ev_select.c
@@ -197,6 +197,9 @@
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 60ad699..bf2383e 100644
--- a/src/fd.c
+++ b/src/fd.c
@@ -322,6 +322,9 @@
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;