1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2023 SUSE LLC Andrea Cervesato <[email protected]>
4 */
5
6 /*\
7 * [Description]
8 *
9 * Verify that edge triggering is correctly handled by epoll, for both EPOLLIN
10 * and EPOLLOUT.
11 *
12 * [Algorithm]
13 *
14 * - The file descriptors for non-blocking pipe are registered on an epoll
15 * instance.
16 * - A pipe writer writes data on the write side of the pipe.
17 * - A call to epoll_wait() is done that will return a EPOLLIN event.
18 * - The pipe reader reads half of data from rfd.
19 * - A call to epoll_wait() should hang because there's data left to read.
20 * - The pipe reader reads remaining data from rfd.
21 * - A call to epoll_wait() should return a EPOLLOUT event.
22 */
23
24 #define _GNU_SOURCE
25
26 #include <fcntl.h>
27 #include "tst_test.h"
28 #include "tst_epoll.h"
29 #include "pgsize_helpers.h"
30
31 static size_t write_size;
32 static size_t read_size;
33 static int fds[2];
34 static int epfd;
35
setup(void)36 static void setup(void)
37 {
38 /*
39 * NOTE: The sematics of this test don't hold across page boundaries for
40 * EPOLLET.
41 *
42 * The documentation says that it "might" / "probably" won't recieve a
43 * new event for exisitng data. So we can't be guaranteed that it won't.
44 *
45 * https://man7.org/linux/man-pages/man7/epoll.7.html
46 */
47 write_size = kernel_page_size();
48 read_size = write_size / 2;
49
50 SAFE_PIPE2(fds, O_NONBLOCK);
51
52 /* EPOLLOUT will be raised when buffer became empty after becoming full */
53 SAFE_FCNTL(fds[1], F_SETPIPE_SZ, write_size);
54 }
55
cleanup(void)56 static void cleanup(void)
57 {
58 if (epfd > 0)
59 SAFE_CLOSE(epfd);
60
61 if (fds[0] > 0)
62 SAFE_CLOSE(fds[0]);
63
64 if (fds[1] > 0)
65 SAFE_CLOSE(fds[1]);
66 }
67
run(void)68 static void run(void)
69 {
70 char buff[write_size];
71 struct epoll_event evt_receive;
72
73 tst_res(TINFO, "Polling on channel with EPOLLET");
74
75 epfd = SAFE_EPOLL_CREATE1(0);
76
77 SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) {
78 .events = EPOLLIN | EPOLLET,
79 .data.fd = fds[0],
80 }));
81 SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[1], &((struct epoll_event) {
82 .events = EPOLLOUT | EPOLLET,
83 .data.fd = fds[1],
84 }));
85
86 tst_res(TINFO, "Write bytes on channel: %zu bytes", write_size);
87
88 memset(buff, 'a', write_size);
89 SAFE_WRITE(SAFE_WRITE_ANY, fds[1], buff, write_size);
90 TST_EXP_FAIL(write(fds[1], buff, write_size), EAGAIN, "write() failed");
91
92 TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1);
93 TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]);
94 TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN);
95
96 tst_res(TINFO, "Read half bytes from channel: %zu bytes", read_size);
97
98 memset(buff, 0, write_size);
99 SAFE_READ(1, fds[0], buff, read_size);
100
101 TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 0);
102
103 tst_res(TINFO, "Read remaining bytes from channel: %zu bytes", read_size);
104
105 SAFE_READ(1, fds[0], buff + read_size, read_size);
106 TST_EXP_FAIL(read(fds[0], buff, read_size), EAGAIN, "read() failed");
107
108 TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1);
109 TST_EXP_EQ_LI(evt_receive.data.fd, fds[1]);
110 TST_EXP_EQ_LI(evt_receive.events & EPOLLOUT, EPOLLOUT);
111 }
112
113 static struct tst_test test = {
114 .setup = setup,
115 .cleanup = cleanup,
116 .test_all = run,
117 };
118