| /******************************************************************************/ |
| /* */ |
| /* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) |
| |
| *******************************************************************************/ |
| #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> |
| |
| /* epoll-lib header */ |
| #include "epoll.h" |
| |
| /* Harness Specific Include Files. */ |
| #include "test.h" |
| #include "usctest.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 |
| |
| /* Dummy function for tst_brk* */ |
| extern void cleanup (void) |
| {} |
| |
| /* |
| 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_flush(); \ |
| kid_pid = fork(); \ |
| 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 exitted due to signal %d (%s)\n", \ |
| 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_flush(); \ |
| kid_pid = fork(); \ |
| 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 exitted due to signal %d (%s)\n", \ |
| WTERMSIG(kid_status), strsignal(WTERMSIG(kid_status))); \ |
| } \ |
| } \ |
| kid_status = kid_status;}) |
| |
| |
| /* Extern Global Variables */ |
| extern int Tst_count; /* counter for tst_xxx routines. */ |
| extern char *TESTDIR; /* temporary dir created by tst_tmpdir() */ |
| |
| /* Global Variables */ |
| char *TCID = "sys_epoll02"; /* test program identifier. */ |
| int TST_TOTAL = 1; /* total number of tests in this file. */ |
| |
| /* |
| 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, "epoll_create with negative set size returned a valid fd (errno = %d:%s)", errno, strerror(errno)); |
| num_epoll_create_test_fails++; |
| close(epoll_fd); |
| } else { |
| if (errno != EINVAL){ |
| tst_resm(TFAIL, "epoll_create with negative set size failed to set errno to EINVAL (%d:%s)", errno, strerror(errno)); |
| num_epoll_create_test_fails++; |
| } else { |
| tst_resm(TPASS, "epoll_create with negative set size"); |
| } |
| } |
| |
| /* Zero set sizes */ |
| errno = 0; |
| fd_set_size = 0; |
| num_epoll_create_test_calls++; |
| epoll_fd = epoll_create(fd_set_size); |
| if (epoll_fd >= 0){ |
| tst_resm(TFAIL, "epoll_create with zero set size returned a valid fd (errno = %d:%s)", errno, strerror(errno)); |
| num_epoll_create_test_fails++; |
| close(epoll_fd); |
| } else { |
| if (errno != EINVAL){ |
| tst_resm(TFAIL, "epoll_create with zero set size failed to set errno to EINVAL (%d:%s)", errno, strerror(errno)); |
| num_epoll_create_test_fails++; |
| } else { |
| tst_resm(TPASS, "epoll_create with zero 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).\n", 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 |
| failiure. 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. |
| */ |
| #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 not get the expected return |
| value, but errno value was expected */ |
| #define RES_FAIL_RETV_MAT_ERRNO_MIS 3 /* Did get the expected return |
| value, and errno value was not expected */ |
| #define RES_FAIL_RETV_BAD_ERRNO_MIS 4 /* Return value was neither 0 nor -1. |
| Mismatch in value of errno */ |
| #define RES_FAIL_RETV_MIS_ERRNO_IGN 5 /* Did not get the expected return |
| value and errno is irrelevant */ |
| #define RES_FAIL_RETV_BAD_ERRNO_IGN 6 /* Return value was neither 0 nor -1. |
| value of errno is irrelevant */ |
| #define RES_PASS_RETV_MAT_ERRNO_IGN 7 /* We expected multiple errors so we |
| were unable to check errno for |
| conformance */ |
| |
| 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 |
| failiure 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,%0.8x,%d,%p = {%0.8x,%0.8d}) 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, errno, \ |
| strerror(errno)); \ |
| } else { \ |
| tst_resm(TFAIL, ( "(epoll_ctl(%d,%0.8x,%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,%0.8x,%d,%p = {%0.8x,%0.8d}) 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, errno, \ |
| strerror(errno)); \ |
| } else { \ |
| tst_resm(TPASS, ( "(epoll_ctl(%d,%0.8x,%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, (const char*)(msg) , ##__VA_ARGS__) |
| #define EPOLL_CTL_TEST_PASS(msg , ...) tst_resm(TPASS, (const char*)(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 + ((((int)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 (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){ |
| return RES_PASS; /* We didn't get an error. Think of this as RES_PASS_RETV_MAT_ERRNO_IGN */ |
| } 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 > 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' failiure */ |
| EPOLL_CTL_TEST_FAIL((result_strings[result])); |
| } |
| num_epoll_ctl_test_fails++; |
| } else /* The call of epoll_ctl behaved as expected */ |
| EPOLL_CTL_TEST_PASS((result_strings[result])); |
| |
| /* Just to be safe, undefine our macros */ |
| #undef EPOLL_CTL_TEST_FAIL |
| #undef EPOLL_CTL_TEST_PASS |
| #undef PROTECT_REGION_BEGIN |
| #undef PROTECT_REGION_END |
| } |
| } |
| } |
| } |
| close(epoll_fd); |
| } |
| |
| tst_resm(TINFO, "Summary: Of %d tests, epoll_ctl failed %d (%3.0f%% passed).\n", 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 (int argc, char** argv) |
| { |
| int epoll_fd; |
| struct timeval tv; |
| int last_result; |
| |
| tst_resm(TINFO, "testing if epoll() system call works\n"); |
| |
| /* Get the current time */ |
| if (gettimeofday(&tv, NULL) != 0){ |
| tst_brkm(TBROK, cleanup, "gettimeofday failed\n"); |
| tst_exit(); |
| } else { |
| tst_resm(TINFO, "gettimeofday() works\n"); |
| } |
| |
| /* Set up RNG */ |
| srand(tv.tv_usec); |
| tst_resm(TINFO, "random number seeded with gettimeofday() [seed = %d] works\n", 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){ |
| return -1; |
| } |
| |
| tst_resm(TINFO, "Testing epoll_ctl"); |
| last_result = PROTECT_FUNC(test_epoll_ctl, -1, epoll_fd); |
| if (last_result != 0){ |
| /* ctl test(s) failed */ |
| } |
| |
| return 0; |
| } |