From: Vijay K. <vij...@br...> - 2008-08-06 04:36:30
|
Subrata Modak <su...@li...> wrote: > My observations/comments: > 1) Get the latest source for the next patch. Some gave hunk failures, > 2) Build, Install and Run is handled properly across all architectures > and kernel versions. Go ahead and send the updated patch. I will merge > them in increments. You can then go ahead and add more in the same > category. Hi Subrata, thanks for the inputs. Here is the updated patch. Changelog: * Added basic testcases for eventfd. Signed-off-by: Vijay Kumar <vij...@br...> runtest/syscalls | 2 + testcases/kernel/include/i386.in | 1 + testcases/kernel/include/ia64.in | 1 + testcases/kernel/include/powerpc.in | 1 + testcases/kernel/include/powerpc64.in | 1 + testcases/kernel/include/s390.in | 1 + testcases/kernel/include/s390x.in | 1 + testcases/kernel/include/sparc.in | 1 + testcases/kernel/include/sparc64.in | 1 + testcases/kernel/include/stub-list | 1 + testcases/kernel/include/x86_64.in | 1 + testcases/kernel/syscalls/eventfd/Makefile | 32 ++ testcases/kernel/syscalls/eventfd/eventfd01.c | 582 +++++++++++++++++++++++++ 13 files changed, 626 insertions(+), 0 deletions(-) diff --git a/runtest/syscalls b/runtest/syscalls index 40a6d36..234027c 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -101,6 +101,8 @@ dup203 dup203 dup204 dup204 dup205 dup205 +eventfd01 eventfd01 + execl01 execl01 execle01 execle01 execlp01 execlp01 diff --git a/testcases/kernel/include/i386.in b/testcases/kernel/include/i386.in index bd61303..df74b6b 100644 --- a/testcases/kernel/include/i386.in +++ b/testcases/kernel/include/i386.in @@ -22,6 +22,7 @@ __NR_tee 315 __NR_vmsplice 316 __NR_utimensat 320 __NR_timerfd_create 322 +__NR_eventfd 323 __NR_fallocate 324 __NR_timerfd_settime 325 __NR_timerfd_gettime 326 diff --git a/testcases/kernel/include/ia64.in b/testcases/kernel/include/ia64.in index ea925b2..54c9910 100644 --- a/testcases/kernel/include/ia64.in +++ b/testcases/kernel/include/ia64.in @@ -17,6 +17,7 @@ __NR_tee 1301 __NR_vmsplice 1302 __NR_fallocate 1303 __NR_utimensat 1306 +__NR_eventfd 1309 __NR_timerfd_create 1310 __NR_timerfd_settime 1311 __NR_timerfd_gettime 1312 diff --git a/testcases/kernel/include/powerpc.in b/testcases/kernel/include/powerpc.in index 99055d3..4dbd734 100644 --- a/testcases/kernel/include/powerpc.in +++ b/testcases/kernel/include/powerpc.in @@ -20,4 +20,5 @@ __NR_symlinkat (__NR_openat + 9) __NR_readlinkat (__NR_openat + 10) __NR_fchmodat (__NR_openat + 11) __NR_faccessat (__NR_openat + 12) +__NR_eventfd 307 __NR_fallocate 309 diff --git a/testcases/kernel/include/powerpc64.in b/testcases/kernel/include/powerpc64.in index 99055d3..4dbd734 100644 --- a/testcases/kernel/include/powerpc64.in +++ b/testcases/kernel/include/powerpc64.in @@ -20,4 +20,5 @@ __NR_symlinkat (__NR_openat + 9) __NR_readlinkat (__NR_openat + 10) __NR_fchmodat (__NR_openat + 11) __NR_faccessat (__NR_openat + 12) +__NR_eventfd 307 __NR_fallocate 309 diff --git a/testcases/kernel/include/s390.in b/testcases/kernel/include/s390.in index 5eb40e2..ef35cf0 100644 --- a/testcases/kernel/include/s390.in +++ b/testcases/kernel/include/s390.in @@ -15,4 +15,5 @@ __NR_faccessat (__NR_openat + 12) __NR_splice 306 __NR_tee 308 __NR_vmsplice 309 +__NR_eventfd 318 __NR_fallocate 314 diff --git a/testcases/kernel/include/s390x.in b/testcases/kernel/include/s390x.in index 8040dd5..0a47f6a 100644 --- a/testcases/kernel/include/s390x.in +++ b/testcases/kernel/include/s390x.in @@ -12,4 +12,5 @@ __NR_symlinkat (__NR_openat + 9) __NR_readlinkat (__NR_openat + 10) __NR_fchmodat (__NR_openat + 11) __NR_faccessat (__NR_openat + 12) +__NR_eventfd 318 __NR_fallocate 314 diff --git a/testcases/kernel/include/sparc.in b/testcases/kernel/include/sparc.in index ad4e3ff..fc81530 100644 --- a/testcases/kernel/include/sparc.in +++ b/testcases/kernel/include/sparc.in @@ -15,4 +15,5 @@ __NR_symlinkat (__NR_openat + 9) __NR_readlinkat (__NR_openat + 10) __NR_fchmodat (__NR_openat + 11) __NR_faccessat (__NR_openat + 12) +__NR_eventfd 313 __NR_fallocate 314 diff --git a/testcases/kernel/include/sparc64.in b/testcases/kernel/include/sparc64.in index ad4e3ff..1ea80fa 100644 --- a/testcases/kernel/include/sparc64.in +++ b/testcases/kernel/include/sparc64.in @@ -15,4 +15,5 @@ __NR_symlinkat (__NR_openat + 9) __NR_readlinkat (__NR_openat + 10) __NR_fchmodat (__NR_openat + 11) __NR_faccessat (__NR_openat + 12) +__NR_eventd 313 __NR_fallocate 314 diff --git a/testcases/kernel/include/stub-list b/testcases/kernel/include/stub-list index 4dde44d..a6738a4 100644 --- a/testcases/kernel/include/stub-list +++ b/testcases/kernel/include/stub-list @@ -21,3 +21,4 @@ __NR_timer_delete __NR_timer_settime __NR_unlinkat __NR_vmsplice +__NR_eventfd \ No newline at end of file diff --git a/testcases/kernel/include/x86_64.in b/testcases/kernel/include/x86_64.in index 8a326ac..9606c98 100644 --- a/testcases/kernel/include/x86_64.in +++ b/testcases/kernel/include/x86_64.in @@ -22,6 +22,7 @@ __NR_tee 276 __NR_vmsplice 278 __NR_utimensat 296 __NR_timerfd_create 283 +__NR_eventfd 284 __NR_fallocate 285 __NR_timerfd_settime 286 __NR_timerfd_gettime 287 diff --git a/testcases/kernel/syscalls/eventfd/Makefile b/testcases/kernel/syscalls/eventfd/Makefile new file mode 100644 index 0000000..e2ebae8 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/Makefile @@ -0,0 +1,32 @@ +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +CFLAGS += -I../../../../include -Wall +LDLIBS += -L../../../../lib -lltp + +SRCS = $(wildcard *.c) +TARGETS = $(patsubst %.c, %, $(wildcard *.c)) + +all: $(TARGETS) + +install: + @set -e; for i in $(TARGETS); do ln -f $$i ../../../bin/$$i ; done + +clean: + rm -f $(TARGETS) + diff --git a/testcases/kernel/syscalls/eventfd/eventfd01.c b/testcases/kernel/syscalls/eventfd/eventfd01.c new file mode 100644 index 0000000..f099248 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd01.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2008 Vijay Kumar B. <vij...@br...> + * + * Based on testcases/kernel/syscalls/waitpid/waitpid01.c + * Original copyright message: + * + * 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 + */ + +/* + * NAME + * eventfd01.c + * + * DESCRIPTION + * Test cases for eventfd syscall. + * + * USAGE: <for command-line> + * eventfd01 [-c n] [-i n] [-I x] [-P x] [-t] + * where, -c n : Run n copies concurrently. + * -i n : Execute test n times. + * -I x : Execute test for x seconds. + * -P x : Pause for x seconds between iterations. + * -t : Turn on syscall timing. + * + * History + * 07/2008 Vijay Kumar + * Initial Version. + * + * Restrictions + * None + */ + +#include <sys/select.h> +#include <sys/signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <stdint.h> + +#include <test.h> +#include <usctest.h> +#include <linux_syscall_numbers.h> + +static void setup(void); +static void cleanup(void); + +char *TCID = "eventfd01"; +int TST_TOTAL = 12; +extern int Tst_count; + +static int +myeventfd(unsigned int initval, int flags) +{ + return syscall(__NR_eventfd, initval); +} + +/* + * clear_counter() - clears the counter by performing a dummy read + * @fd: the eventfd + * + * RETURNS: + * 0 on success, and -1 on failure + */ +static int +clear_counter(int fd) +{ + uint64_t dummy; + int ret; + + ret = read(fd, &dummy, sizeof(dummy)); + if (ret == -1) { + if (errno != EAGAIN) { + tst_resm(TBROK, "error clearing counter: %s", + strerror(errno)); + return -1; + } + } + + return 0; +} + +/* + * set_counter() - sets the count to specified value + * @fd: the eventfd + * @val: the value to be set + * + * Clears the counter and sets the counter to @val. + * + * RETURNS: + * 0 on success, -1 on failure + */ +static int +set_counter(int fd, uint64_t val) +{ + int ret; + + ret = clear_counter(fd); + if (ret == -1) { + return -1; + } + + ret = write(fd, &val, sizeof(val)); + if (ret == -1) { + tst_resm(TBROK, "error setting counter value: %s", + strerror(errno)); + return -1; + } + + return 0; +} + +/* + * Test whether the current value of the counter matches @required. + */ +static void +read_test(int fd, uint64_t required) +{ + int ret; + uint64_t val; + + ret = read(fd, &val, sizeof(val)); + if (ret == -1) { + tst_resm(TBROK, "error reading eventfd: %s", + strerror(errno)); + return; + } + + if (val == required) + tst_resm(TPASS, "counter value matches required"); + else + tst_resm(TFAIL, "counter value mismatch: " + "required: %llu, got: %llu", required, val); +} + +/* + * Test whether read returns with error EAGAIN when counter is at 0. + */ +static void +read_eagain_test(int fd) +{ + int ret; + uint64_t val; + + ret = clear_counter(fd); + if (ret == -1) + return; + + ret = read(fd, &val, sizeof(val)); + if (ret == -1) { + if (errno == EAGAIN) + tst_resm(TPASS, "read failed with EAGAIN as expected"); + else + tst_resm(TFAIL, "read failed with unexpected " + "error: %s", strerror(errno)); + } else { + tst_resm(TFAIL, "read returned with %d"); + } +} + +/* + * Test whether writing to counter works. + */ +static void +write_test(int fd) +{ + int ret; + uint64_t val; + + val = 12; + + ret = set_counter(fd, val); + if (ret == -1) + return; + + read_test(fd, val); +} + +/* + * Test whether write returns with error EAGAIN when counter is at + * (UINT64_MAX - 1). + */ +static void +write_eagain_test(int fd) +{ + int ret; + uint64_t val; + + ret = set_counter(fd, UINT64_MAX - 1); + if (ret == -1) + return; + + val = 1; + ret = write(fd, &val, sizeof(val)); + if (ret == -1) { + if (errno == EAGAIN) + tst_resm(TPASS, "write failed with EAGAIN as " + "expected"); + else + tst_resm(TFAIL, "write returned with unexpected " + "error: %s", strerror(errno)); + } else { + tst_resm(TFAIL, "write returned with %d", ret); + } +} + +/* + * Test whether read returns with error EINVAL, if buffer size is less + * than 8 bytes. + */ +static void +read_einval_test(int fd) +{ + uint32_t invalid; + int ret; + + ret = read(fd, &invalid, sizeof(invalid)); + if (ret == -1) { + if (errno == EINVAL) { + tst_resm(TPASS, "read failed with EINVAL as expected"); + } else { + tst_resm(TFAIL, "read returned with unexpected " + "error: %s", strerror(errno)); + } + } else { + tst_resm(TFAIL, "read returned with %d", ret); + } +} + +/* + * Test whether write returns with error EINVAL, if buffer size is + * less than 8 bytes. + */ +static void +write_einval_test(int fd) +{ + uint32_t invalid; + int ret; + + ret = write(fd, &invalid, sizeof(invalid)); + if (ret == -1) { + if (errno == EINVAL) { + tst_resm(TPASS, "write failed with EINVAL as " + "expected"); + } else { + tst_resm(TFAIL, "write returned with unexpected " + "error: %s", strerror(errno)); + } + } else { + tst_resm(TFAIL, "write returned with %d", ret); + } +} + +/* + * Test wheter write returns with error EINVAL, when the written value + * is 0xFFFFFFFFFFFFFFFF. + */ +static void +write_einval2_test(int fd) +{ + int ret; + uint64_t val; + + ret = clear_counter(fd); + if (ret == -1) + return; + + val = 0xffffffffffffffffLL; + ret = write(fd, &val, sizeof(val)); + if (ret == -1) { + if (errno == EINVAL) + tst_resm(TPASS, "write failed with EINVAL as " + "expected"); + else + tst_resm(TFAIL, "write returned with unexpected " + "error: %s", strerror(errno)); + } else { + tst_resm(TFAIL, "write returned with %d", ret); + } +} + +/* + * Test whether readfd is set by select when counter value is + * non-zero. + */ +static void +readfd_set_test(int fd) +{ + int ret; + fd_set readfds; + struct timeval timeout = { 0, 0 }; + uint64_t non_zero = 10; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + ret = set_counter(fd, non_zero); + if (ret == -1) + return; + + ret = select(fd + 1, &readfds, NULL, NULL, &timeout); + if (ret == -1) { + /* EINTR cannot occur, since we don't block. */ + tst_resm(TBROK, "select: error getting fd status: %s", + strerror(errno)); + return; + } + + if (FD_ISSET(fd, &readfds)) + tst_resm(TPASS, "fd is set in readfds"); + else + tst_resm(TFAIL, "fd is not set in readfds"); +} + +/* + * Test whether readfd is not set by select when counter value is + * zero. + */ +static void +readfd_not_set_test(int fd) +{ + int ret; + fd_set readfds; + struct timeval timeout = { 0, 0 }; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + ret = clear_counter(fd); + if (ret == -1) + return; + + ret = select(fd + 1, &readfds, NULL, NULL, &timeout); + if (ret == -1) { + /* EINTR cannot occur, since we don't block. */ + tst_resm(TBROK, "select: error getting fd status: %s", + strerror(errno)); + return; + } + + if (!FD_ISSET(fd, &readfds)) + tst_resm(TPASS, "fd is not set in readfds"); + else + tst_resm(TFAIL, "fd is set in readfds"); +} + +/* + * Test whether writefd is set by select when counter value is not the + * maximum counter value. + */ +static void +writefd_set_test(int fd) +{ + int ret; + fd_set writefds; + struct timeval timeout = { 0, 0 }; + uint64_t non_max = 10; + + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + ret = set_counter(fd, non_max); + if (ret == -1) + return; + + ret = select(fd + 1, NULL, &writefds, NULL, &timeout); + if (ret == -1) { + /* EINTR cannot occur, since we don't block. */ + tst_resm(TBROK, "select: error getting fd status: %s", + strerror(errno)); + return; + } + + if (FD_ISSET(fd, &writefds)) + tst_resm(TPASS, "fd is set in writefds"); + else + tst_resm(TFAIL, "fd is not set in writefds"); +} + +/* + * Test whether writefd is not set by select when counter value is at + * (UINT64_MAX - 1). + */ +static void +writefd_not_set_test(int fd) +{ + int ret; + fd_set writefds; + struct timeval timeout = { 0, 0 }; + + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + ret = set_counter(fd, UINT64_MAX - 1); + if (ret == -1) + return; + + ret = select(fd + 1, NULL, &writefds, NULL, &timeout); + if (ret == -1) { + /* EINTR cannot occur, since we don't block. */ + tst_resm(TBROK, "select: error getting fd status: %s", + strerror(errno)); + return; + } + + if (!FD_ISSET(fd, &writefds)) + tst_resm(TPASS, "fd is not set in writefds"); + else + tst_resm(TFAIL, "fd is set in writefds"); +} + +/* + * Test whether counter update in child is reflected in the parent. + */ +static void +child_inherit_test(int fd) +{ + uint64_t val; + pid_t cpid; + int ret; + int status; + uint64_t to_parent = 0xdeadbeef; + uint64_t dummy; + + cpid = fork(); + if (cpid == -1) + tst_resm(TBROK, "error while forking child: %s", + strerror(errno)); + if (cpid != 0) { + /* Parent */ + ret = wait(&status); + if (ret == -1) { + tst_resm(TBROK, "error getting child exit status"); + return; + } + + if (WEXITSTATUS(status) == 1) { + tst_resm(TBROK, "counter value write not " + "succesful in child"); + return; + } + + ret = read(fd, &val, sizeof(val)); + if (ret == -1) { + tst_resm(TBROK, "error reading eventfd: %s", + strerror(errno)); + return; + } + + if (val == to_parent) + tst_resm(TPASS, "counter value write from " + "child successful"); + else + tst_resm(TFAIL, "counter value write in child " + "failed"); + } else { + /* Child */ + ret = read(fd, &dummy, sizeof(dummy)); + if (ret == -1 && errno != EAGAIN) { + tst_resm(TWARN, "error clearing counter: %s", + strerror(errno)); + exit(1); + } + + ret = write(fd, &to_parent, sizeof(to_parent)); + if (ret == -1) { + tst_resm(TWARN, "error writing eventfd: %s", + strerror(errno)); + exit(1); + } + + exit(0); + } +} + +int +main(int argc, char **argv) +{ + int lc; /* loop counter */ + char *msg; /* message returned from parse_opts */ + int fd; + + /* parse standard options */ + msg = parse_opts(argc, argv, (option_t *) NULL, NULL); + if (msg != NULL) { + tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); + tst_exit(); + /* NOTREACHED */ + } + + setup(); + + /* check for looping state if -i option is given */ + for (lc = 0; TEST_LOOPING(lc); lc++) { + int ret; + uint64_t einit = 10; + + /* reset Tst_count in case we are looping */ + Tst_count = 0; + + fd = myeventfd(einit, 0); + if (fd == -1) + tst_brkm(TBROK, cleanup, "error creating eventfd: %s", + strerror(errno)); + + ret = fcntl(fd, F_SETFL, O_NONBLOCK); + if (ret == -1) + tst_brkm(TBROK, cleanup, + "error setting non-block mode: %s", strerror); + + read_test(fd, einit); + read_eagain_test(fd); + write_test(fd); + write_eagain_test(fd); + read_einval_test(fd); + write_einval_test(fd); + write_einval2_test(fd); + readfd_set_test(fd); + readfd_not_set_test(fd); + writefd_set_test(fd); + writefd_not_set_test(fd); + child_inherit_test(fd); + + close(fd); + } + + cleanup(); + /* NOT REACHED */ + + return 0; +} + +/* + * setup() - performs all ONE TIME setup for this test + */ +static void +setup(void) +{ + /* capture signals */ + tst_sig(FORK, DEF_HANDLER, cleanup); + + if (tst_kvercmp(2, 6, 22) < 0) + tst_brkm(TCONF, cleanup, "2.6.22 or greater kernel required"); + + /* Pause if that option was specified + * TEST_PAUSE contains the code to fork the test with the -c option. + */ + TEST_PAUSE; +} + +/* + * cleanup() - performs all ONE TIME cleanup for this test + */ +static void +cleanup(void) +{ + /* + * print timing stats if that option was specified. + * print errno log if that option was specified. + */ + TEST_CLEANUP; + + /* exit with return code appropriate for results */ + tst_exit(); + /*NOTREACHED*/ +} |