From 0ea0323d0fb3130e5bc1782812e70993e5cdb742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 3 Jan 2020 21:02:12 +0100 Subject: [PATCH] wayland: don't use wl_display_dispatch() wl_display_dispatch() calls poll(), which is unnecessary since we already know the FD is readable. Use the more lower level wl_display_read_events() + wl_display_dispatch_pending(). These require wl_display_prepare_read() to have been called. The idea is to call wl_display_prepare_read() **before** calling poll(). Thus, we do this more or less last in wayl_init(), and at the **end** of the FDM handler. However, having taking this lock also means we no longer can call wl_display_roundtrip() directly (it will hang). So, add a wrapper, wayl_roundtrip(), that cancels the read intent, does the roundtrip, and then re-acquires the read intent. --- terminal.c | 4 +--- wayland.c | 32 +++++++++++++++++++++++++++----- wayland.h | 2 ++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/terminal.c b/terminal.c index 6d2f7a04..463ceb90 100644 --- a/terminal.c +++ b/terminal.c @@ -659,9 +659,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, /* Let the Wayland backend know we exist */ tll_push_back(wayl->terms, term); - - /* Roundtrip to ensure the wayland window have been configured */ - wl_display_roundtrip(term->wl->display); + wayl_roundtrip(term->wl); term_set_window_title(term, "foot"); diff --git a/wayland.c b/wayland.c index 3d0a7061..abe7329f 100644 --- a/wayland.c +++ b/wayland.c @@ -559,10 +559,17 @@ static bool fdm_wayl(struct fdm *fdm, int fd, int events, void *data) { struct wayland *wayl = data; - int event_count = wl_display_dispatch(wayl->display); + int event_count = 0; + + if (events & EPOLLIN) + wl_display_read_events(wayl->display); + + while (wl_display_prepare_read(wayl->display) != 0) + wl_display_dispatch_pending(wayl->display); if (events & EPOLLHUP) { LOG_WARN("disconnected from Wayland"); + wl_display_cancel_read(wayl->display); return false; } @@ -711,6 +718,11 @@ wayl_init(const struct config *conf, struct fdm *fdm) goto out; } + if (wl_display_prepare_read(wayl->display) != 0) { + LOG_ERRNO("failed to prepare for reading wayland events"); + goto out; + } + if (!fdm_add(fdm, wl_display_get_fd(wayl->display), EPOLLIN, &fdm_wayl, wayl) || !fdm_add(fdm, wayl->kbd.repeat.fd, EPOLLIN, &fdm_repeat, wayl)) { @@ -889,12 +901,12 @@ wayl_win_destroy(struct wl_window *win) /* Scrollback search */ wl_surface_attach(win->search_surface, NULL, 0, 0); wl_surface_commit(win->search_surface); - wl_display_roundtrip(win->term->wl->display); + wayl_roundtrip(win->term->wl); /* Main window */ wl_surface_attach(win->surface, NULL, 0, 0); wl_surface_commit(win->surface); - wl_display_roundtrip(win->term->wl->display); + wayl_roundtrip(win->term->wl); tll_free(win->on_outputs); if (win->search_sub_surface != NULL) @@ -912,8 +924,7 @@ wayl_win_destroy(struct wl_window *win) if (win->surface != NULL) wl_surface_destroy(win->surface); - wl_display_roundtrip(win->term->wl->display); - + wayl_roundtrip(win->term->wl); free(win); } @@ -1006,3 +1017,14 @@ wayl_terminal_from_surface(struct wayland *wayl, struct wl_surface *surface) LOG_WARN("surface %p doesn't map to a terminal", surface); return NULL; } + +void +wayl_roundtrip(struct wayland *wayl) +{ + wl_display_cancel_read(wayl->display); + wl_display_roundtrip(wayl->display); + + while (wl_display_prepare_read(wayl->display) != 0) + wl_display_dispatch_pending(wayl->display); + wl_display_flush(wayl->display); +} diff --git a/wayland.h b/wayland.h index fd0c36e2..eda9e009 100644 --- a/wayland.h +++ b/wayland.h @@ -178,6 +178,8 @@ struct wayland { struct wayland *wayl_init(const struct config *conf, struct fdm *fdm); void wayl_destroy(struct wayland *wayl); +void wayl_roundtrip(struct wayland *wayl); + struct terminal *wayl_terminal_from_surface( struct wayland *wayl, struct wl_surface *surface);