Download raw body.
Qt6: Fix poll() busy-loop on socket close with POLLOUT
If there are no objections, I would commit it. I haven't had any
problems with this diff for a week.
Rafael
On Mon Aug 04, 2025 at 05:30:51PM +0200, Rafael Sadowski wrote:
> sys/kern/sys_generic.c:
> if (pl[i].events != 0 && pl[i].events != POLLOUT)
> DPRINTFN(0, "weird events %x\n", pl[i].events);
>
> Looks like we have the same behavior as FreeBSD:
>
> https://codereview.qt-project.org/c/qt/qtbase/+/651677
>
> "On FreeBSD when asked for POLLOUT the poll() syscall returns only POLLHUP to
> signify the fact that the other side closed the connection. It never sends
> POLLERR for EOF cases, which results in a busy-loop inside the Glib dispatcher:
>
> - poll() returns immediately with POLLHUP for a closed socket
> - socketNotifierSourceCheck() does not detect it, because
> events = POLLOUT | POLLERR and we get .revents = POLLHUP.
> The (events & revents != 0) condition evaluates to false
> - the code decides there is nothing to do and a new iteration starts"
>
> A similar issue in dbus code: https://gitlab.freedesktop.org/dbus/dbus/-/merge_requests/526
>
> @Antoine Maybe we should patch dbus too?
>
> OK?
>
> diff --git a/x11/qt6/qtbase/Makefile b/x11/qt6/qtbase/Makefile
> index 3788dfa293f..9c7df648b55 100644
> --- a/x11/qt6/qtbase/Makefile
> +++ b/x11/qt6/qtbase/Makefile
> @@ -4,7 +4,7 @@ COMMENT-main = C++ general-purpose toolkit
> COMMENT-global = global Qt6 documentation internals
> COMMENT-mysql = MySQL plugin for Qt6
> COMMENT-psql = PostgresSQL plugin for Qt6
> -REVISION-main = 2
> +REVISION-main = 3
>
> PKGSPEC-main = qt6-qtbase-${QT6_PKGSPEC}
>
> diff --git a/x11/qt6/qtbase/patches/patch-src_corelib_kernel_qeventdispatcher_glib_cpp b/x11/qt6/qtbase/patches/patch-src_corelib_kernel_qeventdispatcher_glib_cpp
> new file mode 100644
> index 00000000000..45ee0cfff2d
> --- /dev/null
> +++ b/x11/qt6/qtbase/patches/patch-src_corelib_kernel_qeventdispatcher_glib_cpp
> @@ -0,0 +1,18 @@
> +https://codereview.qt-project.org/c/qt/qtbase/+/651677
> +
> +Index: src/corelib/kernel/qeventdispatcher_glib.cpp
> +--- src/corelib/kernel/qeventdispatcher_glib.cpp.orig
> ++++ src/corelib/kernel/qeventdispatcher_glib.cpp
> +@@ -434,10 +434,10 @@ void QEventDispatcherGlib::registerSocketNotifier(QSoc
> + p->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
> + break;
> + case QSocketNotifier::Write:
> +- p->pollfd.events = G_IO_OUT | G_IO_ERR;
> ++ p->pollfd.events = G_IO_OUT | G_IO_HUP | G_IO_ERR;
> + break;
> + case QSocketNotifier::Exception:
> +- p->pollfd.events = G_IO_PRI | G_IO_ERR;
> ++ p->pollfd.events = G_IO_PRI | G_IO_HUP | G_IO_ERR;
> + break;
> + }
> + p->socketNotifier = notifier;
> diff --git a/x11/qt6/qtbase/patches/patch-src_network_socket_qnativesocketengine_unix_cpp b/x11/qt6/qtbase/patches/patch-src_network_socket_qnativesocketengine_unix_cpp
> new file mode 100644
> index 00000000000..20af6817dad
> --- /dev/null
> +++ b/x11/qt6/qtbase/patches/patch-src_network_socket_qnativesocketengine_unix_cpp
> @@ -0,0 +1,14 @@
> +https://codereview.qt-project.org/c/qt/qtbase/+/651677
> +
> +Index: src/network/socket/qnativesocketengine_unix.cpp
> +--- src/network/socket/qnativesocketengine_unix.cpp.orig
> ++++ src/network/socket/qnativesocketengine_unix.cpp
> +@@ -1379,7 +1379,7 @@ int QNativeSocketEnginePrivate::nativeSelect(QDeadline
> + }
> +
> + static const short read_flags = POLLIN | POLLHUP | POLLERR;
> +- static const short write_flags = POLLOUT | POLLERR;
> ++ static const short write_flags = POLLOUT | POLLHUP | POLLERR;
> +
> + *selectForRead = ((pfd.revents & read_flags) != 0);
> + *selectForWrite = ((pfd.revents & write_flags) != 0);
>
Qt6: Fix poll() busy-loop on socket close with POLLOUT