Home | History | Annotate | Download | only in ppoll
      1 /*
      2  * Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd
      3  *          Author(s): Takahiro Yasui <takahiro.yasui.mp (at) hitachi.com>,
      4  *		       Yumiko Sugita <yumiko.sugita.yf (at) hitachi.com>,
      5  *		       Satoshi Fujiwara <sa-fuji (at) sdl.hitachi.co.jp>
      6  * Copyright (c) 2016 Linux Test Project
      7  *
      8  * This program is free software;  you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     16  * the GNU General Public License for more details.
     17  */
     18 
     19 #ifndef _GNU_SOURCE
     20 #define _GNU_SOURCE
     21 #endif
     22 
     23 #include <errno.h>
     24 #include <poll.h>
     25 #include <signal.h>
     26 #include <stdlib.h>
     27 #include <sys/types.h>
     28 #include <sys/wait.h>
     29 #include "lapi/syscalls.h"
     30 #include "ltp_signal.h"
     31 #include "tst_sig_proc.h"
     32 #include "tst_test.h"
     33 
     34 /* Older versions of glibc don't publish this constant's value. */
     35 #ifndef POLLRDHUP
     36 #define POLLRDHUP 0x2000
     37 #endif
     38 
     39 #define TYPE_NAME(x) .ttype = x, .desc = #x
     40 
     41 struct test_case {
     42 	int ttype;		   /* test type (enum) */
     43 	const char *desc;	   /* test description (name) */
     44 	int ret;		   /* expected ret code */
     45 	int err;		   /* expected errno code */
     46 	short expect_revents;	   /* expected revents value */
     47 	unsigned int nfds;	   /* nfds ppoll parameter */
     48 	sigset_t *sigmask;	   /* sigmask ppoll parameter */
     49 	sigset_t *sigmask_cur;	   /* sigmask set for current process */
     50 	struct timespec *ts;	   /* ts ppoll parameter */
     51 	struct pollfd *fds;	   /* fds ppoll parameter */
     52 	int sigint_count;	   /* if > 0, spawn process to send SIGINT */
     53 				   /* 'count' times to current process */
     54 	unsigned int sigint_delay; /* delay between SIGINT signals */
     55 };
     56 
     57 enum test_type {
     58 	NORMAL,
     59 	MASK_SIGNAL,
     60 	TIMEOUT,
     61 	FD_ALREADY_CLOSED,
     62 	SEND_SIGINT,
     63 	SEND_SIGINT_RACE_TEST,
     64 	INVALID_NFDS,
     65 	INVALID_FDS,
     66 };
     67 
     68 static int fd1 = -1;
     69 static sigset_t sigmask_empty, sigmask_sigint;
     70 static struct pollfd fds_good[1], fds_already_closed[1];
     71 
     72 static struct timespec ts_short = {
     73 	.tv_sec = 0,
     74 	.tv_nsec = 200000000,
     75 };
     76 static struct timespec ts_long = {
     77 	.tv_sec = 2,
     78 	.tv_nsec = 0,
     79 };
     80 
     81 /* Test cases
     82  *
     83  *   test status of errors on man page
     84  *
     85  *   EBADF              can't check because EBADF never happen even though
     86  *                      fd was invalid. In this case, information of invalid
     87  *                      fd is set in revents
     88  *   EFAULT             v ('fds' array in the invalid address space)
     89  *   EINTR              v (a non blocked signal was caught)
     90  *   EINVAL             v ('nfds' is over the 'RLIMIT_NOFILE' value)
     91  *   ENOMEM             can't check because it's difficult to create no-memory
     92  */
     93 
     94 static struct test_case tcase[] = {
     95 	{
     96 		TYPE_NAME(NORMAL),
     97 		.expect_revents = POLLIN | POLLOUT,
     98 		.ret = 1,
     99 		.err = 0,
    100 		.nfds = 1,
    101 		.ts = &ts_long,
    102 		.fds = fds_good,
    103 	},
    104 	{
    105 		TYPE_NAME(MASK_SIGNAL),
    106 		.ret = 0,
    107 		.err = 0,
    108 		.nfds = 0,
    109 		.sigmask = &sigmask_sigint,
    110 		.ts = &ts_short,
    111 		.fds = fds_good,
    112 		.sigint_count = 4,
    113 		.sigint_delay = 100000,
    114 	},
    115 	{
    116 		TYPE_NAME(TIMEOUT),
    117 		.ret = 0,
    118 		.err = 0,
    119 		.nfds = 0,
    120 		.ts = &ts_short,
    121 		.fds = fds_good,
    122 	},
    123 	{
    124 		TYPE_NAME(FD_ALREADY_CLOSED),
    125 		.expect_revents = POLLNVAL,
    126 		.ret = 1,
    127 		.err = 0,
    128 		.nfds = 1,
    129 		.ts = &ts_long,
    130 		.fds = fds_already_closed,
    131 	},
    132 	{
    133 		TYPE_NAME(SEND_SIGINT),
    134 		.ret = -1,
    135 		.err = EINTR,
    136 		.nfds = 0,
    137 		.ts = &ts_long,
    138 		.fds = fds_good,
    139 		.sigint_count = 40,
    140 		.sigint_delay = 100000,
    141 	},
    142 	{
    143 		TYPE_NAME(SEND_SIGINT_RACE_TEST),
    144 		.ret = -1,
    145 		.err = EINTR,
    146 		.nfds = 0,
    147 		.sigmask = &sigmask_empty,
    148 		.sigmask_cur = &sigmask_sigint,
    149 		.ts = &ts_long,
    150 		.fds = fds_good,
    151 		.sigint_count = 1,
    152 		.sigint_delay = 0,
    153 	},
    154 	{
    155 		TYPE_NAME(INVALID_NFDS),
    156 		.ret = -1,
    157 		.err = EINVAL,
    158 		.nfds = -1,
    159 		.ts = &ts_long,
    160 		.fds = fds_good,
    161 	},
    162 	{
    163 		TYPE_NAME(INVALID_FDS),
    164 		.ret = -1,
    165 		.err = EFAULT,
    166 		.nfds = 1,
    167 		.ts = &ts_long,
    168 		.fds = (struct pollfd *) -1,
    169 	},
    170 };
    171 
    172 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
    173 {
    174 }
    175 
    176 static void setup(void)
    177 {
    178 	int fd2;
    179 
    180 	SAFE_SIGNAL(SIGINT, sighandler);
    181 
    182 	if (sigemptyset(&sigmask_empty) == -1)
    183 		tst_brk(TBROK | TERRNO, "sigemptyset");
    184 	if (sigemptyset(&sigmask_sigint) == -1)
    185 		tst_brk(TBROK | TERRNO, "sigemptyset");
    186 	if (sigaddset(&sigmask_sigint, SIGINT) == -1)
    187 		tst_brk(TBROK | TERRNO, "sigaddset");
    188 
    189 	fd1 = SAFE_OPEN("testfile1", O_CREAT | O_EXCL | O_RDWR,
    190 		S_IRUSR | S_IWUSR);
    191 	fds_good[0].fd = fd1;
    192 	fds_good[0].events = POLLIN | POLLPRI | POLLOUT | POLLRDHUP;
    193 	fds_good[0].revents = 0;
    194 
    195 	fd2 = SAFE_OPEN("testfile2", O_CREAT | O_EXCL | O_RDWR,
    196 		S_IRUSR | S_IWUSR);
    197 	fds_already_closed[0].fd = fd2;
    198 	fds_already_closed[0].events = POLLIN | POLLPRI | POLLOUT | POLLRDHUP;
    199 	fds_already_closed[0].revents = 0;
    200 	SAFE_CLOSE(fd2);
    201 }
    202 
    203 static void cleanup(void)
    204 {
    205 	if (fd1 != -1)
    206 		SAFE_CLOSE(fd1);
    207 }
    208 
    209 static void do_test(unsigned int i)
    210 {
    211 	pid_t pid = 0;
    212 	int sys_ret, sys_errno = 0, dummy;
    213 	struct test_case *tc = &tcase[i];
    214 	struct timespec ts, *tsp = NULL;
    215 
    216 	if (tc->ts) {
    217 		memcpy(&ts, tc->ts, sizeof(ts));
    218 		tsp = &ts;
    219 	}
    220 
    221 	tst_res(TINFO, "case %s", tc->desc);
    222 
    223 	/* setup */
    224 	if (tc->sigmask_cur) {
    225 	       if (sigprocmask(SIG_SETMASK, tc->sigmask_cur, NULL) == -1)
    226 			tst_brk(TBROK, "sigprocmask");
    227 	}
    228 	if (tc->sigint_count > 0) {
    229 		pid = create_sig_proc(SIGINT, tc->sigint_count,
    230 			tc->sigint_delay);
    231 	}
    232 
    233 	/* test */
    234 	errno = 0;
    235 	sys_ret = tst_syscall(__NR_ppoll, tc->fds, tc->nfds, tsp,
    236 		tc->sigmask, SIGSETSIZE);
    237 	sys_errno = errno;
    238 
    239 	/* cleanup */
    240 	if (tc->sigmask_cur) {
    241 		if (sigprocmask(SIG_SETMASK, &sigmask_empty, NULL) == -1)
    242 			tst_brk(TBROK, "sigprocmask");
    243 	}
    244 	if (pid > 0) {
    245 		kill(pid, SIGTERM);
    246 		SAFE_WAIT(&dummy);
    247 	}
    248 
    249 	/* result check */
    250 	if (tc->expect_revents) {
    251 		if (tc->fds[0].revents == tc->expect_revents)
    252 			tst_res(TPASS, "revents=0x%04x", tc->expect_revents);
    253 		else
    254 			tst_res(TFAIL, "revents=0x%04x, expected=0x%04x",
    255 				tc->fds[0].revents, tc->expect_revents);
    256 	}
    257 	if (tc->ret >= 0 && tc->ret == sys_ret) {
    258 		tst_res(TPASS, "ret: %d", sys_ret);
    259 	} else if (tc->ret == -1 && sys_ret == -1 && sys_errno == tc->err) {
    260 		tst_res(TPASS, "ret: %d, errno: %s (%d)", sys_ret,
    261 			tst_strerrno(sys_errno), sys_errno);
    262 	} else {
    263 		tst_res(TFAIL, "ret: %d, exp: %d, ret_errno: %s (%d),"
    264 			" exp_errno: %s (%d)", sys_ret, tc->ret,
    265 			tst_strerrno(sys_errno), sys_errno,
    266 			tst_strerrno(tc->err), tc->err);
    267 	}
    268 }
    269 
    270 static struct tst_test test = {
    271 	.tcnt = ARRAY_SIZE(tcase),
    272 	.test = do_test,
    273 	.setup = setup,
    274 	.cleanup = cleanup,
    275 	.forks_child = 1,
    276 	.needs_tmpdir = 1,
    277 };
    278