diff --git a/tools/quest/kgsl_compat.c b/tools/quest/kgsl_compat.c index f2c9e58b1..e834062e0 100644 --- a/tools/quest/kgsl_compat.c +++ b/tools/quest/kgsl_compat.c @@ -31,11 +31,12 @@ static void report(const char *operation, int error) { } struct tracked_context { - unsigned int context, queued, retired; + unsigned int context, queued, retired, generation; }; static struct tracked_context *tracked; static unsigned int tracked_count, tracked_capacity; +static unsigned int next_generation; static char tracked_lock; static void tracked_acquire(void) { @@ -65,6 +66,7 @@ static int tracked_find(unsigned int context, int create) { } tracked[free_slot].context = context; tracked[free_slot].queued = tracked[free_slot].retired = 0; + tracked[free_slot].generation = ++next_generation; return free_slot; } @@ -92,6 +94,7 @@ static int read_timestamp(quest_ioctl_fn real, int fd, struct kgsl_cmdstream_rea int slot = tracked_find(query->context_id, 0); unsigned int queued = slot < 0 ? 0 : tracked[slot].queued; unsigned int retired = slot < 0 ? 0 : tracked[slot].retired; + unsigned int generation = slot < 0 ? 0 : tracked[slot].generation; tracked_release(); if (slot < 0 || (query->type != KGSL_TIMESTAMP_RETIRED && query->type != KGSL_TIMESTAMP_QUEUED)) { errno = EACCES; @@ -105,7 +108,8 @@ static int read_timestamp(quest_ioctl_fn real, int fd, struct kgsl_cmdstream_rea retired = queued; tracked_acquire(); slot = tracked_find(query->context_id, 0); - if (slot >= 0 && (int)(retired - tracked[slot].retired) > 0) tracked[slot].retired = retired; + if (slot >= 0 && tracked[slot].generation == generation && + (int)(retired - tracked[slot].retired) > 0) tracked[slot].retired = retired; tracked_release(); } else if (errno != ETIMEDOUT) { return -1; diff --git a/tools/quest/test_kgsl_compat.c b/tools/quest/test_kgsl_compat.c index a44bd80a6..36aa240c2 100644 --- a/tools/quest/test_kgsl_compat.c +++ b/tools/quest/test_kgsl_compat.c @@ -45,6 +45,7 @@ static struct kgsl_gpumem_alloc_id reset(void) { } static int read_error, wait_error, waits; static unsigned int waited_for; +static void (*during_wait)(void); static int timestamp_mock(int fd, unsigned long request, void *arg) { assert(fd == 42); if (request == IOCTL_KGSL_GPU_COMMAND || request == IOCTL_KGSL_DRAWCTXT_DESTROY) return 0; @@ -57,6 +58,7 @@ static int timestamp_mock(int fd, unsigned long request, void *arg) { assert(w->timeout == 0); waits++; waited_for = w->timestamp; + if (during_wait) during_wait(); if (wait_error) { errno = wait_error; return -1; } return 0; } @@ -73,6 +75,13 @@ static int read_ts(unsigned int context, unsigned int type, unsigned int *timest *timestamp = q.timestamp; return rc; } +static void submit(unsigned int context, unsigned int timestamp); +static void recreate_context(void) { + struct kgsl_drawctxt_destroy gone = {.drawctxt_id = 8}; + during_wait = NULL; + assert(quest_kgsl_ioctl(timestamp_mock, 42, IOCTL_KGSL_DRAWCTXT_DESTROY, &gone) == 0); + submit(8, 20); +} static void timestamp_scenarios(void) { unsigned int ts; read_error = EACCES; @@ -99,6 +108,13 @@ static void timestamp_scenarios(void) { assert(read_ts(5, KGSL_TIMESTAMP_QUEUED, &ts) == -1 && errno == EACCES); for (unsigned int c = 100; c < 100 + 129; c++) submit(c, c); for (unsigned int c = 100; c < 100 + 129; c++) assert(read_ts(c, KGSL_TIMESTAMP_QUEUED, &ts) == 0 && ts == c); + submit(8, 5); + during_wait = recreate_context; + assert(read_ts(8, KGSL_TIMESTAMP_RETIRED, &ts) == 0 && ts == 5); + wait_error = ETIMEDOUT; + assert(read_ts(8, KGSL_TIMESTAMP_RETIRED, &ts) == 0 && ts == 0 && waited_for == 20); + wait_error = 0; + assert(read_ts(8, KGSL_TIMESTAMP_RETIRED, &ts) == 0 && ts == 20); read_error = EIO; submit(6, 3); assert(read_ts(6, KGSL_TIMESTAMP_QUEUED, &ts) == -1 && errno == EIO);