term_shutdown(): cleanup

* Close FDs, then delay destruction to next epoll() call
* Destroy window before destroying terminal
This commit is contained in:
Daniel Eklöf 2019-11-01 20:30:58 +01:00
parent c824aa2ef5
commit 70b236d66d
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

View file

@ -468,77 +468,53 @@ close_fds:
return NULL; return NULL;
} }
static void
close_fd(struct terminal *term, int *fd)
{
if (*fd == -1)
return;
fdm_del(term->fdm, *fd);
close(*fd);
*fd = -1;
}
static void
close_fds(struct terminal *term)
{
close_fd(term, &term->delayed_render_timer.lower_fd);
close_fd(term, &term->delayed_render_timer.upper_fd);
close_fd(term, &term->blink.fd);
close_fd(term, &term->flash.fd);
close_fd(term, &term->ptmx);
}
static bool static bool
fdm_shutdown(struct fdm *fdm, int fd, int events, void *data) fdm_shutdown(struct fdm *fdm, int fd, int events, void *data)
{ {
LOG_DBG("FDM shutdown"); LOG_DBG("FDM shutdown");
struct terminal *term = data; struct terminal *term = data;
struct wayland *wayl = term->wl;
/* Kill the event FD */
fdm_del(term->fdm, fd); fdm_del(term->fdm, fd);
close(fd);
/* wayl_win_destroy(term->window);
* Now there shouldn't be any more callbacks or events that can term->window = NULL;
* trigger, meaning it should be safe to destroy the terminal.
*/
struct wayland *wayl __attribute__((unused)) = term->wl;
assert(wayl->focused != term); assert(wayl->focused != term);
assert(wayl->moused != term); assert(wayl->moused != term);
tll_foreach(wayl->terms, it) {
if (it->item == term) {
tll_remove(wayl->terms, it);
break;
}
}
wayl->last_exit_value = term_destroy(term); int exit_code = term_destroy(term);
return true; return true;
} }
bool bool
term_shutdown(struct terminal *term) term_shutdown(struct terminal *term)
{ {
/* Ensure we don't get any more events */ if (term->is_shutting_down)
close_fds(term); return true;
/* Destroy the wayland window, and consume the trail of Wayland events */ term->is_shutting_down = true;
wayl_win_destroy(term->window);
wl_display_roundtrip(term->wl->display);
term->window = NULL;
/* /*
* At this point, we no longer receive any more events referring to us, and it _should_ be safe to destroy ourselves now. * Close FDs then postpone self-destruction to the next poll
* * iteration, by creating an event FD that we trigger immediately.
* However, in the (unlikely) event that there are events already
* queued up by the FDM, we delay the self-destruction to the next
* FDM poll iteration.
*
* This is done by opening an event FD and adding it to the FDM.
*/ */
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->blink.fd);
fdm_del(term->fdm, term->flash.fd);
fdm_del(term->fdm, term->ptmx);
term->delayed_render_timer.lower_fd = -1;
term->delayed_render_timer.upper_fd = -1;
term->blink.fd = -1;
term->flash.fd = -1;
term->ptmx = -1;
int event_fd = eventfd(0, EFD_CLOEXEC); int event_fd = eventfd(0, EFD_CLOEXEC);
if (event_fd == -1) { if (event_fd == -1) {
LOG_ERRNO("failed to create terminal shutdown event FD"); LOG_ERRNO("failed to create terminal shutdown event FD");
@ -554,7 +530,6 @@ term_shutdown(struct terminal *term)
if (write(event_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) { if (write(event_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) {
LOG_ERRNO("failed to send terminal shutdown event"); LOG_ERRNO("failed to send terminal shutdown event");
fdm_del(term->fdm, event_fd); fdm_del(term->fdm, event_fd);
close(event_fd);
return false; return false;
} }
@ -567,7 +542,18 @@ term_destroy(struct terminal *term)
if (term == NULL) if (term == NULL)
return 0; return 0;
close_fds(term); tll_foreach(term->wl->terms, it) {
if (it->item == term) {
tll_remove(term->wl->terms, it);
break;
}
}
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->blink.fd);
fdm_del(term->fdm, term->flash.fd);
fdm_del(term->fdm, term->ptmx);
if (term->window != NULL) if (term->window != NULL)
wayl_win_destroy(term->window); wayl_win_destroy(term->window);