xref: /linux/tools/testing/selftests/filesystems/eventfd/eventfd_test.c (revision eb01fe7abbe2d0b38824d2a93fdb4cc3eaf2ccc1)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <asm/unistd.h>
7 #include <linux/time_types.h>
8 #include <unistd.h>
9 #include <assert.h>
10 #include <signal.h>
11 #include <pthread.h>
12 #include <sys/epoll.h>
13 #include <sys/eventfd.h>
14 #include "../../kselftest_harness.h"
15 
16 struct error {
17 	int  code;
18 	char msg[512];
19 };
20 
21 static int error_set(struct error *err, int code, const char *fmt, ...)
22 {
23 	va_list args;
24 	int r;
25 
26 	if (code == 0 || !err || err->code != 0)
27 		return code;
28 
29 	err->code = code;
30 	va_start(args, fmt);
31 	r = vsnprintf(err->msg, sizeof(err->msg), fmt, args);
32 	assert((size_t)r < sizeof(err->msg));
33 	va_end(args);
34 
35 	return code;
36 }
37 
38 static inline int sys_eventfd2(unsigned int count, int flags)
39 {
40 	return syscall(__NR_eventfd2, count, flags);
41 }
42 
43 TEST(eventfd01)
44 {
45 	int fd, flags;
46 
47 	fd = sys_eventfd2(0, 0);
48 	ASSERT_GE(fd, 0);
49 
50 	flags = fcntl(fd, F_GETFL);
51 	// since the kernel automatically added O_RDWR.
52 	EXPECT_EQ(flags, O_RDWR);
53 
54 	close(fd);
55 }
56 
57 TEST(eventfd02)
58 {
59 	int fd, flags;
60 
61 	fd = sys_eventfd2(0, EFD_CLOEXEC);
62 	ASSERT_GE(fd, 0);
63 
64 	flags = fcntl(fd, F_GETFD);
65 	ASSERT_GT(flags, -1);
66 	EXPECT_EQ(flags, FD_CLOEXEC);
67 
68 	close(fd);
69 }
70 
71 TEST(eventfd03)
72 {
73 	int fd, flags;
74 
75 	fd = sys_eventfd2(0, EFD_NONBLOCK);
76 	ASSERT_GE(fd, 0);
77 
78 	flags = fcntl(fd, F_GETFL);
79 	ASSERT_GT(flags, -1);
80 	EXPECT_EQ(flags & EFD_NONBLOCK, EFD_NONBLOCK);
81 	EXPECT_EQ(flags & O_RDWR, O_RDWR);
82 
83 	close(fd);
84 }
85 
86 TEST(eventfd04)
87 {
88 	int fd, flags;
89 
90 	fd = sys_eventfd2(0, EFD_CLOEXEC|EFD_NONBLOCK);
91 	ASSERT_GE(fd, 0);
92 
93 	flags = fcntl(fd, F_GETFL);
94 	ASSERT_GT(flags, -1);
95 	EXPECT_EQ(flags & EFD_NONBLOCK, EFD_NONBLOCK);
96 	EXPECT_EQ(flags & O_RDWR, O_RDWR);
97 
98 	flags = fcntl(fd, F_GETFD);
99 	ASSERT_GT(flags, -1);
100 	EXPECT_EQ(flags, FD_CLOEXEC);
101 
102 	close(fd);
103 }
104 
105 static inline void trim_newline(char *str)
106 {
107 	char *pos = strrchr(str, '\n');
108 
109 	if (pos)
110 		*pos = '\0';
111 }
112 
113 static int verify_fdinfo(int fd, struct error *err, const char *prefix,
114 		size_t prefix_len, const char *expect, ...)
115 {
116 	char buffer[512] = {0, };
117 	char path[512] = {0, };
118 	va_list args;
119 	FILE *f;
120 	char *line = NULL;
121 	size_t n = 0;
122 	int found = 0;
123 	int r;
124 
125 	va_start(args, expect);
126 	r = vsnprintf(buffer, sizeof(buffer), expect, args);
127 	assert((size_t)r < sizeof(buffer));
128 	va_end(args);
129 
130 	snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
131 	f = fopen(path, "re");
132 	if (!f)
133 		return error_set(err, -1, "fdinfo open failed for %d", fd);
134 
135 	while (getline(&line, &n, f) != -1) {
136 		char *val;
137 
138 		if (strncmp(line, prefix, prefix_len))
139 			continue;
140 
141 		found = 1;
142 
143 		val = line + prefix_len;
144 		r = strcmp(val, buffer);
145 		if (r != 0) {
146 			trim_newline(line);
147 			trim_newline(buffer);
148 			error_set(err, -1, "%s '%s' != '%s'",
149 				  prefix, val, buffer);
150 		}
151 		break;
152 	}
153 
154 	free(line);
155 	fclose(f);
156 
157 	if (found == 0)
158 		return error_set(err, -1, "%s not found for fd %d",
159 				 prefix, fd);
160 
161 	return 0;
162 }
163 
164 TEST(eventfd05)
165 {
166 	struct error err = {0};
167 	int fd, ret;
168 
169 	fd = sys_eventfd2(0, EFD_SEMAPHORE);
170 	ASSERT_GE(fd, 0);
171 
172 	ret = fcntl(fd, F_GETFL);
173 	ASSERT_GT(ret, -1);
174 	EXPECT_EQ(ret & O_RDWR, O_RDWR);
175 
176 	// The semaphore could only be obtained from fdinfo.
177 	ret = verify_fdinfo(fd, &err, "eventfd-semaphore: ", 19, "1\n");
178 	if (ret != 0)
179 		ksft_print_msg("eventfd-semaphore check failed, msg: %s\n",
180 				err.msg);
181 	EXPECT_EQ(ret, 0);
182 
183 	close(fd);
184 }
185 
186 TEST_HARNESS_MAIN
187