sna/present: Restrict vblank.sequence range to 31bits

The kernel checks for past vblanks using an int32_t comparison, so we
can only program up to 31bits into the future (and similarly programing
a timer that large would also overflow).

References: https://bugs.freedesktop.org/show_bug.cgi?id=94685
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2016-03-24 18:22:20 +00:00
parent 4e108afe55
commit c186d4dda3
2 changed files with 89 additions and 4 deletions

View File

@ -114,8 +114,10 @@ static void vblank_complete(struct sna_present_event *info,
int n;
if (msc < info->target_msc) {
DBG(("%s: %d too early, now %lld, expected %lld\n",
__FUNCTION__, (long long)msc, (long long)info->target_msc));
DBG(("%s: event=%d too early, now %lld, expected %lld\n",
__FUNCTION__,
info->event_id[0],
(long long)msc, (long long)info->target_msc));
if (sna_present_queue(info, msc))
return;
}
@ -247,7 +249,7 @@ static bool sna_present_queue(struct sna_present_event *info,
(long long)info->target_msc,
(unsigned)info->target_msc,
(long long)last_msc));
assert(info->target_msc - last_msc < 1ull<<32);
assert(info->target_msc - last_msc < 1ull<<31);
VG_CLEAR(vbl);
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
@ -360,7 +362,7 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
present_event_notify(event_id, swap_ust(swap), swap->msc);
return Success;
}
if (warn_unless(msc - swap->msc < 1ull<<32))
if (warn_unless(msc - swap->msc < 1ull<<31))
return BadValue;
list_for_each_entry(tmp, &sna->present.vblank_queue, link) {

View File

@ -1089,6 +1089,86 @@ static int test_future_msc(Display *dpy, void *Q)
return ret;
}
static int test_wrap_msc(Display *dpy)
{
xcb_connection_t *c = XGetXCBConnection(dpy);
Window root, win;
int x, y;
unsigned int width, height;
unsigned border, depth;
XSetWindowAttributes attr;
int ret = 0, n;
uint64_t msc, ust;
int complete;
uint64_t interval;
void *Q;
XGetGeometry(dpy, DefaultRootWindow(dpy),
&root, &x, &y, &width, &height, &border, &depth);
attr.override_redirect = 1;
win = XCreateWindow(dpy, root,
0, 0, width, height, 0, depth,
InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)),
CWOverrideRedirect, &attr);
XMapWindow(dpy, win);
XSync(dpy, True);
if (_x_error_occurred)
return 1;
printf("Testing wraparound notifies\n");
_x_error_occurred = 0;
Q = setup_msc(dpy, win);
interval = msc_interval(dpy, win, Q);
if (interval == 0) {
printf("Zero delay between frames\n");
return 1;
}
msc = check_msc(dpy, win, Q, 0, &ust);
printf("Initial msc=%llx, interval between frames %lldus\n",
(long long)msc, (long long)interval);
for (n = 1; n <= 10; n++)
xcb_present_notify_msc(c, win, n,
msc + ((long long)n<<32) + n,
0, 0);
for (n = 1; n <= 10; n++)
xcb_present_notify_msc(c, win, -n,
0, (long long)n << 32, 0);
xcb_present_notify_msc(c, win, 0xdeadbeef, msc + 60*10, 0, 0);
xcb_flush(c);
complete = 0;
do {
xcb_present_complete_notify_event_t *ce;
xcb_generic_event_t *ev;
ev = xcb_wait_for_special_event(c, Q);
if (ev == NULL)
break;
ce = (xcb_present_complete_notify_event_t *)ev;
assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
if (ce->serial == 0xdeadbeef) {
complete = 1;
} else {
fprintf(stderr,
"\tnotify %d recieved at +%llu\n",
ce->serial, ce->msc - msc);
ret++;
}
free(ev);
} while (!complete);
teardown_msc(dpy, Q);
XDestroyWindow(dpy, win);
XSync(dpy, True);
return ret;
}
static int test_exhaustion_msc(Display *dpy, void *Q)
{
#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
@ -2019,6 +2099,9 @@ int main(void)
error += test_future_msc(dpy, queue);
last_msc = check_msc(dpy, root, queue, last_msc, NULL);
error += test_wrap_msc(dpy);
last_msc = check_msc(dpy, root, queue, last_msc, NULL);
error += test_accuracy_msc(dpy, queue);
last_msc = check_msc(dpy, root, queue, last_msc, NULL);