1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright Collabora Ltd., 2021
4 *
5 * futex cmp requeue test by André Almeida <[email protected]>
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
usage(char * prog)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
waiterfn(void * arg)31 static void *waiterfn(void *arg)
32 {
33 struct timespec64 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
main(int argc,char * argv[])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(basename(argv[0]));
65 exit(0);
66 case 'v':
67 log_verbosity(atoi(optarg));
68 break;
69 default:
70 usage(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 if (errno == ENOSYS) {
100 ksft_test_result_skip("shmget returned: %d %s\n",
101 errno, strerror(errno));
102 goto skip_anon_page_shared_memory_test;
103 }
104 perror("shmget");
105 exit(1);
106 }
107
108 shared_data = shmat(shm_id, NULL, 0);
109
110 *shared_data = 0;
111 futex = shared_data;
112
113 info("Calling shared (page anon) futex_wait on futex: %p\n", futex);
114 if (pthread_create(&waiter, NULL, waiterfn, NULL))
115 error("pthread_create failed\n", errno);
116
117 usleep(WAKE_WAIT_US);
118
119 info("Calling shared (page anon) futex_wake on futex: %p\n", futex);
120 res = futex_wake(futex, 1, 0);
121 if (res != 1) {
122 ksft_test_result_fail("futex_wake shared (page anon) returned: %d %s\n",
123 errno, strerror(errno));
124 ret = RET_FAIL;
125 } else {
126 ksft_test_result_pass("futex_wake shared (page anon) succeeds\n");
127 }
128
129 skip_anon_page_shared_memory_test:
130
131 /* Testing a file backed shared memory */
132 fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
133 if (fd < 0) {
134 perror("open");
135 exit(1);
136 }
137
138 if (ftruncate(fd, sizeof(f_private))) {
139 perror("ftruncate");
140 exit(1);
141 }
142
143 shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
144 if (shm == MAP_FAILED) {
145 perror("mmap");
146 exit(1);
147 }
148
149 memcpy(shm, &f_private, sizeof(f_private));
150
151 futex = shm;
152
153 info("Calling shared (file backed) futex_wait on futex: %p\n", futex);
154 if (pthread_create(&waiter, NULL, waiterfn, NULL))
155 error("pthread_create failed\n", errno);
156
157 usleep(WAKE_WAIT_US);
158
159 info("Calling shared (file backed) futex_wake on futex: %p\n", futex);
160 res = futex_wake(shm, 1, 0);
161 if (res != 1) {
162 ksft_test_result_fail("futex_wake shared (file backed) returned: %d %s\n",
163 errno, strerror(errno));
164 ret = RET_FAIL;
165 } else {
166 ksft_test_result_pass("futex_wake shared (file backed) succeeds\n");
167 }
168
169 /* Freeing resources */
170 shmdt(shared_data);
171 munmap(shm, sizeof(f_private));
172 remove(SHM_PATH);
173 close(fd);
174
175 ksft_print_cnts();
176 return ret;
177 }
178