739 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			739 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  *
 | |
|  * Copyright (c) International Business Machines  Corp., 2001
 | |
|  *
 | |
|  * This program is free software;  you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation; either version 2 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 | |
|  * the GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program;  if not, write to the Free Software
 | |
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
|    File:        epoll-ltp.c
 | |
| 
 | |
|    Description:
 | |
|      Test the epoll_* system calls. This test program attempts to
 | |
|      be very thorough in exercising epoll_* system calls. Large
 | |
|      combinations of valid and invalid parameters are passed with
 | |
|      valid and invalid sequences. Due to the combinatorial nature
 | |
|      of this test program the test may take a "long" time to
 | |
|      execute.
 | |
| 
 | |
|    Total Tests: 2 (2 system calls are being tested for)
 | |
| 
 | |
|    Test Name:   epoll_create, epoll_ctl
 | |
| 
 | |
|    Test Assertion
 | |
|    & Strategy:  Test a variety of incorrect parameters for epoll_create
 | |
| 
 | |
|                 Then run a reasonable epoll_create and get a fd for the epoll
 | |
|                      set.
 | |
| 
 | |
|                 Next run epoll_ctl on that fd (epoll_fd) with a variety of
 | |
|                      incorrect parameters and a couple correct ones.
 | |
| 
 | |
|                 Finally ?How to thoroughly test epoll_wait?
 | |
| 
 | |
|    Author:      Matt Helsley <matthltc@us.ibm.com>
 | |
| 
 | |
|    History:     Created - May 22 2003 - Matt Helsley <matthltc@us.ibm.com>
 | |
|                 Added   -
 | |
| 
 | |
|    Notes: Currently we assume that the OS will never allocate an fd s.t.
 | |
|           fd == INT_MAX and that it will instead choose to allocate fds
 | |
|           from the "low" numbers. -MH
 | |
| 
 | |
|    Currently pokes epoll_create several times in 2 + NUM_RAND_ATTEMPTS ways
 | |
|              pokes epoll_ctl 27648 - (2 + NUM_RAND_ATTEMPTS) ways
 | |
|              does not poke epoll_wait
 | |
| 
 | |
|    TODO: change errno test code to build lists of possible errno values for
 | |
|             each erroneous parameter. Check that the errno value is in one
 | |
|             of the lists. Currently errno is not checked at all when multiple
 | |
|             erroneous parameters are passed in.
 | |
| 
 | |
|          test epoll_ctl with a large number of file descriptor events in the
 | |
|             set
 | |
| 
 | |
|    Link against epoll and ltp (-lepoll -lltp)
 | |
| 
 | |
| *******************************************************************************/
 | |
| 
 | |
| #ifndef _GNU_SOURCE
 | |
| #define _GNU_SOURCE
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <fcntl.h>
 | |
| #include <stdarg.h>
 | |
| #include <string.h>
 | |
| #include <signal.h>
 | |
| #include <assert.h>
 | |
| #include <limits.h>
 | |
| #include <ctype.h>
 | |
| #include <time.h>
 | |
| #include <errno.h>
 | |
| #include <signal.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/time.h>
 | |
| #include <sys/file.h>
 | |
| #include <sys/ioctl.h>
 | |
| #include <sys/mman.h>
 | |
| #include <sys/select.h>
 | |
| #include <sys/wait.h>
 | |
| 
 | |
| #include "config.h"
 | |
| #include "test.h"
 | |
| 
 | |
| char *TCID = "epoll01";
 | |
| int TST_TOTAL = 1;
 | |
| 
 | |
| #ifdef HAVE_SYS_EPOLL_H
 | |
| 
 | |
| #include <sys/epoll.h>
 | |
| 
 | |
| /* Local Defines */
 | |
| #if !defined(TRUE) && !defined(FALSE)
 | |
| #define TRUE  1
 | |
| #define FALSE 0
 | |
| #endif
 | |
| 
 | |
| #define NUM_RAND_ATTEMPTS 16
 | |
| #define BACKING_STORE_SIZE_HINT 32
 | |
| 
 | |
