• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
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 
30 static size_t write_size;
31 static size_t read_size;
32 static int fds[2];
33 static int epfd;
34 
setup(void)35 static void setup(void)
36 {
37 	write_size = getpagesize();
38 	read_size = write_size / 2;
39 
40 	SAFE_PIPE2(fds, O_NONBLOCK);
41 
42 	/* EPOLLOUT will be raised when buffer became empty after becoming full */
43 	SAFE_FCNTL(fds[1], F_SETPIPE_SZ, write_size);
44 }
45 
cleanup(void)46 static void cleanup(void)
47 {
48 	if (epfd > 0)
49 		SAFE_CLOSE(epfd);
50 
51 	if (fds[0] > 0)
52 		SAFE_CLOSE(fds[0]);
53 
54 	if (fds[1] > 0)
55 		SAFE_CLOSE(fds[1]);
56 }
57 
run(void)58 static void run(void)
59 {
60 	char buff[write_size];
61 	struct epoll_event evt_receive;
62 
63 	tst_res(TINFO, "Polling on channel with EPOLLET");
64 
65 	epfd = SAFE_EPOLL_CREATE1(0);
66 
67 	SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) {
68 		.events = EPOLLIN | EPOLLET,
69 		.data.fd = fds[0],
70 	}));
71 	SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[1], &((struct epoll_event) {
72 		.events = EPOLLOUT | EPOLLET,
73 		.data.fd = fds[1],
74 	}));
75 
76 	tst_res(TINFO, "Write bytes on channel: %zu bytes", write_size);
77 
78 	memset(buff, 'a', write_size);
79 	SAFE_WRITE(SAFE_WRITE_ANY, fds[1], buff, write_size);
80 	TST_EXP_FAIL(write(fds[1], buff, write_size), EAGAIN, "write() failed");
81 
82 	TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1);
83 	TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]);
84 	TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN);
85 
86 	tst_res(TINFO, "Read half bytes from channel: %zu bytes", read_size);
87 
88 	memset(buff, 0, write_size);
89 	SAFE_READ(1, fds[0], buff, read_size);
90 
91 	TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 0);
92 
93 	tst_res(TINFO, "Read remaining bytes from channel: %zu bytes", read_size);
94 
95 	SAFE_READ(1, fds[0], buff + read_size, read_size);
96 	TST_EXP_FAIL(read(fds[0], buff, read_size), EAGAIN, "read() failed");
97 
98 	TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1);
99 	TST_EXP_EQ_LI(evt_receive.data.fd, fds[1]);
100 	TST_EXP_EQ_LI(evt_receive.events & EPOLLOUT, EPOLLOUT);
101 }
102 
103 static struct tst_test test = {
104 	.setup = setup,
105 	.cleanup = cleanup,
106 	.test_all = run,
107 };
108