libdrm: add timeout handling to drmWaitVBlank
In some cases, vblank interrupts may be disabled or otherwise broken. The kernel has a 3s timeout builtin to handle these cases, but the X server's SIGALM for cursor handling may interrupt vblank wait ioctls, causing libdrm to restart the ioctl, making the kernel's timeout useless. This change tracks time across ioctl restarts and returns EBUSY to the caller if the expected vblank sequence doesn't occur within 1s of the first call. Fixes fdo bz #18041, which is caused by a drmWaitVBlank hanging due to the corresponding pipe getting disabled (thus preventing further events from coming in).main
parent
a8c548034e
commit
f4f76a6894
|
@ -23,6 +23,7 @@ SUBDIRS = . intel
|
||||||
libdrm_la_LTLIBRARIES = libdrm.la
|
libdrm_la_LTLIBRARIES = libdrm.la
|
||||||
libdrm_ladir = $(libdir)
|
libdrm_ladir = $(libdir)
|
||||||
libdrm_la_LDFLAGS = -version-number 2:4:0 -no-undefined
|
libdrm_la_LDFLAGS = -version-number 2:4:0 -no-undefined
|
||||||
|
libdrm_la_LIBADD = -lrt
|
||||||
|
|
||||||
AM_CFLAGS = -I$(top_srcdir)/shared-core
|
AM_CFLAGS = -I$(top_srcdir)/shared-core
|
||||||
libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c \
|
libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c \
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#define stat_t struct stat
|
#define stat_t struct stat
|
||||||
|
@ -1896,13 +1897,30 @@ int drmScatterGatherFree(int fd, drm_handle_t handle)
|
||||||
*/
|
*/
|
||||||
int drmWaitVBlank(int fd, drmVBlankPtr vbl)
|
int drmWaitVBlank(int fd, drmVBlankPtr vbl)
|
||||||
{
|
{
|
||||||
|
struct timespec timeout, cur;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "clock_gettime failed: %s\n", strerror(ret));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
timeout.tv_sec++;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = drmIoctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
|
ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
|
||||||
vbl->request.type &= ~DRM_VBLANK_RELATIVE;
|
vbl->request.type &= ~DRM_VBLANK_RELATIVE;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &cur);
|
||||||
|
/* Timeout after 1s */
|
||||||
|
if (cur.tv_sec > timeout.tv_sec + 1 ||
|
||||||
|
cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= timeout.tv_nsec) {
|
||||||
|
errno = EBUSY;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} while (ret && errno == EINTR);
|
} while (ret && errno == EINTR);
|
||||||
|
|
||||||
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue