xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

sync.c (9470B)


      1 /*
      2  * Copyright © 2017 Broadcom
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include <assert.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <limits.h>
     28 #include <xcb/sync.h>
     29 
     30 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
     31 
     32 static const int64_t some_values[] = {
     33         0,
     34         1,
     35         -1,
     36         LLONG_MAX,
     37         LLONG_MIN,
     38 };
     39 
     40 static int64_t
     41 pack_sync_value(xcb_sync_int64_t val)
     42 {
     43     return ((int64_t)val.hi << 32) | val.lo;
     44 }
     45 
     46 static int64_t
     47 counter_value(struct xcb_connection_t *c,
     48               xcb_sync_query_counter_cookie_t cookie)
     49 {
     50     xcb_sync_query_counter_reply_t *reply =
     51         xcb_sync_query_counter_reply(c, cookie, NULL);
     52     int64_t value = pack_sync_value(reply->counter_value);
     53 
     54     free(reply);
     55     return value;
     56 }
     57 
     58 static xcb_sync_int64_t
     59 sync_value(int64_t value)
     60 {
     61     xcb_sync_int64_t v = {
     62         .hi = value >> 32,
     63         .lo = value,
     64     };
     65 
     66     return v;
     67 }
     68 
     69 /* Initializes counters with a bunch of interesting values and makes
     70  * sure it comes back the same.
     71  */
     72 static void
     73 test_create_counter(xcb_connection_t *c)
     74 {
     75     xcb_sync_query_counter_cookie_t queries[ARRAY_SIZE(some_values)];
     76 
     77     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
     78         xcb_sync_counter_t counter = xcb_generate_id(c);
     79         xcb_sync_create_counter(c, counter, sync_value(some_values[i]));
     80         queries[i] = xcb_sync_query_counter_unchecked(c, counter);
     81     }
     82 
     83     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
     84         int64_t value = counter_value(c, queries[i]);
     85 
     86         if (value != some_values[i]) {
     87             fprintf(stderr, "Creating counter with %lld returned %lld\n",
     88                     (long long)some_values[i],
     89                     (long long)value);
     90             exit(1);
     91         }
     92     }
     93 }
     94 
     95 /* Set a single counter to a bunch of interesting values and make sure
     96  * it comes the same.
     97  */
     98 static void
     99 test_set_counter(xcb_connection_t *c)
    100 {
    101     xcb_sync_counter_t counter = xcb_generate_id(c);
    102     xcb_sync_query_counter_cookie_t queries[ARRAY_SIZE(some_values)];
    103 
    104     xcb_sync_create_counter(c, counter, sync_value(0));
    105 
    106     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
    107         xcb_sync_set_counter(c, counter, sync_value(some_values[i]));
    108         queries[i] = xcb_sync_query_counter_unchecked(c, counter);
    109     }
    110 
    111     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
    112         int64_t value = counter_value(c, queries[i]);
    113 
    114         if (value != some_values[i]) {
    115             fprintf(stderr, "Setting counter to %lld returned %lld\n",
    116                     (long long)some_values[i],
    117                     (long long)value);
    118             exit(1);
    119         }
    120     }
    121 }
    122 
    123 /* Add [0, 1, 2, 3] to a counter and check that the values stick. */
    124 static void
    125 test_change_counter_basic(xcb_connection_t *c)
    126 {
    127     int iterations = 4;
    128     xcb_sync_query_counter_cookie_t queries[iterations];
    129 
    130     xcb_sync_counter_t counter = xcb_generate_id(c);
    131     xcb_sync_create_counter(c, counter, sync_value(0));
    132 
    133     for (int i = 0; i < iterations; i++) {
    134         xcb_sync_change_counter(c, counter, sync_value(i));
    135         queries[i] = xcb_sync_query_counter_unchecked(c, counter);
    136     }
    137 
    138     int64_t expected_value = 0;
    139     for (int i = 0; i < iterations; i++) {
    140         expected_value += i;
    141         int64_t value = counter_value(c, queries[i]);
    142 
    143         if (value != expected_value) {
    144             fprintf(stderr, "Adding %d to counter expected %lld returned %lld\n",
    145                     i,
    146                     (long long)expected_value,
    147                     (long long)value);
    148             exit(1);
    149         }
    150     }
    151 }
    152 
    153 /* Test change_counter where we trigger an integer overflow. */
    154 static void
    155 test_change_counter_overflow(xcb_connection_t *c)
    156 {
    157     int iterations = 4;
    158     xcb_sync_query_counter_cookie_t queries[iterations];
    159     xcb_void_cookie_t changes[iterations];
    160     static const struct {
    161         int64_t a, b;
    162     } overflow_args[] = {
    163         { LLONG_MAX, 1 },
    164         { LLONG_MAX, LLONG_MAX },
    165         { LLONG_MIN, -1 },
    166         { LLONG_MIN, LLONG_MIN },
    167     };
    168 
    169     xcb_sync_counter_t counter = xcb_generate_id(c);
    170     xcb_sync_create_counter(c, counter, sync_value(0));
    171 
    172     for (int i = 0; i < ARRAY_SIZE(overflow_args); i++) {
    173         int64_t a = overflow_args[i].a;
    174         int64_t b = overflow_args[i].b;
    175         xcb_sync_set_counter(c, counter, sync_value(a));
    176         changes[i] = xcb_sync_change_counter_checked(c, counter,
    177                                                      sync_value(b));
    178         queries[i] = xcb_sync_query_counter(c, counter);
    179     }
    180 
    181     for (int i = 0; i < ARRAY_SIZE(overflow_args); i++) {
    182         int64_t a = overflow_args[i].a;
    183         int64_t b = overflow_args[i].b;
    184         xcb_sync_query_counter_reply_t *reply =
    185             xcb_sync_query_counter_reply(c, queries[i], NULL);
    186         int64_t value = (((int64_t)reply->counter_value.hi << 32) |
    187                          reply->counter_value.lo);
    188         int64_t expected_value = a;
    189 
    190         /* The change_counter should have thrown BadValue */
    191         xcb_generic_error_t *e = xcb_request_check(c, changes[i]);
    192         if (!e) {
    193             fprintf(stderr, "(%lld + %lld) failed to return an error\n",
    194                     (long long)a,
    195                     (long long)b);
    196             exit(1);
    197         }
    198 
    199         if (e->error_code != XCB_VALUE) {
    200             fprintf(stderr, "(%lld + %lld) returned %d, not BadValue\n",
    201                     (long long)a,
    202                     (long long)b,
    203                     e->error_code);
    204             exit(1);
    205         }
    206 
    207         /* The change_counter should have had no other effect if it
    208          * errored out.
    209          */
    210         if (value != expected_value) {
    211             fprintf(stderr, "(%lld + %lld) expected %lld returned %lld\n",
    212                     (long long)a,
    213                     (long long)b,
    214                     (long long)expected_value,
    215                     (long long)value);
    216             exit(1);
    217         }
    218 
    219         free(e);
    220         free(reply);
    221     }
    222 }
    223 
    224 static void
    225 test_change_alarm_value(xcb_connection_t *c)
    226 {
    227     xcb_sync_alarm_t alarm = xcb_generate_id(c);
    228     xcb_sync_query_alarm_cookie_t queries[ARRAY_SIZE(some_values)];
    229 
    230     xcb_sync_create_alarm(c, alarm, 0, NULL);
    231 
    232     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
    233         uint32_t values[] = { some_values[i] >> 32, some_values[i] };
    234 
    235         xcb_sync_change_alarm(c, alarm, XCB_SYNC_CA_VALUE, values);
    236         queries[i] = xcb_sync_query_alarm_unchecked(c, alarm);
    237     }
    238 
    239     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
    240         xcb_sync_query_alarm_reply_t *reply =
    241             xcb_sync_query_alarm_reply(c, queries[i], NULL);
    242         int64_t value = pack_sync_value(reply->trigger.wait_value);
    243 
    244         if (value != some_values[i]) {
    245             fprintf(stderr, "Setting alarm value to %lld returned %lld\n",
    246                     (long long)some_values[i],
    247                     (long long)value);
    248             exit(1);
    249         }
    250         free(reply);
    251     }
    252 }
    253 
    254 static void
    255 test_change_alarm_delta(xcb_connection_t *c)
    256 {
    257     xcb_sync_alarm_t alarm = xcb_generate_id(c);
    258     xcb_sync_query_alarm_cookie_t queries[ARRAY_SIZE(some_values)];
    259 
    260     xcb_sync_create_alarm(c, alarm, 0, NULL);
    261 
    262     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
    263         uint32_t values[] = { some_values[i] >> 32, some_values[i] };
    264 
    265         xcb_sync_change_alarm(c, alarm, XCB_SYNC_CA_DELTA, values);
    266         queries[i] = xcb_sync_query_alarm_unchecked(c, alarm);
    267     }
    268 
    269     for (int i = 0; i < ARRAY_SIZE(some_values); i++) {
    270         xcb_sync_query_alarm_reply_t *reply =
    271             xcb_sync_query_alarm_reply(c, queries[i], NULL);
    272         int64_t value = pack_sync_value(reply->delta);
    273 
    274         if (value != some_values[i]) {
    275             fprintf(stderr, "Setting alarm delta to %lld returned %lld\n",
    276                     (long long)some_values[i],
    277                     (long long)value);
    278             exit(1);
    279         }
    280         free(reply);
    281     }
    282 }
    283 
    284 int main(int argc, char **argv)
    285 {
    286     int screen;
    287     xcb_connection_t *c = xcb_connect(NULL, &screen);
    288     const xcb_query_extension_reply_t *ext = xcb_get_extension_data(c, &xcb_sync_id);
    289 
    290     if (!ext->present) {
    291         printf("No XSync present\n");
    292         exit(77);
    293     }
    294 
    295     test_create_counter(c);
    296     test_set_counter(c);
    297     test_change_counter_basic(c);
    298     test_change_counter_overflow(c);
    299     test_change_alarm_value(c);
    300     test_change_alarm_delta(c);
    301 
    302     xcb_disconnect(c);
    303     exit(0);
    304 }