From 459d138fa2f8c0ad3665cbbb393c366b895a4cde Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 23 Sep 2017 16:32:25 +1200 Subject: [PATCH] Add timeout to DRM cleanup This prevents a potential infinite loop preventing us from closing properly. --- backend/drm/backend.c | 3 ++ backend/drm/drm.c | 65 ++++++++++++++++++++++++++----------------- include/backend/drm.h | 5 ++-- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 68e73268..8d562007 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -26,6 +26,9 @@ static void wlr_drm_backend_destroy(struct wlr_backend *_backend) { return; } struct wlr_drm_backend *backend = (struct wlr_drm_backend *)_backend; + + wlr_drm_restore_outputs(backend); + for (size_t i = 0; backend->outputs && i < backend->outputs->length; ++i) { struct wlr_drm_output *output = backend->outputs->items[i]; wlr_output_destroy(&output->output); diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 5c0bad46..b34e86fd 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -556,7 +557,7 @@ error_enc: error_conn: drmModeFreeConnector(conn); error_output: - wlr_drm_output_cleanup(output, false); + wlr_drm_output_cleanup(output); return false; } @@ -703,7 +704,7 @@ static bool wlr_drm_output_move_cursor(struct wlr_output *_output, static void wlr_drm_output_destroy(struct wlr_output *_output) { struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - wlr_drm_output_cleanup(output, true); + wlr_drm_output_cleanup(output); free(output); } @@ -852,7 +853,7 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { conn->connection != DRM_MODE_CONNECTED) { wlr_log(L_INFO, "'%s' disconnected", output->output.name); - wlr_drm_output_cleanup(output, false); + wlr_drm_output_cleanup(output); } drmModeFreeConnector(conn); @@ -868,7 +869,7 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { struct wlr_drm_output *output = backend->outputs->items[i]; wlr_log(L_INFO, "'%s' disappeared", output->output.name); - wlr_drm_output_cleanup(output, false); + wlr_drm_output_cleanup(output); drmModeFreeCrtc(output->old_crtc); free(output); @@ -909,23 +910,46 @@ int wlr_drm_event(int fd, uint32_t mask, void *data) { return 1; } -static void restore_output(struct wlr_drm_output *output, int fd) { - // Wait for any pending pageflips to finish - while (output->pageflip_pending) { - wlr_drm_event(fd, 0, NULL); +void wlr_drm_restore_outputs(struct wlr_drm_backend *drm) { + uint64_t to_close = (1 << drm->outputs->length) - 1; + + for (size_t i = 0; i < drm->outputs->length; ++i) { + struct wlr_drm_output *output = drm->outputs->items[i]; + if (output->state == WLR_DRM_OUTPUT_CONNECTED) { + output->state = WLR_DRM_OUTPUT_CLEANUP; + } } - drmModeCrtc *crtc = output->old_crtc; - if (!crtc) { - return; + time_t timeout = time(NULL) + 5; + + while (to_close && time(NULL) < timeout) { + wlr_drm_event(drm->fd, 0, NULL); + for (size_t i = 0; i < drm->outputs->length; ++i) { + struct wlr_drm_output *output = drm->outputs->items[i]; + if (!output->pageflip_pending) { + to_close &= ~(1 << i); + } + } } - drmModeSetCrtc(fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, - &output->connector, 1, &crtc->mode); - drmModeFreeCrtc(crtc); + if (to_close) { + wlr_log(L_ERROR, "Timed out stopping output renderers"); + } + + for (size_t i = 0; i < drm->outputs->length; ++i) { + struct wlr_drm_output *output = drm->outputs->items[i]; + drmModeCrtc *crtc = output->old_crtc; + if (!crtc) { + continue; + } + + drmModeSetCrtc(drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, + &output->connector, 1, &crtc->mode); + drmModeFreeCrtc(crtc); + } } -void wlr_drm_output_cleanup(struct wlr_drm_output *output, bool restore) { +void wlr_drm_output_cleanup(struct wlr_drm_output *output) { if (!output) { return; } @@ -936,12 +960,7 @@ void wlr_drm_output_cleanup(struct wlr_drm_output *output, bool restore) { switch (output->state) { case WLR_DRM_OUTPUT_CONNECTED: - output->state = WLR_DRM_OUTPUT_DISCONNECTED; - if (restore) { - restore_output(output, renderer->fd); - restore = false; - } - + case WLR_DRM_OUTPUT_CLEANUP:; struct wlr_drm_crtc *crtc = output->crtc; for (int i = 0; i < 3; ++i) { wlr_drm_plane_renderer_free(renderer, crtc->planes[i]); @@ -955,10 +974,6 @@ void wlr_drm_output_cleanup(struct wlr_drm_output *output, bool restore) { output->possible_crtc = 0; /* Fallthrough */ case WLR_DRM_OUTPUT_NEEDS_MODESET: - output->state = WLR_DRM_OUTPUT_DISCONNECTED; - if (restore) { - restore_output(output, renderer->fd); - } wlr_log(L_INFO, "Emmiting destruction signal for '%s'", output->output.name); wl_signal_emit(&backend->backend.events.output_remove, &output->output); diff --git a/include/backend/drm.h b/include/backend/drm.h index 342a980c..cc3e621b 100644 --- a/include/backend/drm.h +++ b/include/backend/drm.h @@ -127,6 +127,7 @@ struct wlr_drm_backend { enum wlr_drm_output_state { WLR_DRM_OUTPUT_DISCONNECTED, WLR_DRM_OUTPUT_NEEDS_MODESET, + WLR_DRM_OUTPUT_CLEANUP, WLR_DRM_OUTPUT_CONNECTED, }; @@ -176,8 +177,8 @@ struct wlr_drm_interface { bool wlr_drm_check_features(struct wlr_drm_backend *drm); bool wlr_drm_resources_init(struct wlr_drm_backend *drm); void wlr_drm_resources_free(struct wlr_drm_backend *drm); -void wlr_drm_output_cleanup(struct wlr_drm_output *output, bool restore); - +void wlr_drm_restore_outputs(struct wlr_drm_backend *drm); +void wlr_drm_output_cleanup(struct wlr_drm_output *output); void wlr_drm_scan_connectors(struct wlr_drm_backend *state); int wlr_drm_event(int fd, uint32_t mask, void *data);