Re: Behavioral difference between Linux and FreeBSD poll()

From: Bob Bishop <rb_at_gid.co.uk>
Date: Wed, 04 Jun 2025 11:49:44 UTC
Hi,

> On 4 Jun 2025, at 09:04, Gleb Popov <arrowd@FreeBSD.org> wrote:
> 
> Hey hackers.
> 
> I was debugging two seemingly unrelated issues regarding busy-looping
> in D-Bus and Qt applications and bumped into a common root problem -
> our poll() implementation doesn't return POLLERR when callers expect
> that. The standard is indeed blurry on this topic [1] and does not
> specify when exactly POLLERR should be delivered.

Well strictly the only thing that is unclear in the standard is whether it’s OK to return POLLERR with POLLHUP.

> Here is a program that demonstrates the difference: https://arrowd.name/poll.c
> On Linux I only see
> 
> 28 (POLLOUT | POLLERR | POLLHUP)
> 28 (POLLOUT | POLLERR | POLLHUP)
> ...
> 
> and on FreeBSD I get
> 
> 20 (POLLOUT|POLLWRNORM|POLLHUP)
> 16 (POLLHUP)
> 16 (POLLHUP)
> ...
> 
> Now here are places in the code expecting POLLERR:
> - Qt [2] + [3], [4]
> - D-Bus [5]
> 
> On FreeBSD these places result in busy-loop, because poll() returns
> immediately, but the caller code does not handle the revents = POLLHUP
> case properly and gets back to calling poll() again.
> 
> My question is what would be a correct way to fix these issues. Should
> I patch poll() consumers to better handle POLLHUP or should we rather
> fix the kernel side to return POLLERR?

Consumers looking for disconnexion should test POLLHUP not POLLERR.

> Grepping through the src reveals that we have places, where calling
> code requests POLLERR in .events, which makes me think that it is the
> kernel that should be fixed. But I'm not a real kernel hacker.
> 
> P.S. Interestingly, the standard says that POLLOUT and POLLHUP are
> mutually exclusive, but both Linux and FreeBSD send them together.

... which is clearly a bug; but consumers ought to ignore POLLOUT if they see POLLHUP.

> [1] https://pubs.opengroup.org/onlinepubs/009696799/functions/poll.html
> [2] https://github.com/qt/qtbase/blob/4db3961ee140867e14f8e1d20173e85060bc6c50/src/corelib/kernel/qeventdispatcher_glib.cpp#L60
> [3] https://github.com/qt/qtbase/blob/4db3961ee140867e14f8e1d20173e85060bc6c50/src/corelib/kernel/qeventdispatcher_glib.cpp#L437
> [4] https://github.com/qt/qtbase/blob/4db3961ee140867e14f8e1d20173e85060bc6c50/src/network/socket/qnativesocketengine_unix.cpp#L1383
> [5] https://gitlab.freedesktop.org/dbus/dbus/-/blob/6bba6c58c5635bc123cb565ee1aac0f12cd980d3/dbus/dbus-transport-socket.c?page=2#L1207-1212
> 

--
Bob Bishop
rb@gid.co.uk