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