# 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
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 */
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)
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) {
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);
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) {
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;
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;
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;
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;
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;
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;