xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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