summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2019-01-28 18:24:41 +0100
committerMichel Dänzer <michel.daenzer@amd.com>2019-01-28 18:24:41 +0100
commit227123de3d862e691131708b7f55260bee17f2b7 (patch)
treed3f258c04b3247c142e0aaac4cbc81d7ca8c2d48
parent1bfdccf7639ee2f655dc659cafa63830ba28be85 (diff)
Call drmHandleEvent again if it was interrupted by a signal
drmHandleEvent can be interrupted by a signal in read(), in which case it doesn't process any events but returns -1, which drm_handle_event propagated to its callers. This could cause the following failure cascade: 1. drm_wait_pending_flip stopped waiting for a pending flip. 2. Its caller cleared drmmode_crtc->flip_pending before the flip completed. 3. Another flip was attempted but got an unexpected EBUSY error because the previous flip was still pending. 4. TearFree was disabled due to the error. The solution is to call drmHandleEvent if it was interrupted by a signal. We can do that in drm_handle_event, because when that is called, either it is known that there are events ready to be processed, or the caller has to wait for events to arrive anyway. Bugzilla: https://bugs.freedesktop.org/109364 (Ported from amdgpu commit 3ff2cc225f6bc08364ee007fa54e9d0150adaf11)
-rw-r--r--src/radeon_drm_queue.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/radeon_drm_queue.c b/src/radeon_drm_queue.c
index d8a8243c..2e2b8404 100644
--- a/src/radeon_drm_queue.c
+++ b/src/radeon_drm_queue.c
@@ -30,6 +30,8 @@
#include "config.h"
#endif
+#include <errno.h>
+
#include <xorg-server.h>
#include <X11/Xdefs.h>
#include <list.h>
@@ -277,7 +279,20 @@ radeon_drm_handle_event(int fd, drmEventContext *event_context)
struct radeon_drm_queue_entry *e;
int r;
- r = drmHandleEvent(fd, event_context);
+ /* Retry drmHandleEvent if it was interrupted by a signal in read() */
+ do {
+ r = drmHandleEvent(fd, event_context);
+ } while (r < 0 && (errno == EINTR || errno == EAGAIN));
+
+ if (r < 0) {
+ static Bool printed;
+
+ if (!printed) {
+ ErrorF("%s: drmHandleEvent returned %d, errno=%d (%s)\n",
+ __func__, r, errno, strerror(errno));
+ printed = TRUE;
+ }
+ }
while (!xorg_list_is_empty(&radeon_drm_flip_signalled)) {
e = xorg_list_first_entry(&radeon_drm_flip_signalled,