render: add a timeout for application synchronized updates

This ensures we can recover from a crashing (or bad behaving)
application that sends a BSU but then never sends an ESU.
This commit is contained in:
Daniel Eklöf 2020-01-12 12:40:42 +01:00
parent 6e474e77e5
commit afa1dbb7cc
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 60 additions and 8 deletions

View file

@ -1193,7 +1193,7 @@ fdm_hook_refresh_pending_terminals(struct fdm *fdm, void *data)
if (!term->render.refresh_needed)
continue;
if (term->render.application_synchronized_updates)
if (term->render.application_synchronized_updates.enabled)
continue;
assert(term->window->is_configured);
@ -1244,19 +1244,31 @@ render_refresh(struct terminal *term)
void
render_enable_application_synchronized_updates(struct terminal *term)
{
if (term->render.application_synchronized_updates)
if (term->render.application_synchronized_updates.enabled)
return;
term->render.application_synchronized_updates = true;
term->render.application_synchronized_updates.enabled = true;
if (timerfd_settime(
term->render.application_synchronized_updates.timer_fd, 0,
&(struct itimerspec){.it_value = {.tv_sec = 1}}, NULL) < 0)
{
LOG_ERR("failed to arm timer for application synchronized updates");
}
}
void
render_disable_application_synchronized_updates(struct terminal *term)
{
if (!term->render.application_synchronized_updates)
if (!term->render.application_synchronized_updates.enabled)
return;
term->render.application_synchronized_updates = false;
term->render.application_synchronized_updates.enabled = false;
/* Reset timers */
timerfd_settime(
term->render.application_synchronized_updates.timer_fd, 0,
&(struct itimerspec){{0}}, NULL);
}
bool

View file

@ -186,7 +186,7 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
* has any effect when the renderer is idle.
*/
if (term->window->frame_callback == NULL) {
if (term->render.application_synchronized_updates) {
if (term->render.application_synchronized_updates.enabled) {
timerfd_settime(
term->delayed_render_timer.lower_fd, 0,
&(struct itimerspec){{0}}, NULL);
@ -424,6 +424,29 @@ fdm_delayed_render(struct fdm *fdm, int fd, int events, void *data)
return true;
}
static bool
fdm_application_synchronized_updates_timeout(
struct fdm *fdm, int fd, int events, void *data)
{
if (events & EPOLLHUP)
return false;
struct terminal *term = data;
uint64_t unused;
ssize_t ret = read(term->render.application_synchronized_updates.timer_fd,
&unused, sizeof(unused));
if (ret < 0) {
if (errno == EAGAIN)
return true;
LOG_ERRNO("failed to read application synchronized updates timeout timer");
return false;
}
render_disable_application_synchronized_updates(term);
return true;
}
static void
initialize_color_cube(struct terminal *term)
{
@ -518,6 +541,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
int cursor_blink_fd = -1;
int delay_lower_fd = -1;
int delay_upper_fd = -1;
int application_synchronized_updates_fd = -1;
struct terminal *term = malloc(sizeof(*term));
@ -544,6 +568,12 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
goto close_fds;
}
if ((application_synchronized_updates_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)) == -1)
{
LOG_ERRNO("failed to create application synchronized updates timer FD");
goto close_fds;
}
int ptmx_flags;
if ((ptmx_flags = fcntl(ptmx, F_GETFL)) < 0 ||
fcntl(ptmx, F_SETFL, ptmx_flags | O_NONBLOCK) < 0)
@ -557,7 +587,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
!fdm_add(fdm, blink_fd, EPOLLIN, &fdm_blink, term) ||
!fdm_add(fdm, cursor_blink_fd, EPOLLIN, &fdm_cursor_blink, term) ||
!fdm_add(fdm, delay_lower_fd, EPOLLIN, &fdm_delayed_render, term) ||
!fdm_add(fdm, delay_upper_fd, EPOLLIN, &fdm_delayed_render, term))
!fdm_add(fdm, delay_upper_fd, EPOLLIN, &fdm_delayed_render, term) ||
!fdm_add(fdm, application_synchronized_updates_fd, EPOLLIN, &fdm_application_synchronized_updates_timeout, term))
{
goto err;
}
@ -632,6 +663,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
.wl = wayl,
.render = {
.scrollback_lines = conf->scrollback_lines,
.application_synchronized_updates.timer_fd = application_synchronized_updates_fd,
.workers = {
.count = conf->render_worker_count,
.queue = tll_init(),
@ -707,6 +739,7 @@ close_fds:
fdm_del(fdm, cursor_blink_fd);
fdm_del(fdm, delay_lower_fd);
fdm_del(fdm, delay_upper_fd);
fdm_del(fdm, application_synchronized_updates_fd);
free(term);
return NULL;
@ -767,6 +800,7 @@ term_shutdown(struct terminal *term)
term_cursor_blink_disable(term);
fdm_del(term->fdm, term->render.application_synchronized_updates.timer_fd);
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
fdm_del(term->fdm, term->cursor_blink.fd);
@ -774,6 +808,7 @@ term_shutdown(struct terminal *term)
fdm_del(term->fdm, term->flash.fd);
fdm_del(term->fdm, term->ptmx);
term->render.application_synchronized_updates.timer_fd = -1;
term->delayed_render_timer.lower_fd = -1;
term->delayed_render_timer.upper_fd = -1;
term->cursor_blink.fd = -1;
@ -823,6 +858,7 @@ term_destroy(struct terminal *term)
}
}
fdm_del(term->fdm, term->render.application_synchronized_updates.timer_fd);
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
fdm_del(term->fdm, term->cursor_blink.fd);

View file

@ -292,7 +292,11 @@ struct terminal {
bool refresh_needed; /* Terminal needs to be re-rendered, as soon-as-possible */
int scrollback_lines; /* Number of scrollback lines, from conf (TODO: move out from render struct?) */
bool application_synchronized_updates;
struct {
bool enabled;
int timer_fd;
} application_synchronized_updates;
/* Render threads + synchronization primitives */
struct {
size_t count;