mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
An older submission that returns late must not hide a newer one. Contexts with user-generated timestamps can have gaps, so they keep the failed read instead of waiting once per integer.
152 lines
4.5 KiB
C
152 lines
4.5 KiB
C
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
|
|
#include "../quest/kgsl_compat.h"
|
|
|
|
void bl_kgsl_track(int (*real)(int, unsigned long, void *), int fd, unsigned long request,
|
|
void *arg, int *rc);
|
|
|
|
static int read_error, wait_error, waits;
|
|
static unsigned int retired;
|
|
|
|
static int mock(int fd, unsigned long request, void *arg) {
|
|
assert(fd == 42 || fd == 43);
|
|
if (request == IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID) {
|
|
if (read_error) {
|
|
errno = read_error;
|
|
return -1;
|
|
}
|
|
((struct kgsl_cmdstream_readtimestamp_ctxtid *)arg)->timestamp = retired;
|
|
return 0;
|
|
}
|
|
assert(request == IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID);
|
|
struct kgsl_device_waittimestamp_ctxtid *wait = arg;
|
|
assert(wait->context_id == 3 && wait->timeout != 0);
|
|
waits++;
|
|
if (wait_error) {
|
|
errno = wait_error;
|
|
return -1;
|
|
}
|
|
if (wait->timestamp > retired) {
|
|
errno = ETIMEDOUT;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int issue(unsigned long request, void *arg) {
|
|
int rc = mock(42, request, arg);
|
|
bl_kgsl_track(mock, 42, request, arg, &rc);
|
|
return rc;
|
|
}
|
|
|
|
static void submit(unsigned int timestamp) {
|
|
struct kgsl_gpu_command command = {.context_id = 3, .timestamp = timestamp};
|
|
int rc = 0;
|
|
bl_kgsl_track(mock, 42, IOCTL_KGSL_GPU_COMMAND, &command, &rc);
|
|
assert(rc == 0);
|
|
}
|
|
|
|
static int read_timestamp(unsigned int context, unsigned int *timestamp) {
|
|
struct kgsl_cmdstream_readtimestamp_ctxtid read = {
|
|
.context_id = context, .type = KGSL_TIMESTAMP_RETIRED};
|
|
int rc = issue(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID, &read);
|
|
*timestamp = read.timestamp;
|
|
return rc;
|
|
}
|
|
|
|
static void create_context(unsigned int context) {
|
|
struct kgsl_drawctxt_create create = {.drawctxt_id = context};
|
|
int rc = 0;
|
|
bl_kgsl_track(mock, 42, IOCTL_KGSL_DRAWCTXT_CREATE, &create, &rc);
|
|
}
|
|
|
|
int main(void) {
|
|
unsigned int timestamp;
|
|
|
|
retired = 5;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 5 && waits == 0);
|
|
|
|
read_error = EACCES;
|
|
retired = 0;
|
|
errno = EACCES;
|
|
assert(read_timestamp(3, ×tamp) == -1 && errno == EACCES && waits == 0);
|
|
|
|
create_context(3);
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 0 && waits == 1);
|
|
|
|
wait_error = EINVAL;
|
|
assert(read_timestamp(3, ×tamp) == -1 && errno == EINVAL);
|
|
wait_error = 0;
|
|
|
|
waits = 0;
|
|
read_error = EBADF;
|
|
assert(read_timestamp(3, ×tamp) == -1 && errno == EBADF && waits == 0);
|
|
read_error = EACCES;
|
|
|
|
struct kgsl_cmdstream_readtimestamp_ctxtid other = {.context_id = 3, .type = KGSL_TIMESTAMP_RETIRED};
|
|
int other_rc = mock(43, IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID, &other);
|
|
bl_kgsl_track(mock, 43, IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID, &other, &other_rc);
|
|
assert(other_rc == -1 && errno == EACCES && waits == 0);
|
|
|
|
submit(1);
|
|
submit(2);
|
|
submit(3);
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 0 && waits == 1);
|
|
|
|
retired = 2;
|
|
waits = 0;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 2 && waits == 3);
|
|
|
|
waits = 0;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 2 && waits == 1);
|
|
|
|
retired = 3;
|
|
waits = 0;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 3 && waits == 1);
|
|
|
|
waits = 0;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 3 && waits == 1);
|
|
|
|
wait_error = EINVAL;
|
|
assert(read_timestamp(3, ×tamp) == -1 && errno == EINVAL);
|
|
wait_error = 0;
|
|
|
|
submit(4);
|
|
retired = 4;
|
|
wait_error = EDEADLK;
|
|
assert(read_timestamp(3, ×tamp) == -1 && errno == EDEADLK);
|
|
wait_error = 0;
|
|
|
|
struct kgsl_gpu_aux_command aux = {.context_id = 3, .timestamp = 6};
|
|
int rc = 0;
|
|
bl_kgsl_track(mock, 42, IOCTL_KGSL_GPU_AUX_COMMAND, &aux, &rc);
|
|
retired = 6;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 6);
|
|
|
|
submit(8);
|
|
submit(7);
|
|
retired = 8;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 8);
|
|
|
|
create_context(3);
|
|
retired = 0;
|
|
waits = 0;
|
|
assert(read_timestamp(3, ×tamp) == 0 && timestamp == 0 && waits == 1);
|
|
|
|
struct kgsl_drawctxt_destroy destroy = {.drawctxt_id = 3};
|
|
bl_kgsl_track(mock, 42, IOCTL_KGSL_DRAWCTXT_DESTROY, &destroy, &rc);
|
|
assert(read_timestamp(3, ×tamp) == -1 && errno == EACCES);
|
|
|
|
struct kgsl_drawctxt_create user = {.flags = KGSL_CONTEXT_USER_GENERATED_TS, .drawctxt_id = 3};
|
|
bl_kgsl_track(mock, 42, IOCTL_KGSL_DRAWCTXT_CREATE, &user, &rc);
|
|
waits = 0;
|
|
assert(read_timestamp(3, ×tamp) == -1 && errno == EACCES && waits == 0);
|
|
|
|
errno = EACCES;
|
|
assert(read_timestamp(5000, ×tamp) == -1 && errno == EACCES);
|
|
|
|
puts("PASS: refused timestamp reads answered from retired waits");
|
|
}
|