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 <sys/shm.h> |
10 | #include <sys/mman.h> |
11 | #include <fcntl.h> |
12 | #include "logging.h" |
13 | #include "futextest.h" |
14 | |
15 | #define TEST_NAME "futex-wait" |
16 | #define timeout_ns 30000000 |
17 | #define WAKE_WAIT_US 10000 |
18 | #define SHM_PATH "futex_shm_file" |
19 | |
20 | void *futex; |
21 | |
22 | void usage(char *prog) |
23 | { |
24 | printf("Usage: %s\n" , prog); |
25 | printf(" -c Use color\n" ); |
26 | printf(" -h Display this help message\n" ); |
27 | printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n" , |
28 | VQUIET, VCRITICAL, VINFO); |
29 | } |
30 | |
31 | static void *waiterfn(void *arg) |
32 | { |
33 | struct timespec to; |
34 | unsigned int flags = 0; |
35 | |
36 | if (arg) |
37 | flags = *((unsigned int *) arg); |
38 | |
39 | to.tv_sec = 0; |
40 | to.tv_nsec = timeout_ns; |
41 | |
42 | if (futex_wait(futex, 0, &to, flags)) |
43 | printf("waiter failed errno %d\n" , errno); |
44 | |
45 | return NULL; |
46 | } |
47 | |
48 | int main(int argc, char *argv[]) |
49 | { |
50 | int res, ret = RET_PASS, fd, c, shm_id; |
51 | u_int32_t f_private = 0, *shared_data; |
52 | unsigned int flags = FUTEX_PRIVATE_FLAG; |
53 | pthread_t waiter; |
54 | void *shm; |
55 | |
56 | futex = &f_private; |
57 | |
58 | while ((c = getopt(argc, argv, "cht:v:" )) != -1) { |
59 | switch (c) { |
60 | case 'c': |
61 | log_color(1); |
62 | break; |
63 | case 'h': |
64 | usage(prog: basename(argv[0])); |
65 | exit(0); |
66 | case 'v': |
67 | log_verbosity(atoi(optarg)); |
68 | break; |
69 | default: |
70 | usage(prog: basename(argv[0])); |
71 | exit(1); |
72 | } |
73 | } |
74 | |
75 | ksft_print_header(); |
76 | ksft_set_plan(3); |
77 | ksft_print_msg("%s: Test futex_wait\n" , basename(argv[0])); |
78 | |
79 | /* Testing a private futex */ |
80 | info("Calling private futex_wait on futex: %p\n" , futex); |
81 | if (pthread_create(&waiter, NULL, waiterfn, (void *) &flags)) |
82 | error("pthread_create failed\n" , errno); |
83 | |
84 | usleep(WAKE_WAIT_US); |
85 | |
86 | info("Calling private futex_wake on futex: %p\n" , futex); |
87 | res = futex_wake(futex, 1, FUTEX_PRIVATE_FLAG); |
88 | if (res != 1) { |
89 | ksft_test_result_fail("futex_wake private returned: %d %s\n" , |
90 | errno, strerror(errno)); |
91 | ret = RET_FAIL; |
92 | } else { |
93 | ksft_test_result_pass("futex_wake private succeeds\n" ); |
94 | } |
95 | |
96 | /* Testing an anon page shared memory */ |
97 | shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); |
98 | if (shm_id < 0) { |
99 | perror("shmget" ); |
100 | exit(1); |
101 | } |
102 | |
103 | shared_data = shmat(shm_id, NULL, 0); |
104 | |
105 | *shared_data = 0; |
106 | futex = shared_data; |
107 | |
108 | info("Calling shared (page anon) futex_wait on futex: %p\n" , futex); |
109 | if (pthread_create(&waiter, NULL, waiterfn, NULL)) |
110 | error("pthread_create failed\n" , errno); |
111 | |
112 | usleep(WAKE_WAIT_US); |
113 | |
114 | info("Calling shared (page anon) futex_wake on futex: %p\n" , futex); |
115 | res = futex_wake(futex, 1, 0); |
116 | if (res != 1) { |
117 | ksft_test_result_fail("futex_wake shared (page anon) returned: %d %s\n" , |
118 | errno, strerror(errno)); |
119 | ret = RET_FAIL; |
120 | } else { |
121 | ksft_test_result_pass("futex_wake shared (page anon) succeeds\n" ); |
122 | } |
123 | |
124 | |
125 | /* Testing a file backed shared memory */ |
126 | fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
127 | if (fd < 0) { |
128 | perror("open" ); |
129 | exit(1); |
130 | } |
131 | |
132 | if (ftruncate(fd, sizeof(f_private))) { |
133 | perror("ftruncate" ); |
134 | exit(1); |
135 | } |
136 | |
137 | shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
138 | if (shm == MAP_FAILED) { |
139 | perror("mmap" ); |
140 | exit(1); |
141 | } |
142 | |
143 | memcpy(shm, &f_private, sizeof(f_private)); |
144 | |
145 | futex = shm; |
146 | |
147 | info("Calling shared (file backed) futex_wait on futex: %p\n" , futex); |
148 | if (pthread_create(&waiter, NULL, waiterfn, NULL)) |
149 | error("pthread_create failed\n" , errno); |
150 | |
151 | usleep(WAKE_WAIT_US); |
152 | |
153 | info("Calling shared (file backed) futex_wake on futex: %p\n" , futex); |
154 | res = futex_wake(shm, 1, 0); |
155 | if (res != 1) { |
156 | ksft_test_result_fail("futex_wake shared (file backed) returned: %d %s\n" , |
157 | errno, strerror(errno)); |
158 | ret = RET_FAIL; |
159 | } else { |
160 | ksft_test_result_pass("futex_wake shared (file backed) succeeds\n" ); |
161 | } |
162 | |
163 | /* Freeing resources */ |
164 | shmdt(shared_data); |
165 | munmap(shm, sizeof(f_private)); |
166 | remove(SHM_PATH); |
167 | close(fd); |
168 | |
169 | ksft_print_cnts(); |
170 | return ret; |
171 | } |
172 | |