[PATCH weston 1/1] compositor: Abort on bad page flip timestamps

Frederic Plourde frederic.plourde at collabora.co.uk
Wed Nov 5 10:06:23 PST 2014


Many features, like animations, hardly depend on page flip timestamps
to work properly, but some DRM drivers do not correctly support page flip
timestamps (or not at all) and in that case, things start to go wrong.

This patch adds sanity check to weston_output_finish_frame. By solely
verifying that page flip timestamps are monotonically increasing, we
make sure that :

1) Underlying driver is not throwing zeroed-out timestamp series at us.
2) We have not mistakenly jumped backwards because of integer overflow.

If a pathological case is detected, we gracefully exit Weston
with an appropriate exit code to help developers debug their drivers.

This fixes: https://bugs.freedesktop.org/show_bug.cgi?id=79502

Notes:
Based on initial design by Pekka Paalanen <pekka.paalanen at collabora.co.uk>
Depends on "compositor: Return a user-defined exit code"

Signed-off-by: Frederic Plourde <frederic.plourde at collabora.co.uk>
---
 src/compositor.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 src/compositor.h |  1 +
 2 files changed, 47 insertions(+)

diff --git a/src/compositor.c b/src/compositor.c
index ac5bda2..c49b3f9 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -507,6 +507,29 @@ weston_presentation_feedback_present_list(struct wl_list *list,
 						     refresh_nsec, ts, seq);
 }
 
+#define NSEC_PER_SEC 1000000000
+
+static int
+timespec_cmp(const struct timespec *a, const struct timespec *b)
+{
+   assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC);
+   assert(b->tv_nsec >= 0 && b->tv_nsec < NSEC_PER_SEC);
+
+   if (a->tv_sec < b->tv_sec)
+       return -1;
+
+   if (a->tv_sec > b->tv_sec)
+       return 1;
+
+   if (a->tv_nsec < b->tv_nsec)
+       return -1;
+
+   if (a->tv_nsec > b->tv_nsec)
+       return 1;
+
+   return 0;
+}
+
 static void
 surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
 {
@@ -2052,6 +2075,21 @@ weston_compositor_read_input(int fd, uint32_t mask, void *data)
 	return 1;
 }
 
+static void
+weston_output_check_timestamp(struct weston_output *output,
+							  const struct timespec *cur)
+{
+	const struct timespec *prev = &output->last_finish_time;
+
+	if (prev->tv_nsec != -1) {
+		if (timespec_cmp(prev, cur) >= 0) {
+			weston_log("Bad timestamp! Abort Weston! %m\n");
+			weston_compositor_exit_with_code(output->compositor,
+											 EXIT_FAILURE);
+		}
+	}
+}
+
 WL_EXPORT void
 weston_output_finish_frame(struct weston_output *output,
 			   const struct timespec *stamp)
@@ -2062,6 +2100,9 @@ weston_output_finish_frame(struct weston_output *output,
 	int fd, r;
 	uint32_t refresh_nsec;
 
+	weston_output_check_timestamp(output, stamp);
+	output->last_finish_time = *stamp;
+
 	refresh_nsec = 1000000000000UL / output->current_mode->refresh;
 	weston_presentation_feedback_present_list(&output->feedback_list,
 						  output, refresh_nsec, stamp,
@@ -3576,6 +3617,11 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
 	output->dirty = 1;
 	output->original_scale = scale;
 
+	/* We set tv_nsec out of range here to indicate that we have not
+	 * initialized last_finish_time with a page flip event timestamp yet.
+	 */
+	output->last_finish_time.tv_nsec = -1;
+
 	weston_output_transform_scale_init(output, transform, scale);
 	weston_output_init_zoom(output);
 
diff --git a/src/compositor.h b/src/compositor.h
index a8967f0..d8a2985 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -205,6 +205,7 @@ struct weston_output {
 	int move_x, move_y;
 	uint32_t frame_time; /* presentation timestamp in milliseconds */
 	uint64_t msc;        /* media stream counter */
+	struct timespec last_finish_time;
 	int disable_planes;
 	int destroying;
 	struct wl_list feedback_list;
-- 
1.9.1



More information about the wayland-devel mailing list