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
20void *futex;
21
22void 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
31static 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
48int 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		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