From 7bdecaae3bc3f493ab7cbec637f7c373b6d96357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 24 May 2021 20:42:55 +0200 Subject: [PATCH] wayland: roundtrip: log error and abort when wl_display_roundtrip() fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ayl_roundtrip() has the following code: wl_display_roundtrip(wayl->display); while (wl_display_prepare_read(wayl->display) != 0) wl_display_dispatch_pending(wayl->display); wayl_flush(wayl); If the first wl_display_roundtrip() fails, for example because the Wayland socket has been closed, we may get stuck in the while-loop. This happens if the read queue isn’t empty, in which case wl_display_prepare_read() will return -1 and we’ll continue trying to dispatch the pending events forever, never succeeding since the socket is gone. Closes #542 --- CHANGELOG.md | 3 +++ wayland.c | 13 ++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5e4bbf4..69c5db1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -126,6 +126,9 @@ * Rare occurrences where the window did not close when the shell exited. Only seen on FreeBSD (https://codeberg.org/dnkl/foot/issues/534) +* Foot process(es) sometimes remaining, using 100% CPU, when closing + multiple foot windows at the same time + (https://codeberg.org/dnkl/foot/issues/542). ### Security diff --git a/wayland.c b/wayland.c index e1055101..3c0209d4 100644 --- a/wayland.c +++ b/wayland.c @@ -1589,14 +1589,21 @@ void wayl_roundtrip(struct wayland *wayl) { wl_display_cancel_read(wayl->display); - wl_display_roundtrip(wayl->display); + if (wl_display_roundtrip(wayl->display) < 0) { + LOG_ERRNO("failed to roundtrip Wayland display"); + return; + } /* I suspect the roundtrip above clears the pending queue, and * that prepare_read() will always succeed in the first call. But, * better safe than sorry... */ - while (wl_display_prepare_read(wayl->display) != 0) - wl_display_dispatch_pending(wayl->display); + while (wl_display_prepare_read(wayl->display) != 0) { + if (wl_display_dispatch_pending(wayl->display) < 0) { + LOG_ERRNO("failed to dispatch pending Wayland events"); + return; + } + } wayl_flush(wayl); }