diff options
author | Eric Anholt <eric@anholt.net> | 2017-09-18 17:34:31 -0700 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2017-09-20 13:19:27 -0400 |
commit | 5cbfa276541e6a621cf9c4b44b75323e90a5bd4c (patch) | |
tree | 78e9a981ba06256da970e971f5eaaca44a9abbf8 | |
parent | 3336291fc68444ee65b48ba675ec947e505fed57 (diff) |
test: Add basic SYNC tests.
I couldn't find any, and I was modifying the implementation, so I had
to write some. I would like the test to end with a "make sure there
weren't any stray unchecked errors", but I didn't figure out how to do
that.
v2: Extend sync tests to cover alarm delta and waitvalue changes.
Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Keith Packard <keithp@keithp.com>
-rw-r--r-- | hw/vfb/meson.build | 2 | ||||
-rw-r--r-- | test/meson.build | 2 | ||||
-rw-r--r-- | test/sync/meson.build | 9 | ||||
-rw-r--r-- | test/sync/sync.c | 304 |
4 files changed, 316 insertions, 1 deletions
diff --git a/hw/vfb/meson.build b/hw/vfb/meson.build index 6566b4590..89acdfacd 100644 --- a/hw/vfb/meson.build +++ b/hw/vfb/meson.build @@ -4,7 +4,7 @@ srcs = [ '../../mi/miinitext.c', ] -executable( +xvfb_server = executable( 'Xvfb', srcs, include_directories: inc, diff --git a/test/meson.build b/test/meson.build index b71d7e249..3e482d6f1 100644 --- a/test/meson.build +++ b/test/meson.build @@ -22,3 +22,5 @@ if get_option('xvfb') ) endif endif + +subdir('sync') diff --git a/test/sync/meson.build b/test/sync/meson.build new file mode 100644 index 000000000..dfae75b1e --- /dev/null +++ b/test/sync/meson.build @@ -0,0 +1,9 @@ +xcb_dep = dependency('xcb', required: false) +xcb_sync_dep = dependency('xcb-sync', required: false) + +if get_option('xvfb') + if xcb_dep.found() and xcb_sync_dep.found() + sync = executable('sync', 'sync.c', dependencies: [xcb_dep, xcb_sync_dep]) + test('sync', simple_xinit, args: [sync, '--', xvfb_server]) + endif +endif diff --git a/test/sync/sync.c b/test/sync/sync.c new file mode 100644 index 000000000..f25d3fa37 --- /dev/null +++ b/test/sync/sync.c @@ -0,0 +1,304 @@ +/* + * Copyright © 2017 Broadcom + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <xcb/sync.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static const int64_t some_values[] = { + 0, + 1, + -1, + LLONG_MAX, + LLONG_MIN, +}; + +static int64_t +pack_sync_value(xcb_sync_int64_t val) +{ + return ((int64_t)val.hi << 32) | val.lo; +} + +static int64_t +counter_value(struct xcb_connection_t *c, + xcb_sync_query_counter_cookie_t cookie) +{ + xcb_sync_query_counter_reply_t *reply = + xcb_sync_query_counter_reply(c, cookie, NULL); + int64_t value = pack_sync_value(reply->counter_value); + + free(reply); + return value; +} + +static xcb_sync_int64_t +sync_value(int64_t value) +{ + xcb_sync_int64_t v = { + .hi = value >> 32, + .lo = value, + }; + + return v; +} + +/* Initializes counters with a bunch of interesting values and makes + * sure it comes back the same. + */ +static void +test_create_counter(xcb_connection_t *c) +{ + xcb_sync_query_counter_cookie_t queries[ARRAY_SIZE(some_values)]; + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + xcb_sync_counter_t counter = xcb_generate_id(c); + xcb_sync_create_counter(c, counter, sync_value(some_values[i])); + queries[i] = xcb_sync_query_counter_unchecked(c, counter); + } + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + int64_t value = counter_value(c, queries[i]); + + if (value != some_values[i]) { + fprintf(stderr, "Creating counter with %lld returned %lld\n", + (long long)some_values[i], + (long long)value); + exit(1); + } + } +} + +/* Set a single counter to a bunch of interesting values and make sure + * it comes the same. + */ +static void +test_set_counter(xcb_connection_t *c) +{ + xcb_sync_counter_t counter = xcb_generate_id(c); + xcb_sync_query_counter_cookie_t queries[ARRAY_SIZE(some_values)]; + + xcb_sync_create_counter(c, counter, sync_value(0)); + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + xcb_sync_set_counter(c, counter, sync_value(some_values[i])); + queries[i] = xcb_sync_query_counter_unchecked(c, counter); + } + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + int64_t value = counter_value(c, queries[i]); + + if (value != some_values[i]) { + fprintf(stderr, "Setting counter to %lld returned %lld\n", + (long long)some_values[i], + (long long)value); + exit(1); + } + } +} + +/* Add [0, 1, 2, 3] to a counter and check that the values stick. */ +static void +test_change_counter_basic(xcb_connection_t *c) +{ + int iterations = 4; + xcb_sync_query_counter_cookie_t queries[iterations]; + + xcb_sync_counter_t counter = xcb_generate_id(c); + xcb_sync_create_counter(c, counter, sync_value(0)); + + for (int i = 0; i < iterations; i++) { + xcb_sync_change_counter(c, counter, sync_value(i)); + queries[i] = xcb_sync_query_counter_unchecked(c, counter); + } + + int64_t expected_value = 0; + for (int i = 0; i < iterations; i++) { + expected_value += i; + int64_t value = counter_value(c, queries[i]); + + if (value != expected_value) { + fprintf(stderr, "Adding %d to counter expected %lld returned %lld\n", + i, + (long long)expected_value, + (long long)value); + exit(1); + } + } +} + +/* Test change_counter where we trigger an integer overflow. */ +static void +test_change_counter_overflow(xcb_connection_t *c) +{ + int iterations = 4; + xcb_sync_query_counter_cookie_t queries[iterations]; + xcb_void_cookie_t changes[iterations]; + static const struct { + int64_t a, b; + } overflow_args[] = { + { LLONG_MAX, 1 }, + { LLONG_MAX, LLONG_MAX }, + { LLONG_MIN, -1 }, + { LLONG_MIN, LLONG_MIN }, + }; + + xcb_sync_counter_t counter = xcb_generate_id(c); + xcb_sync_create_counter(c, counter, sync_value(0)); + + for (int i = 0; i < ARRAY_SIZE(overflow_args); i++) { + int64_t a = overflow_args[i].a; + int64_t b = overflow_args[i].b; + xcb_sync_set_counter(c, counter, sync_value(a)); + changes[i] = xcb_sync_change_counter_checked(c, counter, + sync_value(b)); + queries[i] = xcb_sync_query_counter(c, counter); + } + + for (int i = 0; i < ARRAY_SIZE(overflow_args); i++) { + int64_t a = overflow_args[i].a; + int64_t b = overflow_args[i].b; + xcb_sync_query_counter_reply_t *reply = + xcb_sync_query_counter_reply(c, queries[i], NULL); + int64_t value = (((int64_t)reply->counter_value.hi << 32) | + reply->counter_value.lo); + int64_t expected_value = a; + + /* The change_counter should have thrown BadValue */ + xcb_generic_error_t *e = xcb_request_check(c, changes[i]); + if (!e) { + fprintf(stderr, "(%lld + %lld) failed to return an error\n", + (long long)a, + (long long)b); + exit(1); + } + + if (e->error_code != XCB_VALUE) { + fprintf(stderr, "(%lld + %lld) returned %d, not BadValue\n", + (long long)a, + (long long)b, + e->error_code); + exit(1); + } + + /* The change_counter should have had no other effect if it + * errored out. + */ + if (value != expected_value) { + fprintf(stderr, "(%lld + %lld) expected %lld returned %lld\n", + (long long)a, + (long long)b, + (long long)expected_value, + (long long)value); + exit(1); + } + + free(e); + free(reply); + } +} + +static void +test_change_alarm_value(xcb_connection_t *c) +{ + xcb_sync_alarm_t alarm = xcb_generate_id(c); + xcb_sync_query_alarm_cookie_t queries[ARRAY_SIZE(some_values)]; + + xcb_sync_create_alarm(c, alarm, 0, NULL); + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + uint32_t values[] = { some_values[i] >> 32, some_values[i] }; + + xcb_sync_change_alarm(c, alarm, XCB_SYNC_CA_VALUE, values); + queries[i] = xcb_sync_query_alarm_unchecked(c, alarm); + } + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + xcb_sync_query_alarm_reply_t *reply = + xcb_sync_query_alarm_reply(c, queries[i], NULL); + int64_t value = pack_sync_value(reply->trigger.wait_value); + + if (value != some_values[i]) { + fprintf(stderr, "Setting alarm value to %lld returned %lld\n", + (long long)some_values[i], + (long long)value); + exit(1); + } + free(reply); + } +} + +static void +test_change_alarm_delta(xcb_connection_t *c) +{ + xcb_sync_alarm_t alarm = xcb_generate_id(c); + xcb_sync_query_alarm_cookie_t queries[ARRAY_SIZE(some_values)]; + + xcb_sync_create_alarm(c, alarm, 0, NULL); + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + uint32_t values[] = { some_values[i] >> 32, some_values[i] }; + + xcb_sync_change_alarm(c, alarm, XCB_SYNC_CA_DELTA, values); + queries[i] = xcb_sync_query_alarm_unchecked(c, alarm); + } + + for (int i = 0; i < ARRAY_SIZE(some_values); i++) { + xcb_sync_query_alarm_reply_t *reply = + xcb_sync_query_alarm_reply(c, queries[i], NULL); + int64_t value = pack_sync_value(reply->delta); + + if (value != some_values[i]) { + fprintf(stderr, "Setting alarm delta to %lld returned %lld\n", + (long long)some_values[i], + (long long)value); + exit(1); + } + free(reply); + } +} + +int main(int argc, char **argv) +{ + int screen; + xcb_connection_t *c = xcb_connect(NULL, &screen); + xcb_query_extension_reply_t *ext = xcb_get_extension_data(c, &xcb_sync_id); + + if (!ext->present) { + printf("No XSync present\n"); + exit(77); + } + + test_create_counter(c); + test_set_counter(c); + test_change_counter_basic(c); + test_change_counter_overflow(c); + test_change_alarm_value(c); + test_change_alarm_delta(c); + + xcb_disconnect(c); + exit(0); +} |