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