xref: /OK3568_Linux_fs/external/xserver/test/sync/sync.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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
pack_sync_value(xcb_sync_int64_t val)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
counter_value(struct xcb_connection_t * c,xcb_sync_query_counter_cookie_t cookie)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
sync_value(int64_t value)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
test_create_counter(xcb_connection_t * c)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
test_set_counter(xcb_connection_t * c)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
test_change_counter_basic(xcb_connection_t * c)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
test_change_counter_overflow(xcb_connection_t * c)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
test_change_alarm_value(xcb_connection_t * c)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
test_change_alarm_delta(xcb_connection_t * c)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 
main(int argc,char ** argv)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 }
305