| /*
 | |
|   Define the beginning of a "protected region".
 | |
|   This is a region where a wide variety of errors
 | |
|   could occur or signals could arrive (including
 | |
|   SIGSEGV and SIGKILL).
 | |
| $
 | |
|   The test program uses this to catch those
 | |
|   conditions as best it can and continue testing.
 | |
| 
 | |
|   The region MUST be marked by a corresponding
 | |
|   PROTECT_REGION_END.
 | |
| 
 | |
|   DO NOT nest protected regions! i.e. Do not build
 | |
|   code of the form:
 | |
| 
 | |
| 	PROTECT_REGION_START
 | |
|               ...
 | |
| 	PROTECT_REGION_START
 | |
|               ...
 | |
| 	PROTECT_REGION_END
 | |
|               ...
 | |
| 	PROTECT_REGION_END
 | |
|  */
 | |
| #define PROTECT_REGION_START		\
 | |
| do {					\
 | |
| 	pid_t kid_pid;			\
 | |
| 	int kid_status;			\
 | |
| 					\
 | |
| 	tst_old_flush();			\
 | |
| 	kid_pid = FORK_OR_VFORK();	\
 | |
| 	if (kid_pid == 0) {
 | |
| 
 | |
| #define PROTECT_REGION_EXIT(errval) return (errval);
 | |
| 
 | |
| #define PROTECT_REGION_END(result, errval)					\
 | |
| 	return 0;								\
 | |
| 	} else {								\
 | |
| 	 waitpid(kid_pid, &kid_status, 0);					\
 | |
| 	 if (WIFEXITED(kid_status)) {						\
 | |
| 		(result) = WEXITSTATUS(kid_status);				\
 | |
| 	} else { /* Must have been signaled */					\
 | |
| 		(result) = (errval);						\
 | |
| 		if (WIFSIGNALED(kid_status))						\
 | |
| 			tst_resm(TFAIL, "Protected function test exited due to signal %d (%s)", \
 | |
| 				WTERMSIG(kid_status), strsignal(WTERMSIG(kid_status)));	\
 | |
| 		}								\
 | |
| 	}									\
 | |
| } while (0)
 | |
| 
 | |
| /*
 | |
|  * Call a function in a "protected" context.
 | |
|  * This protects the test program proper from segfaults
 | |
|  * and allows for the extraction of an integer return
 | |
|  * code.
 | |
|  *
 | |
|  * return only integer results.
 | |
|  */
 | |
| #define PROTECT_FUNC(fn, errval, epoll_fd) (					\
 | |
| {										\
 | |
| 	pid_t kid_pid;								\
 | |
| 	int kid_status;								\
 | |
| 										\
 | |
| 	tst_old_flush();								\
 | |
| 	kid_pid = FORK_OR_VFORK();						\
 | |
| 	if (kid_pid == 0) { /* Run the function */				\
 | |
| 		return fn(epoll_fd);						\
 | |
| 	} else {								\
 | |
| 		waitpid(kid_pid, &kid_status, 0);				\
 | |
| 		if (WIFEXITED(kid_status)) {					\
 | |
| 		kid_status = WEXITSTATUS(kid_status);				\
 | |
| 	} else { /* Must have been signaled */					\
 | |
| 		kid_status = (errval);						\
 | |
| 		if (WIFSIGNALED(kid_status))					\
 | |
| 			tst_resm(TFAIL, "Protected function test exited due to signal %d (%s)", \
 | |
| 						WTERMSIG(kid_status), strsignal(WTERMSIG(kid_status))); \
 | |
| 	}									\
 | |
| }										\
 | |
| kid_status = kid_status;})
 | |
| 
 | |
| /*
 | |
|  * Given the number of random size requests to test,
 | |
|  * test various boundary cases of epoll_create().
 | |
|  *
 | |
|  * Return the number of tests that failed. 0 indicates
 | |
|  * 100% passed.
 | |
|  */
 | |
| int test_epoll_create(unsigned int num_rand_attempts)
 | |
| {
 | |
| 	int epoll_fd = -1;
 | |
| 	int fd_set_size = -1;
 | |
| 	unsigned int attempt_count;
 | |
| 	unsigned int num_epoll_create_test_fails = 0;
 | |
| 	unsigned int num_epoll_create_test_calls = 0;
 | |
| 
 | |
| 	/* Negative set sizes */
 | |
| 	errno = 0;
 | |
| 	fd_set_size = -1;
 | |
| 	num_epoll_create_test_calls++;
 | |
| 	epoll_fd = epoll_create(fd_set_size);
 | |
| 	if (epoll_fd >= 0) {
 | |
| 		tst_resm(TFAIL | TERRNO,
 | |
| 			 "epoll_create with negative set size succeeded unexpectedly");
 | |
| 		num_epoll_create_test_fails++;
 | |
| 		close(epoll_fd);
 | |
| 	} else {
 | |
| 		if (errno != EINVAL) {
 | |
| 			tst_resm(TFAIL | TERRNO,
 | |
| 				 "epoll_create with negative set size didn't set errno to EINVAL");
 | |
| 			num_epoll_create_test_fails++;
 | |
| 		} else {
 | |
| 			tst_resm(TPASS, "epoll_create with negative set size");
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Large set sizes -- try several less than or equal to INT_MAX by some
 | |
| 	   small amount (expect num_rand_attempts to be approximately the
 | |
| 	   amount we'd like to go below INT_MAX). */
 | |
| 	fd_set_size = INT_MAX;
 | |
| 	for (attempt_count = num_rand_attempts; attempt_count > 0;
 | |
| 	     attempt_count--, fd_set_size--) {
 | |
| 		num_epoll_create_test_calls++;
 | |
| 		epoll_fd = epoll_create(fd_set_size);
 | |
| 		if (epoll_fd == -1) {
 | |
| 			if (errno != ENOMEM) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "epoll_create with large set size (size = %d)",
 | |
| 					 fd_set_size);
 | |
| 				num_epoll_create_test_fails++;
 | |
| 			} else {
 | |
| 				tst_resm(TPASS,
 | |
| 					 "epoll_create with large set size (size = %d)",
 | |
| 					 fd_set_size);
 | |
| 			}
 | |
| 		} else {
 | |
| 			tst_resm(TPASS,
 | |
| 				 "epoll_create with large set size (size = %d)",
 | |
| 				 fd_set_size);
 | |
| 			close(epoll_fd);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Random large set sizes */
 | |
| 	for (attempt_count = num_rand_attempts; attempt_count > 0;
 | |
| 	     attempt_count--) {
 | |
| 		fd_set_size = abs(rand() + SHRT_MAX) % INT_MAX;
 | |
| 		errno = 0;
 | |
| 		num_epoll_create_test_calls++;
 | |
| 		epoll_fd = epoll_create(fd_set_size);
 | |
| 		if (epoll_fd < 0) {
 | |
| 			if (errno != ENOMEM) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "epoll_create with random random large set size (size = %d)",
 | |
| 					 fd_set_size);
 | |
| 				num_epoll_create_test_fails++;
 | |
| 			} else {
 | |
| 				tst_resm(TPASS,
 | |
| 					 "epoll_create with random random large set size (size = %d)",
 | |
| 					 fd_set_size);
 | |
| 			}
 | |
| 		} else {
 | |
| 			tst_resm(TPASS,
 | |
| 				 "epoll_create with random large set size (size = %d)",
 | |
| 				 fd_set_size);
 | |
| 			close(epoll_fd);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	tst_resm(TINFO,
 | |
| 		 "Summary: Of %d tests, epoll_create failed %d (%3.0f%% passed).",
 | |
| 		 num_epoll_create_test_calls, num_epoll_create_test_fails,
 | |
| 		 ((float)
 | |
| 		  (num_epoll_create_test_calls - num_epoll_create_test_fails)
 | |
| 		  * 100.0f / (float)
 | |
| 		  num_epoll_create_test_calls));
 | |
| 	/* Return 0 on success. */
 | |
| 
 | |
| 	return num_epoll_create_test_fails;
 | |
| }
 | |
| 
 | |
| /* RES_PASS indicates a PASS result */
 | |
| #define RES_PASS 0
 | |
| 
 | |
| /*
 | |
|  * RES_FAIL_* indicates a FAIL result
 | |
|  * In brief, there are two things that can go wrong in a
 | |
|  * failure. The return value (result = epoll_ctl(...)) and
 | |
|  * the errno value may not match expectations. In this notation,
 | |
|  * MIS -> mismatch, MAT -> match, BAD -> bad, and IGN -> ignored.
 | |
|  *
 | |
|  * RETV_MIS_* indicates the return value was either 0 or 1, but did
 | |
|  * not match the expected return value
 | |
|  *
 | |
|  * _RETV_MAT_* indicates that the return value was 0 xor 1 and did
 | |
|  * match the expected value
 | |
|  *
 | |
|  *_RETV_BAD_* the return value was neither 0 nor 1.
 | |
|  *_ERRNO_MAT  the error number matched the expected number
 | |
|  *_ERRNO_MIS  the error number did not match the expected number
 | |
|  *_ERRNO_IGN  no error number was expected and so errno was ignored
 | |
|  *
 | |
|  * Keep these values below 256 as only 1 byte gets passed as a
 | |
|  * return value for the process. Note that RES_PASS is 0 which
 | |
|  * LTP interprets as a PASS.
 | |
|  */
 | |
| 
 | |
| /* Did not get the expected return value, but errno value was expected */
 | |
| #define RES_FAIL_RETV_MIS_ERRNO_MAT 1
 | |
| /* Did not get the expected return value, but errno value was expected */
 | |
| #define RES_FAIL_RETV_BAD_ERRNO_MAT 2
 | |
| /* Did get the expected return value, and errno value was not expected */
 | |
| #define RES_FAIL_RETV_MAT_ERRNO_MIS 3
 | |
| /* Return value was neither 0 nor -1. Mismatch in value of errno */
 | |
| #define RES_FAIL_RETV_BAD_ERRNO_MIS 4
 | |
| /* Did not get the expected return value and errno is irrelevant */
 | |
| #define RES_FAIL_RETV_MIS_ERRNO_IGN 5
 | |
| /* Return value was neither 0 nor -1. value of errno is irrelevant */
 | |
| #define RES_FAIL_RETV_BAD_ERRNO_IGN 6
 | |
| /* We expected multiple errors so we were unable to check errno for conformance */
 | |
| #define RES_PASS_RETV_MAT_ERRNO_IGN 7
 | |
| 
 | |
| static const char *result_strings[] = {
 | |
| 	"Passed",
 | |
| 	"Return value mismatched yet errno matched.",
 | |
| 	"Return value was bad    yet errno matched.",
 | |
| 	"Return value matched    yet errno mismatched.",
 | |
| 	"Return value was bad    and errno mismatched.",
 | |
| 	"Return value mismatched  so errno ignored.",
 | |
| 	"Return value was bad     so errno ignored.",
 | |
| 	"Return value matched    but errno ignored. (multiple errors expected)"
 | |
| };
 | |
| 
 | |
| /****************************************************************************************/
 | |
| /* This macro helps keep the code below understandable. It prints out the
 | |
|    failure message passed to it plus the parameters to the system call. */
 | |
| #define EPOLL_CTL_TEST_RESULTS_SHOW_PARAMS 1
 | |
| #if EPOLL_CTL_TEST_RESULTS_SHOW_PARAMS
 | |
| #define EPOLL_CTL_TEST_FAIL(msg , ...) \
 | |
| ({ \
 | |
| 	if (ev_ptr != NULL) { \
 | |
| 		tst_resm(TFAIL, ( "(epoll_ctl(%d,%08x,%d,%p = {%08x,%08d}) returned %d:%s)" ) , ##__VA_ARGS__ , \
 | |
| 			epoll_fds[epfd_index], epoll_ctl_ops[op_index], \
 | |
| 			epoll_fds[fd_index], ev_ptr, ev_ptr->events, ev_ptr->data.fd, errno, \
 | |
| 			strerror(errno)); \
 | |
| 	} else { \
 | |
| 		tst_resm(TFAIL, ( "(epoll_ctl(%d,%08x,%d,%p) returned %d:%s)" ) , ##__VA_ARGS__  , \
 | |
| 			epoll_fds[epfd_index], epoll_ctl_ops[op_index], \
 | |
| 			epoll_fds[fd_index], ev_ptr, errno, strerror(errno)); \
 | |
| 	} \
 | |
| })
 | |
| 
 | |
| #define EPOLL_CTL_TEST_PASS(msg , ...) \
 | |
| ({ \
 | |
| 	if (ev_ptr != NULL) { \
 | |
| 		tst_resm(TPASS, ( "(epoll_ctl(%d,%08x,%d,%p = {%08x,%08d}) returned %d:%s)" ) , ##__VA_ARGS__ , \
 | |
| 			epoll_fds[epfd_index], epoll_ctl_ops[op_index], \
 | |
| 			epoll_fds[fd_index], ev_ptr, ev_ptr->events, ev_ptr->data.fd, errno, \
 | |
| 			strerror(errno)); \
 | |
| 	} else { \
 | |
| 		tst_resm(TPASS, ( "(epoll_ctl(%d,%08x,%d,%p) returned %d:%s)" ) , ##__VA_ARGS__  , \
 | |
| 			epoll_fds[epfd_index], epoll_ctl_ops[op_index], \
 | |
| 			epoll_fds[fd_index], ev_ptr, errno, strerror(errno)); \
 | |
| 	} \
 | |
| })
 | |
| #else
 | |
| #define EPOLL_CTL_TEST_FAIL(msg , ...) tst_resm(TFAIL, msg , ##__VA_ARGS__)
 | |
| #define EPOLL_CTL_TEST_PASS(msg , ...) tst_resm(TPASS, msg , ##__VA_ARGS__)
 | |
| #endif
 | |
| 
 | |
| /****************************************************************************************/
 | |
| 
 | |
| int test_epoll_ctl(int epoll_fd)
 | |
| {
 | |
| 	int fds[] = { -1, INT_MAX };
 | |
| 	int epoll_fds[] = { 0, -1, 0, INT_MAX };
 | |
| 	int epoll_events[64];
 | |
| 	/* The list of operations to try AND THE ORDER THEY ARE TRIED IN */
 | |
| 	int epoll_ctl_ops[] =
 | |
| 	    { EPOLL_CTL_DEL, EPOLL_CTL_MOD, EPOLL_CTL_ADD, EPOLL_CTL_MOD,
 | |
| 		EPOLL_CTL_DEL, EPOLL_CTL_MOD, EPOLL_CTL_DEL, INT_MAX, -1
 | |
| 	};
 | |
| 	struct epoll_event event;
 | |
| 	char event_mem[sizeof(struct epoll_event) * 2];
 | |
| 	struct epoll_event *unaligned_event_ptr;
 | |
| 
 | |
| 	/* Indices into lists */
 | |
| 	int index = 0;		/* multi-use index. First uses are to initialize
 | |
| 				   lists. Second use is to iterate over the implicit
 | |
| 				   list of structs to pass in */
 | |
| 	unsigned int epfd_index;	/* index into fd list for the epfd parameter */
 | |
| 	unsigned int event_index;	/* index into event list for the events field of the
 | |
| 					   struct epoll_event parameter */
 | |
| 	unsigned int fd_index;	/* index into fd list for the fd parameter */
 | |
| 	unsigned int op_index;	/* index into the list of operations for the op
 | |
| 				   parameter */
 | |
| 	unsigned int num_epoll_ctl_test_fails = 0;
 | |
| 	unsigned int num_epoll_ctl_test_calls = 0;
 | |
| 
 | |
| 	/* Generate all possible combinations of events (2^6 == 64)
 | |
| 	   Assume we know nothing about the EPOLL event types _except_
 | |
| 	   that they describe bits in a set. */
 | |
| 	for (index = 0; index < 64; index++) {
 | |
| 		epoll_events[index] = ((EPOLLIN * ((index & 0x01) >> 0)) |
 | |
| 				       (EPOLLOUT * ((index & 0x02) >> 1)) |
 | |
| 				       (EPOLLPRI * ((index & 0x04) >> 2)) |
 | |
| 				       (EPOLLERR * ((index & 0x08) >> 3)) |
 | |
| 				       (EPOLLHUP * ((index & 0x10) >> 4)) |
 | |
| 				       (EPOLLET * ((index & 0x20) >> 5)));
 | |
| 	}
 | |
| 
 | |
| 	/* Get a pointer to an unaligned struct epoll_event */
 | |
| 	{
 | |
| 		char *unalign_ptr = event_mem;
 | |
| 
 | |
| 		unalign_ptr =
 | |
| 		    unalign_ptr + (((unsigned long)unalign_ptr & 1) ? 0 : 1);
 | |
| 		unaligned_event_ptr = (struct epoll_event *)unalign_ptr;
 | |
| 	}
 | |
| 
 | |
| 	/* One of the fds we want to test is the valid one */
 | |
| 	epoll_fds[0] = epoll_fd;
 | |
| 
 | |
| 	/* Test out all of the interesting combinations. This is going to
 | |
| 	   take a while (in compute cycles). It took less than 1 minute to
 | |
| 	   run on a PIII 500 without checking the results. */
 | |
| 	for (index = 0; index < 3; index++) {
 | |
| 		struct epoll_event *ev_ptr = NULL;
 | |
| 
 | |
| 		switch (index) {
 | |
| 		case 0:	/* Pass aligned struct */
 | |
| 			event.data.u64 = 0;
 | |
| 			ev_ptr = &event;
 | |
| 			break;
 | |
| 		case 1:	/* Pass unaligned struct */
 | |
| 			unaligned_event_ptr->data.u64 = 0;
 | |
| 			ev_ptr = unaligned_event_ptr;
 | |
| 			break;
 | |
| 		case 2:
 | |
| 		default:	/* Pass NULL ptr */
 | |
| 			ev_ptr = NULL;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		for (epfd_index = 0;
 | |
| 		     epfd_index < (sizeof(epoll_fds) / sizeof(int));
 | |
| 		     epfd_index++) {
 | |
| 			for (event_index = 0;
 | |
| 			     event_index < (sizeof(epoll_events) / sizeof(int));
 | |
| 			     event_index++) {
 | |
| 				for (fd_index = 0;
 | |
| 				     fd_index < (sizeof(fds) / sizeof(int));
 | |
| 				     fd_index++) {
 | |
| 					/* Now epoll_fd is a descriptor that references the set of
 | |
| 					   file descriptors we are interested in. Next we test epoll_ctl */
 | |
| 					for (op_index = 0;
 | |
| 					     op_index <
 | |
| 					     (sizeof(epoll_ctl_ops) /
 | |
| 					      sizeof(int)); op_index++) {
 | |
| 						int result;
 | |
| 						int expected_errno = 0;
 | |
| 						int num_errors_expected = 0;
 | |
| 
 | |
| 						if (ev_ptr != NULL)
 | |
| 							ev_ptr->events =
 | |
| 							    epoll_events
 | |
| 							    [event_index];
 | |
| 
 | |
| 						/* Perform the call itself. Put it in a protected region which
 | |
| 						   returns -1 in the variable result if a protection violation
 | |
| 						   occurs (see PROTECT_REGION_END for the result) */
 | |
| 						PROTECT_REGION_START errno = 0;
 | |
| 
 | |
| 						/* NOTE that we are assuming that epoll will operate across
 | |
| 						   a fork() call such that a subsequent fork() in the parent
 | |
| 						   will also manipulate the same set */
 | |
| 						result =
 | |
| 						    epoll_ctl(epoll_fds
 | |
| 							      [epfd_index],
 | |
| 							      epoll_ctl_ops
 | |
| 							      [op_index],
 | |
| 							      fds[fd_index],
 | |
| 							      ev_ptr);
 | |
| 
 | |
| 						/* We can't test errno resulting from the epoll_ctl call outside of
 | |
| 						   the PROTECT_REGION hence we do not have a PROTECT_REGION_END
 | |
| 						   here */
 | |
| 
 | |
| 						/*
 | |
| 						   Test the results. Look for appropriate error conditions
 | |
| 						 */
 | |
| 
 | |
| 						/* Check the epfd */
 | |
| 						if (epoll_fds[epfd_index] !=
 | |
| 						    epoll_fd) {
 | |
| 							/* Expect an error */
 | |
| 							if (epoll_fds
 | |
| 							    [epfd_index] == 0)
 | |
| 								expected_errno =
 | |
| 								    EINVAL;
 | |
| 							else	/* epfd is not a valid file descriptor since it is
 | |
| 								   neither epoll_fd nor stdin */
 | |
| 								expected_errno =
 | |
| 								    EBADF;
 | |
| 							num_errors_expected++;
 | |
| 						}
 | |
| 
 | |
| 						switch (epoll_ctl_ops[op_index]) {
 | |
| 						case EPOLL_CTL_ADD:
 | |
| 						case EPOLL_CTL_MOD:
 | |
| 						case EPOLL_CTL_DEL:
 | |
| 							break;
 | |
| 						default:	/* Expect an error */
 | |
| 							expected_errno = EINVAL;
 | |
| 							num_errors_expected++;
 | |
| 							break;
 | |
| 						}
 | |
| 
 | |
| 						expected_errno = EPERM;
 | |
| 						num_errors_expected++;
 | |
| 
 | |
| 						if (ev_ptr == NULL) {
 | |
| 							expected_errno = EINVAL;
 | |
| 							num_errors_expected++;
 | |
| 						} else if ((ev_ptr == &event)
 | |
| 							   || (ev_ptr ==
 | |
| 							       unaligned_event_ptr))
 | |
| 						{
 | |
| 							if (ev_ptr->events == 0) {
 | |
| 								expected_errno =
 | |
| 								    EINVAL;
 | |
| 								num_errors_expected++;
 | |
| 							}
 | |
| 
 | |
| 							for (index = 1;
 | |
| 							     index < 64;
 | |
| 							     index++) {
 | |
| 								if ((int)ev_ptr->events != epoll_events[index]) {
 | |
| 									expected_errno
 | |
| 									    =
 | |
| 									    EINVAL;
 | |
| 									num_errors_expected++;
 | |
| 								}
 | |
| 							}
 | |
| 						} else {
 | |
| 							/* Do not expect an error */
 | |
| 						}
 | |
| 
 | |
| 						if (num_errors_expected == 0) {
 | |
| 							/* We did not expect an error */
 | |
| 							if (result == 0) {
 | |
| 								/* We didn't get an error. Think of this as RES_PASS_RETV_MAT_ERRNO_IGN */
 | |
| 								return RES_PASS;
 | |
| 							} else if (result == -1) {	/* The return value is -1, so it's not bad */
 | |
| 								return
 | |
| 								    RES_FAIL_RETV_MIS_ERRNO_IGN;
 | |
| 							} else {
 | |
| 								return
 | |
| 								    RES_FAIL_RETV_BAD_ERRNO_IGN;
 | |
| 							}
 | |
| 						} else if (num_errors_expected
 | |
| 							   == 1) {
 | |
| 							/* We expected an error */
 | |
| 							if (result == 0) {
 | |
| 								return RES_FAIL_RETV_MIS_ERRNO_IGN;	/* Unexpected success */
 | |
| 							} else if (result == -1) {
 | |
| 								/* We got an error. Check errno */
 | |
| 								if (errno ==
 | |
| 								    expected_errno)
 | |
| 								{
 | |
| 									return RES_PASS;	/* think of this as RETV_MAT_ERRNO_MAT */
 | |
| 								} else {
 | |
| 									return
 | |
| 									    RES_FAIL_RETV_MAT_ERRNO_MIS;
 | |
| 								}
 | |
| 							} else {
 | |
| 								/* We got a bad return code! Interpret this as
 | |
| 								   getting an error and check errno. */
 | |
| 								if (errno ==
 | |
| 								    expected_errno)
 | |
| 									return
 | |
| 									    RES_FAIL_RETV_BAD_ERRNO_MAT;
 | |
| 								else
 | |
| 									return
 | |
| 									    RES_FAIL_RETV_BAD_ERRNO_MIS;
 | |
| 							}
 | |
| 						} else if (num_errors_expected >
 | |
| 							   1) {
 | |
| 							/* We expected multiple errors */
 | |
| 							if (result == 0) {
 | |
| 								return RES_FAIL_RETV_MIS_ERRNO_IGN;	/* Unexpected success */
 | |
| 							} else if (result == -1) {
 | |
| 								/* We got an error. Check errno */
 | |
| 								if (errno ==
 | |
| 								    expected_errno)
 | |
| 								{
 | |
| 									return RES_PASS;	/* think of this as RETV_MAT_ERRNO_MAT */
 | |
| 								} else {
 | |
| 									/* Ignore errno because the desired value is unknowable
 | |
| 									   without looking at the structure of the code. */
 | |
| 									return
 | |
| 									    RES_PASS_RETV_MAT_ERRNO_IGN;
 | |
| 								}
 | |
| 							} else {
 | |
| 								/* We got a bad return code! Interpret this as
 | |
| 								   getting an error and check errno. */
 | |
| 								if (errno ==
 | |
| 								    expected_errno)
 | |
| 									/* Don't Ignore errno because the desired value
 | |
| 									   happened to match what we expected. */
 | |
| 									return
 | |
| 									    RES_FAIL_RETV_BAD_ERRNO_MAT;
 | |
| 								else
 | |
| 									/* Ignore errno because the desired value is unknowable
 | |
| 									   without looking at the structure of the code. */
 | |
| 									return
 | |
| 									    RES_FAIL_RETV_BAD_ERRNO_IGN;
 | |
| 							}
 | |
| 						}
 | |
| 
 | |
| 						/* All "return"s between PROTECT_REGION_BEGIN
 | |
| 						   and PROTECT_REGION_END place their value in
 | |
| 						   the result parameter. If the region caused
 | |
| 						   a protection violation (segfault or otherwise)
 | |
| 						   then the result is set to the second parameter's
 | |
| 						   value (-1 in this case). */
 | |
| 						PROTECT_REGION_END(result, -1);
 | |
| 
 | |
| 						/* Count the number of tests run */
 | |
| 						num_epoll_ctl_test_calls++;
 | |
| 
 | |
| 						/* Now test the result */
 | |
| 						if (!((result == RES_PASS)
 | |
| 						      || (result ==
 | |
| 							  RES_PASS_RETV_MAT_ERRNO_IGN)))
 | |
| 						{
 | |
| 							if (result >
 | |
| 							   (int)(sizeof(result_strings) /
 | |
| 							     sizeof(const char
 | |
| 								    *))) {
 | |
| 								/* Returned a result which has no corresponding text description */
 | |
| 								EPOLL_CTL_TEST_FAIL
 | |
| 								    ("FIXME FIX ME BUG in Test Program itself!");
 | |
| 							} else {
 | |
| 								if (result == -1)	/* Segfault during epoll_ctl call */
 | |
| 									EPOLL_CTL_TEST_FAIL
 | |
| 									    ("Test arguments caused abnormal exit.");
 | |
| 								else	/* The 'normal' failure */
 | |
| 									EPOLL_CTL_TEST_FAIL
 | |
| 									    ((result_strings[result]));
 | |
| 							}
 | |
| 							num_epoll_ctl_test_fails++;
 | |
| #ifdef DEBUG
 | |
| 						} else	/* The call of epoll_ctl behaved as expected */
 | |
| 							EPOLL_CTL_TEST_PASS((result_strings[result]));
 | |
| #else
 | |
| 						}
 | |
| #endif
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		close(epoll_fd);
 | |
| 	}
 | |
| 
 | |
| 	tst_resm(TINFO,
 | |
| 		 "Summary: Of %d tests, epoll_ctl failed %d (%3.0f%% passed).",
 | |
| 		 num_epoll_ctl_test_calls, num_epoll_ctl_test_fails,
 | |
| 		 ((float)(num_epoll_ctl_test_calls - num_epoll_ctl_test_fails) *
 | |
| 		  100.0f / (float)num_epoll_ctl_test_calls));
 | |
| 	return (num_epoll_ctl_test_fails / num_epoll_ctl_test_calls);
 | |
| }
 | |
| 
 | |
| int main(void)
 | |
| {
 | |
| 	int epoll_fd;
 | |
| 	struct timeval tv;
 | |
| 	int last_result;
 | |
| 
 | |
| 	tst_resm(TINFO, "testing if epoll() system call works");
 | |
| 
 | |
| 	/* Get the current time */
 | |
| 	if (gettimeofday(&tv, NULL) != 0) {
 | |
| 		tst_brkm(TBROK | TERRNO, NULL, "gettimeofday failed");
 | |
| 	} else {
 | |
| 		tst_resm(TINFO, "gettimeofday() works");
 | |
| 	}
 | |
| 
 | |
| 	/* Set up RNG */
 | |
| 	srand(tv.tv_usec);
 | |
| 	tst_resm(TINFO,
 | |
| 		 "random number seeded with gettimeofday() [seed = %ld] works",
 | |
| 		 tv.tv_usec);
 | |
| 
 | |
| 	tst_resm(TINFO, "Testing epoll_create");
 | |
| 	/* Testing epoll_create with some different sizes */
 | |
| 	last_result = PROTECT_FUNC(test_epoll_create, -1, NUM_RAND_ATTEMPTS);
 | |
| 	if (last_result != 0) {
 | |
| 		/* create test(s) failed */
 | |
| 	}
 | |
| 
 | |
| 	/* Create an epoll_fd for testing epoll_ctl */
 | |
| 	epoll_fd = epoll_create(BACKING_STORE_SIZE_HINT);
 | |
| 	if (epoll_fd < 0) {
 | |
| 		tst_brkm(TFAIL | TERRNO, NULL, "epoll_create failed");
 | |
| 	}
 | |
| 
 | |
| 	tst_resm(TINFO, "Testing epoll_ctl");
 | |
| 	last_result = PROTECT_FUNC(test_epoll_ctl, -1, epoll_fd);
 | |
| 	if (last_result != 0) {
 | |
| 		/* ctl test(s) failed */
 | |
| 	}
 | |
| 
 | |
| 	tst_exit();
 | |
| }
 | |
| 
 | |
| #else
 | |
| 
 | |
| int main(void)
 | |
| {
 | |
| 	tst_brkm(TCONF, NULL, "No epoll support found.");
 | |
| }
 | |
| 
 | |
| #endif
 |