mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
wayland: wl_display_flush() never blocks
Since it doesn't block, we need to detect EAGAIN failures and ensure we actually flush everything. If we don't, we sooner or later end up in a wayland client library call that aborts due to the socket buffer being full. Ideally, we'd simply enable POLLOUT in the FDM. However, we cannot write *anything* to the wayland socket until we've actually managed to send everything. This means enabling POLLOUT in the FDM wont work since we may (*will*) end up trying to write more data to it before we've flushed it. So, add a wrapper function, wayl_flush(), that acts as a blocking variant of wl_display_flush(), by detecting EAGAIN failiures and calling poll() itself, on the wayland socket only, until all data has been sent.
This commit is contained in:
parent
2128d5912f
commit
abc36d8f09
3 changed files with 46 additions and 4 deletions
2
render.c
2
render.c
|
|
@ -867,7 +867,7 @@ grid_render(struct terminal *term)
|
|||
}
|
||||
|
||||
wl_surface_commit(term->window->surface);
|
||||
wl_display_flush(term->wl->display);
|
||||
wayl_flush(term->wl);
|
||||
|
||||
#if TIME_FRAME_RENDERING
|
||||
struct timeval end_time;
|
||||
|
|
|
|||
47
wayland.c
47
wayland.c
|
|
@ -4,6 +4,7 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/epoll.h>
|
||||
|
|
@ -573,7 +574,7 @@ fdm_wayl(struct fdm *fdm, int fd, int events, void *data)
|
|||
return false;
|
||||
}
|
||||
|
||||
wl_display_flush(wayl->display);
|
||||
wayl_flush(wayl);
|
||||
return event_count != -1;
|
||||
}
|
||||
|
||||
|
|
@ -983,7 +984,7 @@ wayl_cursor_set(struct wayland *wayl, const struct terminal *term)
|
|||
|
||||
wl_surface_set_buffer_scale(wayl->pointer.surface, scale);
|
||||
wl_surface_commit(wayl->pointer.surface);
|
||||
wl_display_flush(wayl->display);
|
||||
wayl_flush(wayl);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1029,6 +1030,46 @@ wayl_terminal_from_surface(struct wayland *wayl, struct wl_surface *surface)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wayl_flush(struct wayland *wayl)
|
||||
{
|
||||
while (true) {
|
||||
int r = wl_display_flush(wayl->display);
|
||||
if (r >= 0)
|
||||
return;
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno != EAGAIN) {
|
||||
LOG_ERRNO("failed to flush wayland socket");
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd fds[] = {
|
||||
{.fd = wl_display_get_fd(wayl->display), .events = POLLOUT}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
r = poll(fds, sizeof(fds) / sizeof(fds[0]), -1);
|
||||
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
LOG_ERRNO("failed to poll");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fds[0].revents & POLLHUP)
|
||||
return;
|
||||
|
||||
assert(fds[0].revents & POLLOUT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wayl_roundtrip(struct wayland *wayl)
|
||||
{
|
||||
|
|
@ -1037,5 +1078,5 @@ wayl_roundtrip(struct wayland *wayl)
|
|||
|
||||
while (wl_display_prepare_read(wayl->display) != 0)
|
||||
wl_display_dispatch_pending(wayl->display);
|
||||
wl_display_flush(wayl->display);
|
||||
wayl_flush(wayl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ struct wayland {
|
|||
struct wayland *wayl_init(const struct config *conf, struct fdm *fdm);
|
||||
void wayl_destroy(struct wayland *wayl);
|
||||
|
||||
void wayl_flush(struct wayland *wayl);
|
||||
void wayl_roundtrip(struct wayland *wayl);
|
||||
|
||||
struct terminal *wayl_terminal_from_surface(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue