From b440e6e9d8574eb08f1ee368d0bcafc73197a555 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sat, 11 Jul 2026 02:13:13 +0800 Subject: [PATCH] udev-monitor: make the monitor fd non-blocking systemd's libudev documents that the monitor socket is non-blocking by default: https://github.com/systemd/systemd/blob/v261/src/libudev/libudev-monitor.c#L228-L231 It also creates the monitor socket with SOCK_NONBLOCK: https://github.com/systemd/systemd/blob/v261/src/libsystemd/sd-device/device-monitor.c#L179-L183 libudev-devd currently uses a blocking pipe. Once all pending events have been consumed, another call to udev_monitor_receive_device() blocks instead of returning NULL with EAGAIN. This was observed in KWin, where display hotplug handling stalled after disconnecting and reconnecting an external display in a KDE/Wayland session. Set O_NONBLOCK on the read end returned by udev_monitor_get_fd(). Keep the internal write end blocking to preserve the current producer and backpressure behavior. Sponsored by: The FreeBSD Foundation --- udev-monitor.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/udev-monitor.c b/udev-monitor.c index 042e67a..6d295da 100644 --- a/udev-monitor.c +++ b/udev-monitor.c @@ -59,6 +59,20 @@ struct udev_monitor { pthread_t thread; }; +static int +udev_monitor_set_fd_nonblock(int fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) + return (-1); + if ((flags & O_NONBLOCK) != 0) + return (0); + + return (fcntl(fd, F_SETFL, flags | O_NONBLOCK)); +} + LIBUDEV_EXPORT struct udev_device * udev_monitor_receive_device(struct udev_monitor *um) { @@ -226,6 +240,13 @@ udev_monitor_new_from_netlink(struct udev *udev, const char *name) free(um); return (NULL); } + if (udev_monitor_set_fd_nonblock(um->fds[0]) == -1) { + ERR("fcntl failed"); + close(um->fds[0]); + close(um->fds[1]); + free(um); + return (NULL); + } um->udev = udev; _udev_ref(udev);