blob: a96f911aa2e91f55eb8dac04f2183fbabb1034a9 [file] [log] [blame]
Dominik Behr27dc8db2017-08-14 13:37:18 -07001#include <errno.h>
2#include <fcntl.h>
3#include <getopt.h>
4#include <stdbool.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sync/sync.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <unistd.h>
12
13/* These are not exported from the library because they are for testing only. */
14int sw_sync_fence_create(int fd, const char *name, unsigned value);
15int sw_sync_timeline_create(void);
16int sw_sync_timeline_inc(int fd, unsigned count);
17
18#define CHK(errn) do { int ret = fc; if (ret < 0) return ret; } while (0)
19
20#define ERROR(msg, en) do {\
21 fprintf(stderr, "ERROR : %s. : %d:%s\n", (msg), (en), strerror(en)); \
22 } while (0)
23
24bool verbose = false;
25
26static int
27test_swsync_exists(void)
28{
29 int ret;
30 int newsync = 0;
31 struct stat buf = { 0 };
32
33 ret = stat("/dev/sw_sync", &buf);
34 if (ret < 0 && errno == ENOENT) {
35 ret = stat("/sys/kernel/debug/sync/sw_sync", &buf);
36 if (ret < 0 && errno == ENOENT) {
37 ret = -errno;
38 ERROR("sw_sync interface does not exist", -ret);
39 goto fail;
40 }
41 newsync = 1;
42 }
43 if (ret < 0 && errno == EACCES) {
44 ret = -errno;
45 ERROR("No permission to access sw_sync interface", -ret);
46 goto fail;
47 }
48
49 if (ret < 0) {
50 ret = -errno;
51 ERROR("Stat failed", -ret);
52 goto fail;
53 }
54
55 /* Old sync is a character device. New is a regular file in sysfs. */
56 if ((!newsync && (buf.st_mode & S_IFCHR))
57 || (newsync && (buf.st_mode & S_IFREG))) {
58 ret = 0;
59 }
60
61fail:
62 return ret;
63}
64
65static int
66get_timeline(void)
67{
68 int tl = sw_sync_timeline_create();
69 if (tl < 0) {
70 tl = -errno;
71 ERROR("Cannot create timeline", -tl);
72 }
73 return tl;
74}
75
76static int
77get_fence(int tl, int value)
78{
79 int fc = sw_sync_fence_create(tl, "simple fence", value);
80 if (fc < 0) {
81 fc = -errno;
82 ERROR("Failed to create fence", -fc);
83 }
84 return fc;
85}
86
87static int
88fence_check(int fc)
89{
90 int ret;
91 ret = sync_wait(fc, 0);
92 if (ret < 0) {
93 if (errno == ETIME)
94 return 0;
95 if (errno == EINVAL)
96 return 1; /* timeline destroyed */
97 ret = -errno;
98 ERROR("Failed fence wait", -ret);
99 return ret;
100 }
101
102 return 1;
103}
104
105/* Return 0 when timeout, 1 when passing, < 0 for error
106*/
107static int
108timeline_inc(int tl, int delta)
109{
110 int ret;
111 ret = sw_sync_timeline_inc(tl, delta);
112 if (ret < 0) {
113 ret = -errno;
114 ERROR("Failed to increment timeline", -ret);
115 }
116 return ret;
117}
118
119/* Test single fence. */
120static int
121test_simple(void)
122{
123 int tl;
124 int fc;
125 int ret;
126
127 tl = get_timeline();
128 if (tl < 0) {
129 return tl;
130 }
131
132 fc = get_fence(tl, 1);
133 if (fc < 0) {
134 ret = fc;
135 goto fail;
136 }
137
138 ret = fence_check(fc);
139 if (ret < 0) {
140 goto fail_fence;
141 } else if (ret == 1) {
142 ret = -1;
143 ERROR("Fence already signaled even though we did not signal it", 0);
144 goto fail_fence;
145 }
146
147 ret = timeline_inc(tl, 1);
148 if (ret < 0) {
149 goto fail_fence;
150 }
151
152 ret = fence_check(fc);
153 if (ret < 0) {
154 goto fail_fence;
155 } else if (ret == 0) {
156 ret = -1;
157 ERROR("Fence is not signaled even though it should be", 0);
158 goto fail_fence;
159 }
160 ret = 0;
161
162fail_fence:
163 close(fc);
164fail:
165 close(tl);
166 return ret;
167}
168
169
170#define NUM_FENCES 10
171/* Test multiple fences signaled with one timeline inc. */
172static int
173test_multiple(void)
174{
175 int i;
176 int tl;
177 int fc[NUM_FENCES];
178 int ret;
179 int value = 1;
180
181 tl = get_timeline();
182 if (tl < 0) {
183 return tl;
184 }
185
186 for (i = 0; i < NUM_FENCES; i++) {
187 fc[i] = get_fence(tl, value++);
188 if (fc[i] < 0) {
189 ret = fc[i];
190 goto fail;
191 }
192 }
193
194 for (i = 0; i < NUM_FENCES; i++) {
195 ret = fence_check(fc[i]);
196 if (ret < 0) {
197 goto fail_fence;
198 } else if (ret == 1) {
199 ret = -1;
200 ERROR("Fence already signaled even though we did not signal it", 0);
201 goto fail_fence;
202 }
203 }
204
205 ret = timeline_inc(tl, NUM_FENCES);
206 if (ret < 0) {
207 goto fail_fence;
208 }
209
210 for (i = 0; i < NUM_FENCES; i++) {
211 ret = fence_check(fc[i]);
212 if (ret < 0) {
213 goto fail_fence;
214 } else if (ret == 0) {
215 ret = -1;
216 ERROR("Fence is not signaled even though it should be", 0);
217 goto fail_fence;
218 }
219 }
220 ret = 0;
221
222fail_fence:
223 for (i = 0; i < NUM_FENCES; i++)
224 close(fc[i]);
225fail:
226 close(tl);
227 return ret;
228}
229#undef NUM_FENCES
230
231/* Test destruction of timeline. It should signal/set error condition on all
232 * fences in the timeline. */
233static int
234test_timeline_destroy(void)
235{
236 int tl;
237 int fc;
238 int ret;
239
240 tl = get_timeline();
241 if (tl < 0) {
242 return tl;
243 }
244
245 fc = get_fence(tl, 1);
246 if (fc < 0) {
247 ret = fc;
248 goto fail;
249 }
250
251 ret = fence_check(fc);
252 if (ret < 0) {
253 goto fail_fence;
254 } else if (ret == 1) {
255 ret = -1;
256 ERROR("Fence already signaled even though we did not signal it", 0);
257 goto fail_fence;
258 }
259
260 close(tl);
261
262 ret = fence_check(fc);
263 if (ret < 0) {
264 goto fail_fence;
265 } else if (ret == 0) {
266 ret = -1;
267 ERROR("Fence is not signaled even though it should be", 0);
268 goto fail_fence;
269 }
270 ret = 0;
271
272fail_fence:
273 close(fc);
274fail:
275 return ret;
276}
277
278static const struct { const char *name; int (*func)(void); } cases[] = {
279 { "swsync_exists", test_swsync_exists },
280 { "simple", test_simple },
281 { "multiple", test_multiple },
282 { "timeline_destroy", test_timeline_destroy },
283 { NULL, NULL }
284};
285
286
287static const struct option longopts[] = {
288 { "test_name", required_argument, NULL, 't' },
289 { "verbose", no_argument, NULL, 'v' },
290 { "help", no_argument, NULL, 'h' },
291 { 0, 0, 0, 0 },
292};
293
294static void print_help(const char *argv0)
295{
296 unsigned int u;
297 printf("usage: %s -t <test_name> [-v]\n", argv0);
298 printf("A valid name test is one the following:\n");
299 for (u = 0; cases[u].name; u++)
300 printf("%s\n", cases[u].name);
301 printf("all\n");
302}
303
304int
305run_synctest(const char *name)
306{
307 unsigned int u;
308 int ret = 0;
309
310 for (u = 0; cases[u].name; u++) {
311 if (strcmp(cases[u].name, name) && strcmp(name, "all"))
312 continue;
313 if (verbose)
314 printf("Running subtest %s\n", cases[u].name);
315 ret = cases[u].func();
316 if (verbose)
317 printf("Subtest %s %s\n", cases[u].name, (ret < 0) ? "failed" : "passed");
318 if (ret < 0)
319 break;
320 }
321
322 return ret;
323}
324
325int
326main(int ARGC, char *ARGV[])
327{
328 int c;
329 char *name = strdup("all");
330
331 while ((c = getopt_long(ARGC, ARGV, "t:vh", longopts, NULL)) != -1) {
332 switch (c) {
333 case 't':
334 if (name) {
335 free(name);
336 name = NULL;
337 }
338
339 name = strdup(optarg);
340 break;
341 case 'v':
342 verbose = true;
343 break;
344 case 'h':
345 goto print;
346 default:
347 goto print;
348 }
349 }
350
351 if (!name)
352 goto print;
353
354 int ret = run_synctest(name);
355 if (ret == 0)
356 printf("[ PASSED ] synctest.%s\n", name);
357 else if (ret < 0)
358 printf("[ FAILED ] synctest.%s\n", name);
359
360 free(name);
361
362 if (ret > 0) {
363 printf("Unexpected test result.\n");
364 goto print;
365 }
366
367 return ret;
368
369print:
370 print_help(ARGV[0]);
371 return -EINVAL;
372
373}