Home | History | Annotate | Download | only in epoll_wait
      1 /*
      2  * Copyright (c) 2016 Fujitsu Ltd.
      3  * Author: Guangwen Feng <fenggw-fnst (at) cn.fujitsu.com>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
     13  * the GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.
     17  */
     18 
     19 /*
     20  * Description:
     21  *  Basic test for epoll_wait(2).
     22  *  Check that epoll_wait(2) works for EPOLLOUT and EPOLLIN events
     23  *  on a epoll instance and that struct epoll_event is set correctly.
     24  */
     25 
     26 #include <sys/epoll.h>
     27 #include <poll.h>
     28 #include <string.h>
     29 #include <errno.h>
     30 
     31 #include "tst_test.h"
     32 
     33 static int write_size, epfd, fds[2];
     34 
     35 static int get_writesize(void)
     36 {
     37 	int nfd, write_size = 0;
     38 	char buf[4096];
     39 	struct pollfd pfd[] = {
     40 		{.fd = fds[1], .events = POLLOUT},
     41 	};
     42 
     43 	memset(buf, 'a', sizeof(buf));
     44 
     45 	do {
     46 		write_size += SAFE_WRITE(0, fds[1], buf, sizeof(buf));
     47 		nfd = poll(pfd, 1, 1);
     48 		if (nfd == -1)
     49 			tst_brk(TBROK | TERRNO, "poll() failed");
     50 	} while (nfd > 0);
     51 
     52 	char read_buf[write_size];
     53 
     54 	SAFE_READ(1, fds[0], read_buf, sizeof(read_buf));
     55 
     56 	tst_res(TINFO, "Pipe buffer size is %i bytes", write_size);
     57 
     58 	return write_size;
     59 }
     60 
     61 static void setup(void)
     62 {
     63 	static struct epoll_event epevs[2] = {
     64 		{.events = EPOLLIN},
     65 		{.events = EPOLLOUT},
     66 	};
     67 
     68 	SAFE_PIPE(fds);
     69 
     70 	epevs[0].data.fd = fds[0];
     71 	epevs[1].data.fd = fds[1];
     72 
     73 	write_size = get_writesize();
     74 
     75 	epfd = epoll_create(3);
     76 	if (epfd == -1)
     77 		tst_brk(TBROK | TERRNO, "epoll_create() failed");
     78 
     79 	if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0]) ||
     80 	    epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[1])) {
     81 		tst_brk(TBROK | TERRNO, "epoll_ctl() failed");
     82 	}
     83 }
     84 
     85 static int has_event(struct epoll_event *epevs, int epevs_len,
     86 		     int fd, uint32_t events)
     87 {
     88 	int i;
     89 
     90 	for (i = 0; i < epevs_len; i++) {
     91 		if ((epevs[i].data.fd == fd) && (epevs[i].events == events))
     92 			return 1;
     93 	}
     94 
     95 	return 0;
     96 }
     97 
     98 static void dump_epevs(struct epoll_event *epevs, int epevs_len)
     99 {
    100 	int i;
    101 
    102 	for (i = 0; i < epevs_len; i++) {
    103 		tst_res(TINFO, "epevs[%d]: epoll.data.fd %d, epoll.events %x",
    104 			i, epevs[i].data.fd, epevs[i].events);
    105 	}
    106 }
    107 
    108 static void verify_epollout(void)
    109 {
    110 	struct epoll_event ret_evs = {.events = 0, .data.fd = 0};
    111 
    112 	TEST(epoll_wait(epfd, &ret_evs, 1, -1));
    113 
    114 	if (TEST_RETURN == -1) {
    115 		tst_res(TFAIL | TTERRNO, "epoll_wait() epollout failed");
    116 		return;
    117 	}
    118 
    119 	if (TEST_RETURN != 1) {
    120 		tst_res(TFAIL, "epoll_wait() returned %li, expected 1",
    121 			TEST_RETURN);
    122 		return;
    123 	}
    124 
    125 	if (ret_evs.data.fd != fds[1]) {
    126 		tst_res(TFAIL, "epoll.data.fd %i, expected %i",
    127 			ret_evs.data.fd, fds[1]);
    128 		return;
    129 	}
    130 
    131 	if (ret_evs.events != EPOLLOUT) {
    132 		tst_res(TFAIL, "epoll.events %x, expected EPOLLOUT %x",
    133 			ret_evs.events, EPOLLOUT);
    134 		return;
    135 	}
    136 
    137 	tst_res(TPASS, "epoll_wait() epollout");
    138 }
    139 
    140 static void verify_epollin(void)
    141 {
    142 	char write_buf[write_size];
    143 	char read_buf[sizeof(write_buf)];
    144 	struct epoll_event ret_evs = {.events = 0, .data.fd = 0};
    145 
    146 	memset(write_buf, 'a', sizeof(write_buf));
    147 
    148 	SAFE_WRITE(1, fds[1], write_buf, sizeof(write_buf));
    149 
    150 	TEST(epoll_wait(epfd, &ret_evs, 1, -1));
    151 
    152 	if (TEST_RETURN == -1) {
    153 		tst_res(TFAIL | TTERRNO, "epoll_wait() epollin failed");
    154 		goto end;
    155 	}
    156 
    157 	if (TEST_RETURN != 1) {
    158 		tst_res(TFAIL, "epoll_wait() returned %li, expected 1",
    159 			TEST_RETURN);
    160 		goto end;
    161 	}
    162 
    163 	if (ret_evs.data.fd != fds[0]) {
    164 		tst_res(TFAIL, "epoll.data.fd %i, expected %i",
    165 			ret_evs.data.fd, fds[0]);
    166 		goto end;
    167 	}
    168 
    169 	if (ret_evs.events != EPOLLIN) {
    170 		tst_res(TFAIL, "epoll.events %x, expected EPOLLIN %x",
    171 			ret_evs.events, EPOLLIN);
    172 		goto end;
    173 	}
    174 
    175 	tst_res(TPASS, "epoll_wait() epollin");
    176 
    177 end:
    178 	SAFE_READ(1, fds[0], read_buf, sizeof(write_buf));
    179 }
    180 
    181 static void verify_epollio(void)
    182 {
    183 	char write_buf[] = "Testing";
    184 	char read_buf[sizeof(write_buf)];
    185 	uint32_t events = EPOLLIN | EPOLLOUT;
    186 	struct epoll_event ret_evs[2];
    187 
    188 	SAFE_WRITE(1, fds[1], write_buf, sizeof(write_buf));
    189 
    190 	while (events) {
    191 		int events_matched = 0;
    192 
    193 		bzero(ret_evs, sizeof(ret_evs));
    194 		TEST(epoll_wait(epfd, ret_evs, 2, -1));
    195 
    196 		if (TEST_RETURN <= 0) {
    197 			tst_res(TFAIL | TTERRNO, "epoll_wait() returned %li",
    198 				TEST_RETURN);
    199 			goto end;
    200 		}
    201 
    202 		if ((events & EPOLLIN) &&
    203 		    has_event(ret_evs, 2, fds[0], EPOLLIN)) {
    204 			events_matched++;
    205 			events &= ~EPOLLIN;
    206 		}
    207 
    208 		if ((events & EPOLLOUT) &&
    209 		    has_event(ret_evs, 2, fds[1], EPOLLOUT)) {
    210 			events_matched++;
    211 			events &= ~EPOLLOUT;
    212 		}
    213 
    214 		if (TEST_RETURN != events_matched) {
    215 			tst_res(TFAIL,
    216 				"epoll_wait() returned unexpected events");
    217 			dump_epevs(ret_evs, 2);
    218 			goto end;
    219 		}
    220 	}
    221 
    222 	tst_res(TPASS, "epoll_wait() epollio");
    223 
    224 end:
    225 	SAFE_READ(1, fds[0], read_buf, sizeof(write_buf));
    226 }
    227 
    228 static void cleanup(void)
    229 {
    230 	if (epfd > 0)
    231 		SAFE_CLOSE(epfd);
    232 
    233 	if (fds[0]) {
    234 		SAFE_CLOSE(fds[0]);
    235 		SAFE_CLOSE(fds[1]);
    236 	}
    237 }
    238 
    239 static void do_test(unsigned int n)
    240 {
    241 	switch (n) {
    242 	case 0:
    243 		verify_epollout();
    244 	break;
    245 	case 1:
    246 		verify_epollin();
    247 	break;
    248 	case 2:
    249 		verify_epollio();
    250 	break;
    251 	}
    252 }
    253 
    254 static struct tst_test test = {
    255 	.setup = setup,
    256 	.cleanup = cleanup,
    257 	.test = do_test,
    258 	.tcnt = 3,
    259 };
    260