sync.c revision f2346221
11b5d61b8Smrg/* 21b5d61b8Smrg * Copyright © 2017 Broadcom 31b5d61b8Smrg * 41b5d61b8Smrg * Permission is hereby granted, free of charge, to any person obtaining a 51b5d61b8Smrg * copy of this software and associated documentation files (the "Software"), 61b5d61b8Smrg * to deal in the Software without restriction, including without limitation 71b5d61b8Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 81b5d61b8Smrg * and/or sell copies of the Software, and to permit persons to whom the 91b5d61b8Smrg * Software is furnished to do so, subject to the following conditions: 101b5d61b8Smrg * 111b5d61b8Smrg * The above copyright notice and this permission notice (including the next 121b5d61b8Smrg * paragraph) shall be included in all copies or substantial portions of the 131b5d61b8Smrg * Software. 141b5d61b8Smrg * 151b5d61b8Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161b5d61b8Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171b5d61b8Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181b5d61b8Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191b5d61b8Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 201b5d61b8Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 211b5d61b8Smrg * IN THE SOFTWARE. 221b5d61b8Smrg */ 231b5d61b8Smrg 241b5d61b8Smrg#include <assert.h> 251b5d61b8Smrg#include <stdio.h> 261b5d61b8Smrg#include <stdlib.h> 271b5d61b8Smrg#include <limits.h> 281b5d61b8Smrg#include <xcb/sync.h> 291b5d61b8Smrg 301b5d61b8Smrg#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 311b5d61b8Smrg 321b5d61b8Smrgstatic const int64_t some_values[] = { 331b5d61b8Smrg 0, 341b5d61b8Smrg 1, 351b5d61b8Smrg -1, 361b5d61b8Smrg LLONG_MAX, 371b5d61b8Smrg LLONG_MIN, 381b5d61b8Smrg}; 391b5d61b8Smrg 401b5d61b8Smrgstatic int64_t 411b5d61b8Smrgpack_sync_value(xcb_sync_int64_t val) 421b5d61b8Smrg{ 431b5d61b8Smrg return ((int64_t)val.hi << 32) | val.lo; 441b5d61b8Smrg} 451b5d61b8Smrg 461b5d61b8Smrgstatic int64_t 471b5d61b8Smrgcounter_value(struct xcb_connection_t *c, 481b5d61b8Smrg xcb_sync_query_counter_cookie_t cookie) 491b5d61b8Smrg{ 501b5d61b8Smrg xcb_sync_query_counter_reply_t *reply = 511b5d61b8Smrg xcb_sync_query_counter_reply(c, cookie, NULL); 521b5d61b8Smrg int64_t value = pack_sync_value(reply->counter_value); 531b5d61b8Smrg 541b5d61b8Smrg free(reply); 551b5d61b8Smrg return value; 561b5d61b8Smrg} 571b5d61b8Smrg 581b5d61b8Smrgstatic xcb_sync_int64_t 591b5d61b8Smrgsync_value(int64_t value) 601b5d61b8Smrg{ 611b5d61b8Smrg xcb_sync_int64_t v = { 621b5d61b8Smrg .hi = value >> 32, 631b5d61b8Smrg .lo = value, 641b5d61b8Smrg }; 651b5d61b8Smrg 661b5d61b8Smrg return v; 671b5d61b8Smrg} 681b5d61b8Smrg 691b5d61b8Smrg/* Initializes counters with a bunch of interesting values and makes 701b5d61b8Smrg * sure it comes back the same. 711b5d61b8Smrg */ 721b5d61b8Smrgstatic void 731b5d61b8Smrgtest_create_counter(xcb_connection_t *c) 741b5d61b8Smrg{ 751b5d61b8Smrg xcb_sync_query_counter_cookie_t queries[ARRAY_SIZE(some_values)]; 761b5d61b8Smrg 771b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 781b5d61b8Smrg xcb_sync_counter_t counter = xcb_generate_id(c); 791b5d61b8Smrg xcb_sync_create_counter(c, counter, sync_value(some_values[i])); 801b5d61b8Smrg queries[i] = xcb_sync_query_counter_unchecked(c, counter); 811b5d61b8Smrg } 821b5d61b8Smrg 831b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 841b5d61b8Smrg int64_t value = counter_value(c, queries[i]); 851b5d61b8Smrg 861b5d61b8Smrg if (value != some_values[i]) { 871b5d61b8Smrg fprintf(stderr, "Creating counter with %lld returned %lld\n", 881b5d61b8Smrg (long long)some_values[i], 891b5d61b8Smrg (long long)value); 901b5d61b8Smrg exit(1); 911b5d61b8Smrg } 921b5d61b8Smrg } 931b5d61b8Smrg} 941b5d61b8Smrg 951b5d61b8Smrg/* Set a single counter to a bunch of interesting values and make sure 961b5d61b8Smrg * it comes the same. 971b5d61b8Smrg */ 981b5d61b8Smrgstatic void 991b5d61b8Smrgtest_set_counter(xcb_connection_t *c) 1001b5d61b8Smrg{ 1011b5d61b8Smrg xcb_sync_counter_t counter = xcb_generate_id(c); 1021b5d61b8Smrg xcb_sync_query_counter_cookie_t queries[ARRAY_SIZE(some_values)]; 1031b5d61b8Smrg 1041b5d61b8Smrg xcb_sync_create_counter(c, counter, sync_value(0)); 1051b5d61b8Smrg 1061b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 1071b5d61b8Smrg xcb_sync_set_counter(c, counter, sync_value(some_values[i])); 1081b5d61b8Smrg queries[i] = xcb_sync_query_counter_unchecked(c, counter); 1091b5d61b8Smrg } 1101b5d61b8Smrg 1111b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 1121b5d61b8Smrg int64_t value = counter_value(c, queries[i]); 1131b5d61b8Smrg 1141b5d61b8Smrg if (value != some_values[i]) { 1151b5d61b8Smrg fprintf(stderr, "Setting counter to %lld returned %lld\n", 1161b5d61b8Smrg (long long)some_values[i], 1171b5d61b8Smrg (long long)value); 1181b5d61b8Smrg exit(1); 1191b5d61b8Smrg } 1201b5d61b8Smrg } 1211b5d61b8Smrg} 1221b5d61b8Smrg 1231b5d61b8Smrg/* Add [0, 1, 2, 3] to a counter and check that the values stick. */ 1241b5d61b8Smrgstatic void 1251b5d61b8Smrgtest_change_counter_basic(xcb_connection_t *c) 1261b5d61b8Smrg{ 1271b5d61b8Smrg int iterations = 4; 1281b5d61b8Smrg xcb_sync_query_counter_cookie_t queries[iterations]; 1291b5d61b8Smrg 1301b5d61b8Smrg xcb_sync_counter_t counter = xcb_generate_id(c); 1311b5d61b8Smrg xcb_sync_create_counter(c, counter, sync_value(0)); 1321b5d61b8Smrg 1331b5d61b8Smrg for (int i = 0; i < iterations; i++) { 1341b5d61b8Smrg xcb_sync_change_counter(c, counter, sync_value(i)); 1351b5d61b8Smrg queries[i] = xcb_sync_query_counter_unchecked(c, counter); 1361b5d61b8Smrg } 1371b5d61b8Smrg 1381b5d61b8Smrg int64_t expected_value = 0; 1391b5d61b8Smrg for (int i = 0; i < iterations; i++) { 1401b5d61b8Smrg expected_value += i; 1411b5d61b8Smrg int64_t value = counter_value(c, queries[i]); 1421b5d61b8Smrg 1431b5d61b8Smrg if (value != expected_value) { 1441b5d61b8Smrg fprintf(stderr, "Adding %d to counter expected %lld returned %lld\n", 1451b5d61b8Smrg i, 1461b5d61b8Smrg (long long)expected_value, 1471b5d61b8Smrg (long long)value); 1481b5d61b8Smrg exit(1); 1491b5d61b8Smrg } 1501b5d61b8Smrg } 1511b5d61b8Smrg} 1521b5d61b8Smrg 1531b5d61b8Smrg/* Test change_counter where we trigger an integer overflow. */ 1541b5d61b8Smrgstatic void 1551b5d61b8Smrgtest_change_counter_overflow(xcb_connection_t *c) 1561b5d61b8Smrg{ 1571b5d61b8Smrg int iterations = 4; 1581b5d61b8Smrg xcb_sync_query_counter_cookie_t queries[iterations]; 1591b5d61b8Smrg xcb_void_cookie_t changes[iterations]; 1601b5d61b8Smrg static const struct { 1611b5d61b8Smrg int64_t a, b; 1621b5d61b8Smrg } overflow_args[] = { 1631b5d61b8Smrg { LLONG_MAX, 1 }, 1641b5d61b8Smrg { LLONG_MAX, LLONG_MAX }, 1651b5d61b8Smrg { LLONG_MIN, -1 }, 1661b5d61b8Smrg { LLONG_MIN, LLONG_MIN }, 1671b5d61b8Smrg }; 1681b5d61b8Smrg 1691b5d61b8Smrg xcb_sync_counter_t counter = xcb_generate_id(c); 1701b5d61b8Smrg xcb_sync_create_counter(c, counter, sync_value(0)); 1711b5d61b8Smrg 1721b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(overflow_args); i++) { 1731b5d61b8Smrg int64_t a = overflow_args[i].a; 1741b5d61b8Smrg int64_t b = overflow_args[i].b; 1751b5d61b8Smrg xcb_sync_set_counter(c, counter, sync_value(a)); 1761b5d61b8Smrg changes[i] = xcb_sync_change_counter_checked(c, counter, 1771b5d61b8Smrg sync_value(b)); 1781b5d61b8Smrg queries[i] = xcb_sync_query_counter(c, counter); 1791b5d61b8Smrg } 1801b5d61b8Smrg 1811b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(overflow_args); i++) { 1821b5d61b8Smrg int64_t a = overflow_args[i].a; 1831b5d61b8Smrg int64_t b = overflow_args[i].b; 1841b5d61b8Smrg xcb_sync_query_counter_reply_t *reply = 1851b5d61b8Smrg xcb_sync_query_counter_reply(c, queries[i], NULL); 1861b5d61b8Smrg int64_t value = (((int64_t)reply->counter_value.hi << 32) | 1871b5d61b8Smrg reply->counter_value.lo); 1881b5d61b8Smrg int64_t expected_value = a; 1891b5d61b8Smrg 1901b5d61b8Smrg /* The change_counter should have thrown BadValue */ 1911b5d61b8Smrg xcb_generic_error_t *e = xcb_request_check(c, changes[i]); 1921b5d61b8Smrg if (!e) { 1931b5d61b8Smrg fprintf(stderr, "(%lld + %lld) failed to return an error\n", 1941b5d61b8Smrg (long long)a, 1951b5d61b8Smrg (long long)b); 1961b5d61b8Smrg exit(1); 1971b5d61b8Smrg } 1981b5d61b8Smrg 1991b5d61b8Smrg if (e->error_code != XCB_VALUE) { 2001b5d61b8Smrg fprintf(stderr, "(%lld + %lld) returned %d, not BadValue\n", 2011b5d61b8Smrg (long long)a, 2021b5d61b8Smrg (long long)b, 2031b5d61b8Smrg e->error_code); 2041b5d61b8Smrg exit(1); 2051b5d61b8Smrg } 2061b5d61b8Smrg 2071b5d61b8Smrg /* The change_counter should have had no other effect if it 2081b5d61b8Smrg * errored out. 2091b5d61b8Smrg */ 2101b5d61b8Smrg if (value != expected_value) { 2111b5d61b8Smrg fprintf(stderr, "(%lld + %lld) expected %lld returned %lld\n", 2121b5d61b8Smrg (long long)a, 2131b5d61b8Smrg (long long)b, 2141b5d61b8Smrg (long long)expected_value, 2151b5d61b8Smrg (long long)value); 2161b5d61b8Smrg exit(1); 2171b5d61b8Smrg } 2181b5d61b8Smrg 2191b5d61b8Smrg free(e); 2201b5d61b8Smrg free(reply); 2211b5d61b8Smrg } 2221b5d61b8Smrg} 2231b5d61b8Smrg 2241b5d61b8Smrgstatic void 2251b5d61b8Smrgtest_change_alarm_value(xcb_connection_t *c) 2261b5d61b8Smrg{ 2271b5d61b8Smrg xcb_sync_alarm_t alarm = xcb_generate_id(c); 2281b5d61b8Smrg xcb_sync_query_alarm_cookie_t queries[ARRAY_SIZE(some_values)]; 2291b5d61b8Smrg 2301b5d61b8Smrg xcb_sync_create_alarm(c, alarm, 0, NULL); 2311b5d61b8Smrg 2321b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 2331b5d61b8Smrg uint32_t values[] = { some_values[i] >> 32, some_values[i] }; 2341b5d61b8Smrg 2351b5d61b8Smrg xcb_sync_change_alarm(c, alarm, XCB_SYNC_CA_VALUE, values); 2361b5d61b8Smrg queries[i] = xcb_sync_query_alarm_unchecked(c, alarm); 2371b5d61b8Smrg } 2381b5d61b8Smrg 2391b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 2401b5d61b8Smrg xcb_sync_query_alarm_reply_t *reply = 2411b5d61b8Smrg xcb_sync_query_alarm_reply(c, queries[i], NULL); 2421b5d61b8Smrg int64_t value = pack_sync_value(reply->trigger.wait_value); 2431b5d61b8Smrg 2441b5d61b8Smrg if (value != some_values[i]) { 2451b5d61b8Smrg fprintf(stderr, "Setting alarm value to %lld returned %lld\n", 2461b5d61b8Smrg (long long)some_values[i], 2471b5d61b8Smrg (long long)value); 2481b5d61b8Smrg exit(1); 2491b5d61b8Smrg } 2501b5d61b8Smrg free(reply); 2511b5d61b8Smrg } 2521b5d61b8Smrg} 2531b5d61b8Smrg 2541b5d61b8Smrgstatic void 2551b5d61b8Smrgtest_change_alarm_delta(xcb_connection_t *c) 2561b5d61b8Smrg{ 2571b5d61b8Smrg xcb_sync_alarm_t alarm = xcb_generate_id(c); 2581b5d61b8Smrg xcb_sync_query_alarm_cookie_t queries[ARRAY_SIZE(some_values)]; 2591b5d61b8Smrg 2601b5d61b8Smrg xcb_sync_create_alarm(c, alarm, 0, NULL); 2611b5d61b8Smrg 2621b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 263f2346221Smrg uint32_t mask = XCB_SYNC_CA_TEST_TYPE | XCB_SYNC_CA_DELTA; 264f2346221Smrg uint32_t test_type = (some_values[i] >= 0 ? 265f2346221Smrg XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON : 266f2346221Smrg XCB_SYNC_TESTTYPE_NEGATIVE_COMPARISON); 267f2346221Smrg uint32_t values[] = { test_type, some_values[i] >> 32, some_values[i] }; 2681b5d61b8Smrg 269f2346221Smrg xcb_sync_change_alarm(c, alarm, mask, values); 2701b5d61b8Smrg queries[i] = xcb_sync_query_alarm_unchecked(c, alarm); 2711b5d61b8Smrg } 2721b5d61b8Smrg 2731b5d61b8Smrg for (int i = 0; i < ARRAY_SIZE(some_values); i++) { 2741b5d61b8Smrg xcb_sync_query_alarm_reply_t *reply = 2751b5d61b8Smrg xcb_sync_query_alarm_reply(c, queries[i], NULL); 2761b5d61b8Smrg int64_t value = pack_sync_value(reply->delta); 2771b5d61b8Smrg 2781b5d61b8Smrg if (value != some_values[i]) { 2791b5d61b8Smrg fprintf(stderr, "Setting alarm delta to %lld returned %lld\n", 2801b5d61b8Smrg (long long)some_values[i], 2811b5d61b8Smrg (long long)value); 2821b5d61b8Smrg exit(1); 2831b5d61b8Smrg } 2841b5d61b8Smrg free(reply); 2851b5d61b8Smrg } 2861b5d61b8Smrg} 2871b5d61b8Smrg 2881b5d61b8Smrgint main(int argc, char **argv) 2891b5d61b8Smrg{ 2901b5d61b8Smrg int screen; 2911b5d61b8Smrg xcb_connection_t *c = xcb_connect(NULL, &screen); 2921b5d61b8Smrg const xcb_query_extension_reply_t *ext = xcb_get_extension_data(c, &xcb_sync_id); 2931b5d61b8Smrg 2941b5d61b8Smrg if (!ext->present) { 2951b5d61b8Smrg printf("No XSync present\n"); 2961b5d61b8Smrg exit(77); 2971b5d61b8Smrg } 2981b5d61b8Smrg 2991b5d61b8Smrg test_create_counter(c); 3001b5d61b8Smrg test_set_counter(c); 3011b5d61b8Smrg test_change_counter_basic(c); 3021b5d61b8Smrg test_change_counter_overflow(c); 3031b5d61b8Smrg test_change_alarm_value(c); 3041b5d61b8Smrg test_change_alarm_delta(c); 3051b5d61b8Smrg 3061b5d61b8Smrg xcb_disconnect(c); 3071b5d61b8Smrg exit(0); 3081b5d61b8Smrg} 309