Index | Thread | Search

From:
Rafael Sadowski <rafael@sizeofvoid.org>
Subject:
Qt6: Fix poll() busy-loop on socket close with POLLOUT
To:
ports@openbsd.org
Cc:
Antoine Jacoutot <ajacoutot@openbsd.org>
Date:
Mon, 4 Aug 2025 17:30:51 +0200

Download raw body.

Thread
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);