1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright Collabora Ltd., 2021 |
4 | * |
5 | * futex cmp requeue test by André Almeida <andrealmeid@collabora.com> |
6 | */ |
7 | |
8 | #include <pthread.h> |
9 | #include <limits.h> |
10 | #include "logging.h" |
11 | #include "futextest.h" |
12 | |
13 | #define TEST_NAME "futex-requeue" |
14 | #define timeout_ns 30000000 |
15 | #define WAKE_WAIT_US 10000 |
16 | |
17 | volatile futex_t *f1; |
18 | |
19 | void usage(char *prog) |
20 | { |
21 | printf("Usage: %s\n" , prog); |
22 | printf(" -c Use color\n" ); |
23 | printf(" -h Display this help message\n" ); |
24 | printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n" , |
25 | VQUIET, VCRITICAL, VINFO); |
26 | } |
27 | |
28 | void *waiterfn(void *arg) |
29 | { |
30 | struct timespec to; |
31 | |
32 | to.tv_sec = 0; |
33 | to.tv_nsec = timeout_ns; |
34 | |
35 | if (futex_wait(f1, *f1, &to, 0)) |
36 | printf("waiter failed errno %d\n" , errno); |
37 | |
38 | return NULL; |
39 | } |
40 | |
41 | int main(int argc, char *argv[]) |
42 | { |
43 | pthread_t waiter[10]; |
44 | int res, ret = RET_PASS; |
45 | int c, i; |
46 | volatile futex_t _f1 = 0; |
47 | volatile futex_t f2 = 0; |
48 | |
49 | f1 = &_f1; |
50 | |
51 | while ((c = getopt(argc, argv, "cht:v:" )) != -1) { |
52 | switch (c) { |
53 | case 'c': |
54 | log_color(1); |
55 | break; |
56 | case 'h': |
57 | usage(prog: basename(argv[0])); |
58 | exit(0); |
59 | case 'v': |
60 | log_verbosity(atoi(optarg)); |
61 | break; |
62 | default: |
63 | usage(prog: basename(argv[0])); |
64 | exit(1); |
65 | } |
66 | } |
67 | |
68 | ksft_print_header(); |
69 | ksft_set_plan(2); |
70 | ksft_print_msg("%s: Test futex_requeue\n" , |
71 | basename(argv[0])); |
72 | |
73 | /* |
74 | * Requeue a waiter from f1 to f2, and wake f2. |
75 | */ |
76 | if (pthread_create(&waiter[0], NULL, waiterfn, NULL)) |
77 | error("pthread_create failed\n" , errno); |
78 | |
79 | usleep(WAKE_WAIT_US); |
80 | |
81 | info("Requeuing 1 futex from f1 to f2\n" ); |
82 | res = futex_cmp_requeue(f1, 0, &f2, 0, 1, 0); |
83 | if (res != 1) { |
84 | ksft_test_result_fail("futex_requeue simple returned: %d %s\n" , |
85 | res ? errno : res, |
86 | res ? strerror(errno) : "" ); |
87 | ret = RET_FAIL; |
88 | } |
89 | |
90 | |
91 | info("Waking 1 futex at f2\n" ); |
92 | res = futex_wake(&f2, 1, 0); |
93 | if (res != 1) { |
94 | ksft_test_result_fail("futex_requeue simple returned: %d %s\n" , |
95 | res ? errno : res, |
96 | res ? strerror(errno) : "" ); |
97 | ret = RET_FAIL; |
98 | } else { |
99 | ksft_test_result_pass("futex_requeue simple succeeds\n" ); |
100 | } |
101 | |
102 | |
103 | /* |
104 | * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7. |
105 | * At futex_wake, wake INT_MAX (should be exactly 7). |
106 | */ |
107 | for (i = 0; i < 10; i++) { |
108 | if (pthread_create(&waiter[i], NULL, waiterfn, NULL)) |
109 | error("pthread_create failed\n" , errno); |
110 | } |
111 | |
112 | usleep(WAKE_WAIT_US); |
113 | |
114 | info("Waking 3 futexes at f1 and requeuing 7 futexes from f1 to f2\n" ); |
115 | res = futex_cmp_requeue(f1, 0, &f2, 3, 7, 0); |
116 | if (res != 10) { |
117 | ksft_test_result_fail("futex_requeue many returned: %d %s\n" , |
118 | res ? errno : res, |
119 | res ? strerror(errno) : "" ); |
120 | ret = RET_FAIL; |
121 | } |
122 | |
123 | info("Waking INT_MAX futexes at f2\n" ); |
124 | res = futex_wake(&f2, INT_MAX, 0); |
125 | if (res != 7) { |
126 | ksft_test_result_fail("futex_requeue many returned: %d %s\n" , |
127 | res ? errno : res, |
128 | res ? strerror(errno) : "" ); |
129 | ret = RET_FAIL; |
130 | } else { |
131 | ksft_test_result_pass("futex_requeue many succeeds\n" ); |
132 | } |
133 | |
134 | ksft_print_cnts(); |
135 | return ret; |
136 | } |
137 | |