eventfd01.c revision 4fc9f54c5f65d10d7f1258ab424967e14e40da74
1/* 2 * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> 3 * 4 * Based on testcases/kernel/syscalls/waitpid/waitpid01.c 5 * Original copyright message: 6 * 7 * Copyright (c) International Business Machines Corp., 2001 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24/* 25 * NAME 26 * eventfd01.c 27 * 28 * DESCRIPTION 29 * Test cases for eventfd syscall. 30 * 31 * USAGE: <for command-line> 32 * eventfd01 [-c n] [-i n] [-I x] [-P x] [-t] 33 * where, -c n : Run n copies concurrently. 34 * -i n : Execute test n times. 35 * -I x : Execute test for x seconds. 36 * -P x : Pause for x seconds between iterations. 37 * -t : Turn on syscall timing. 38 * 39 * History 40 * 07/2008 Vijay Kumar 41 * Initial Version. 42 * 43 * Restrictions 44 * None 45 */ 46 47#include "config.h" 48 49#include <sys/select.h> 50#include <sys/signal.h> 51#include <sys/types.h> 52#include <sys/wait.h> 53#include <unistd.h> 54#include <fcntl.h> 55#include <errno.h> 56#include <string.h> 57#include <stdint.h> 58#include <poll.h> 59 60#include <test.h> 61#include <usctest.h> 62#include <linux_syscall_numbers.h> 63 64#ifdef HAVE_LIBAIO_H 65#include <libaio.h> 66#endif 67 68static void setup(void); 69static void cleanup(void); 70 71TCID_DEFINE(eventfd01); 72int TST_TOTAL = 15; 73extern int Tst_count; 74 75static int 76myeventfd(unsigned int initval, int flags) 77{ 78 /* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */ 79#if defined (__NR_eventfd) 80 return syscall(__NR_eventfd, initval); 81#else 82 errno = ENOSYS; 83 return -1; 84#endif 85} 86 87/* 88 * clear_counter() - clears the counter by performing a dummy read 89 * @fd: the eventfd 90 * 91 * RETURNS: 92 * 0 on success, and -1 on failure 93 */ 94static int 95clear_counter(int fd) 96{ 97 uint64_t dummy; 98 int ret; 99 100 ret = read(fd, &dummy, sizeof(dummy)); 101 if (ret == -1) { 102 if (errno != EAGAIN) { 103 tst_resm(TINFO, "error clearing counter: %s", 104 strerror(errno)); 105 return -1; 106 } 107 } 108 109 return 0; 110} 111 112/* 113 * set_counter() - sets the count to specified value 114 * @fd: the eventfd 115 * @val: the value to be set 116 * 117 * Clears the counter and sets the counter to @val. 118 * 119 * RETURNS: 120 * 0 on success, -1 on failure 121 */ 122static int 123set_counter(int fd, uint64_t val) 124{ 125 int ret; 126 127 ret = clear_counter(fd); 128 if (ret == -1) { 129 return -1; 130 } 131 132 ret = write(fd, &val, sizeof(val)); 133 if (ret == -1) { 134 tst_resm(TINFO, "error setting counter value: %s", 135 strerror(errno)); 136 return -1; 137 } 138 139 return 0; 140} 141 142/* 143 * Test whether the current value of the counter matches @required. 144 */ 145static void 146read_test(int fd, uint64_t required) 147{ 148 int ret; 149 uint64_t val; 150 151 ret = read(fd, &val, sizeof(val)); 152 if (ret == -1) { 153 tst_resm(TBROK, "error reading eventfd: %s", 154 strerror(errno)); 155 return; 156 } 157 158 if (val == required) 159 tst_resm(TPASS, "counter value matches required"); 160 else 161 tst_resm(TFAIL, "counter value mismatch: " 162 "required: %llu, got: %llu", required, val); 163} 164 165/* 166 * Test whether read returns with error EAGAIN when counter is at 0. 167 */ 168static void 169read_eagain_test(int fd) 170{ 171 int ret; 172 uint64_t val; 173 174 ret = clear_counter(fd); 175 if (ret == -1) { 176 tst_resm(TBROK, "error clearing counter"); 177 return; 178 } 179 180 ret = read(fd, &val, sizeof(val)); 181 if (ret == -1) { 182 if (errno == EAGAIN) 183 tst_resm(TPASS, "read failed with EAGAIN as expected"); 184 else 185 tst_resm(TFAIL, "read failed with unexpected " 186 "error: %s", strerror(errno)); 187 } else { 188 tst_resm(TFAIL, "read returned with %d"); 189 } 190} 191 192/* 193 * Test whether writing to counter works. 194 */ 195static void 196write_test(int fd) 197{ 198 int ret; 199 uint64_t val; 200 201 val = 12; 202 203 ret = set_counter(fd, val); 204 if (ret == -1) { 205 tst_resm(TBROK, "error setting counter value to %lld", val); 206 return; 207 } 208 209 read_test(fd, val); 210} 211 212/* 213 * Test whether write returns with error EAGAIN when counter is at 214 * (UINT64_MAX - 1). 215 */ 216static void 217write_eagain_test(int fd) 218{ 219 int ret; 220 uint64_t val; 221 222 ret = set_counter(fd, UINT64_MAX - 1); 223 if (ret == -1) { 224 tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); 225 return; 226 } 227 228 val = 1; 229 ret = write(fd, &val, sizeof(val)); 230 if (ret == -1) { 231 if (errno == EAGAIN) 232 tst_resm(TPASS, "write failed with EAGAIN as " 233 "expected"); 234 else 235 tst_resm(TFAIL, "write returned with unexpected " 236 "error: %s", strerror(errno)); 237 } else { 238 tst_resm(TFAIL, "write returned with %d", ret); 239 } 240} 241 242/* 243 * Test whether read returns with error EINVAL, if buffer size is less 244 * than 8 bytes. 245 */ 246static void 247read_einval_test(int fd) 248{ 249 uint32_t invalid; 250 int ret; 251 252 ret = read(fd, &invalid, sizeof(invalid)); 253 if (ret == -1) { 254 if (errno == EINVAL) { 255 tst_resm(TPASS, "read failed with EINVAL as expected"); 256 } else { 257 tst_resm(TFAIL, "read returned with unexpected " 258 "error: %s", strerror(errno)); 259 } 260 } else { 261 tst_resm(TFAIL, "read returned with %d", ret); 262 } 263} 264 265/* 266 * Test whether write returns with error EINVAL, if buffer size is 267 * less than 8 bytes. 268 */ 269static void 270write_einval_test(int fd) 271{ 272 uint32_t invalid; 273 int ret; 274 275 ret = write(fd, &invalid, sizeof(invalid)); 276 if (ret == -1) { 277 if (errno == EINVAL) { 278 tst_resm(TPASS, "write failed with EINVAL as " 279 "expected"); 280 } else { 281 tst_resm(TFAIL, "write returned with unexpected " 282 "error: %s", strerror(errno)); 283 } 284 } else { 285 tst_resm(TFAIL, "write returned with %d", ret); 286 } 287} 288 289/* 290 * Test wheter write returns with error EINVAL, when the written value 291 * is 0xFFFFFFFFFFFFFFFF. 292 */ 293static void 294write_einval2_test(int fd) 295{ 296 int ret; 297 uint64_t val; 298 299 ret = clear_counter(fd); 300 if (ret == -1) { 301 tst_resm(TBROK, "error clearing counter"); 302 return; 303 } 304 305 val = 0xffffffffffffffffLL; 306 ret = write(fd, &val, sizeof(val)); 307 if (ret == -1) { 308 if (errno == EINVAL) 309 tst_resm(TPASS, "write failed with EINVAL as " 310 "expected"); 311 else 312 tst_resm(TFAIL, "write returned with unexpected " 313 "error: %s", strerror(errno)); 314 } else { 315 tst_resm(TFAIL, "write returned with %d", ret); 316 } 317} 318 319/* 320 * Test whether readfd is set by select when counter value is 321 * non-zero. 322 */ 323static void 324readfd_set_test(int fd) 325{ 326 int ret; 327 fd_set readfds; 328 struct timeval timeout = { 0, 0 }; 329 uint64_t non_zero = 10; 330 331 FD_ZERO(&readfds); 332 FD_SET(fd, &readfds); 333 334 ret = set_counter(fd, non_zero); 335 if (ret == -1) { 336 tst_resm(TBROK, "error setting counter value to %lld", 337 non_zero); 338 return; 339 } 340 341 ret = select(fd + 1, &readfds, NULL, NULL, &timeout); 342 if (ret == -1) { 343 /* EINTR cannot occur, since we don't block. */ 344 tst_resm(TBROK, "select: error getting fd status: %s", 345 strerror(errno)); 346 return; 347 } 348 349 if (FD_ISSET(fd, &readfds)) 350 tst_resm(TPASS, "fd is set in readfds"); 351 else 352 tst_resm(TFAIL, "fd is not set in readfds"); 353} 354 355/* 356 * Test whether readfd is not set by select when counter value is 357 * zero. 358 */ 359static void 360readfd_not_set_test(int fd) 361{ 362 int ret; 363 fd_set readfds; 364 struct timeval timeout = { 0, 0 }; 365 366 FD_ZERO(&readfds); 367 FD_SET(fd, &readfds); 368 369 ret = clear_counter(fd); 370 if (ret == -1) { 371 tst_resm(TBROK, "error clearing counter"); 372 return; 373 } 374 375 ret = select(fd + 1, &readfds, NULL, NULL, &timeout); 376 if (ret == -1) { 377 /* EINTR cannot occur, since we don't block. */ 378 tst_resm(TBROK, "select: error getting fd status: %s", 379 strerror(errno)); 380 return; 381 } 382 383 if (!FD_ISSET(fd, &readfds)) 384 tst_resm(TPASS, "fd is not set in readfds"); 385 else 386 tst_resm(TFAIL, "fd is set in readfds"); 387} 388 389/* 390 * Test whether writefd is set by select when counter value is not the 391 * maximum counter value. 392 */ 393static void 394writefd_set_test(int fd) 395{ 396 int ret; 397 fd_set writefds; 398 struct timeval timeout = { 0, 0 }; 399 uint64_t non_max = 10; 400 401 FD_ZERO(&writefds); 402 FD_SET(fd, &writefds); 403 404 ret = set_counter(fd, non_max); 405 if (ret == -1) { 406 tst_resm(TBROK, "error setting counter value to %lld", 407 non_max); 408 return; 409 } 410 411 ret = select(fd + 1, NULL, &writefds, NULL, &timeout); 412 if (ret == -1) { 413 /* EINTR cannot occur, since we don't block. */ 414 tst_resm(TBROK, "select: error getting fd status: %s", 415 strerror(errno)); 416 return; 417 } 418 419 if (FD_ISSET(fd, &writefds)) 420 tst_resm(TPASS, "fd is set in writefds"); 421 else 422 tst_resm(TFAIL, "fd is not set in writefds"); 423} 424 425/* 426 * Test whether writefd is not set by select when counter value is at 427 * (UINT64_MAX - 1). 428 */ 429static void 430writefd_not_set_test(int fd) 431{ 432 int ret; 433 fd_set writefds; 434 struct timeval timeout = { 0, 0 }; 435 436 FD_ZERO(&writefds); 437 FD_SET(fd, &writefds); 438 439 ret = set_counter(fd, UINT64_MAX - 1); 440 if (ret == -1) { 441 tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); 442 return; 443 } 444 445 ret = select(fd + 1, NULL, &writefds, NULL, &timeout); 446 if (ret == -1) { 447 /* EINTR cannot occur, since we don't block. */ 448 tst_resm(TBROK, "select: error getting fd status: %s", 449 strerror(errno)); 450 return; 451 } 452 453 if (!FD_ISSET(fd, &writefds)) 454 tst_resm(TPASS, "fd is not set in writefds"); 455 else 456 tst_resm(TFAIL, "fd is set in writefds"); 457} 458 459/* 460 * Test whether counter update in child is reflected in the parent. 461 */ 462static void 463child_inherit_test(int fd) 464{ 465 uint64_t val; 466 pid_t cpid; 467 int ret; 468 int status; 469 uint64_t to_parent = 0xdeadbeef; 470 uint64_t dummy; 471 472 cpid = fork(); 473 if (cpid == -1) 474 tst_resm(TBROK, "error while forking child: %s", 475 strerror(errno)); 476 if (cpid != 0) { 477 /* Parent */ 478 ret = wait(&status); 479 if (ret == -1) { 480 tst_resm(TBROK, "error getting child exit status"); 481 return; 482 } 483 484 if (WEXITSTATUS(status) == 1) { 485 tst_resm(TBROK, "counter value write not " 486 "succesful in child"); 487 return; 488 } 489 490 ret = read(fd, &val, sizeof(val)); 491 if (ret == -1) { 492 tst_resm(TBROK, "error reading eventfd: %s", 493 strerror(errno)); 494 return; 495 } 496 497 if (val == to_parent) 498 tst_resm(TPASS, "counter value write from " 499 "child successful"); 500 else 501 tst_resm(TFAIL, "counter value write in child " 502 "failed"); 503 } else { 504 /* Child */ 505 ret = read(fd, &dummy, sizeof(dummy)); 506 if (ret == -1 && errno != EAGAIN) { 507 tst_resm(TWARN, "error clearing counter: %s", 508 strerror(errno)); 509 exit(1); 510 } 511 512 ret = write(fd, &to_parent, sizeof(to_parent)); 513 if (ret == -1) { 514 tst_resm(TWARN, "error writing eventfd: %s", 515 strerror(errno)); 516 exit(1); 517 } 518 519 exit(0); 520 } 521} 522 523#ifdef HAVE_IO_SET_EVENTFD 524/* 525 * Test whether counter overflow is detected and handled correctly. 526 * 527 * It is not possible to directly overflow the counter using the 528 * write() syscall. Overflows occur when the counter is incremented 529 * from kernel space, in an irq context, when it is not possible to 530 * block the calling thread of execution. 531 * 532 * The AIO subsystem internally uses eventfd mechanism for 533 * notification of completion of read or write requests. In this test 534 * we trigger a counter overflow, by setting the counter value to the 535 * max possible value initially. When the AIO subsystem notifies 536 * through the eventfd counter, the counter overflows. 537 * 538 * NOTE: If the the counter starts from an initial value of 0, it will 539 * take decades for an overflow to occur. But since we set the initial 540 * value to the max possible counter value, we are able to cause it to 541 * overflow with a single increment. 542 * 543 * When the counter overflows, the following are tested 544 * 1. Check whether POLLERR event occurs in poll() for the eventfd. 545 * 2. Check whether readfd_set/writefd_set is set in select() for the 546 eventfd. 547 * 3. The counter value is UINT64_MAX. 548 */ 549static int 550trigger_eventfd_overflow(int evfd, int *fd, io_context_t *ctx) 551{ 552 int ret; 553 struct iocb iocb; 554 struct iocb *iocbap[1]; 555 static char buf[4 * 1024]; 556 557 *ctx = 0; 558 ret = io_setup(16, ctx); 559 if (ret < 0) { 560 tst_resm(TINFO, "io_setup error: %s", strerror(-ret)); 561 return -1; 562 } 563 564 *fd = open("testfile", O_RDWR | O_CREAT, 0644); 565 if (*fd == -1) { 566 tst_resm(TINFO, "error creating tmp file: %s", 567 strerror(errno)); 568 goto err_io_destroy; 569 } 570 571 ret = set_counter(evfd, UINT64_MAX - 1); 572 if (ret == -1) { 573 tst_resm(TINFO, "error setting counter to UINT64_MAX-1"); 574 goto err_close_file; 575 } 576 577 io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0); 578 io_set_eventfd(&iocb, evfd); 579 580 iocbap[0] = &iocb; 581 ret = io_submit(*ctx, 1, iocbap); 582 if (ret < 0) { 583 tst_resm(TINFO, "error submitting iocb: %s", strerror(-ret)); 584 goto err_close_file; 585 } 586 587 return 0; 588 589 err_close_file: 590 close(*fd); 591 592 err_io_destroy: 593 io_destroy(*ctx); 594 595 return -1; 596} 597 598static void 599cleanup_overflow(int fd, io_context_t ctx) 600{ 601 close(fd); 602 io_destroy(ctx); 603} 604 605static void 606overflow_select_test(int evfd) 607{ 608 struct timeval timeout = { 10, 0 }; 609 fd_set readfds; 610 int fd; 611 io_context_t ctx; 612 int ret; 613 614 ret = trigger_eventfd_overflow(evfd, &fd, &ctx); 615 if (ret == -1) { 616 tst_resm(TBROK, "error triggering eventfd overflow"); 617 return; 618 } 619 620 FD_ZERO(&readfds); 621 FD_SET(evfd, &readfds); 622 ret = select(evfd + 1, &readfds, NULL, NULL, &timeout); 623 if (ret == -1) { 624 tst_resm(TBROK, "error getting evfd status with select: %s", 625 strerror(errno)); 626 goto err_cleanup; 627 } 628 629 if (FD_ISSET(evfd, &readfds)) 630 tst_resm(TPASS, "read fd set as expected"); 631 else 632 tst_resm(TFAIL, "read fd not set"); 633 634 err_cleanup: 635 cleanup_overflow(fd, ctx); 636} 637 638static void 639overflow_poll_test(int evfd) 640{ 641 struct pollfd pollfd; 642 int fd; 643 io_context_t ctx; 644 int ret; 645 646 ret = trigger_eventfd_overflow(evfd, &fd, &ctx); 647 if (fd == -1) { 648 tst_resm(TBROK, "error triggering eventfd overflow"); 649 return; 650 } 651 652 pollfd.fd = evfd; 653 pollfd.events = POLLIN; 654 pollfd.revents = 0; 655 ret = poll(&pollfd, 1, 10000); 656 if (ret == -1) { 657 tst_resm(TBROK, "error getting evfd status with poll: %s", 658 strerror(errno)); 659 goto err_cleanup; 660 } 661 if (pollfd.revents & POLLERR) 662 tst_resm(TPASS, "POLLERR occurred as expected"); 663 else 664 tst_resm(TFAIL, "POLLERR did not occur"); 665 666 err_cleanup: 667 cleanup_overflow(fd, ctx); 668} 669 670static void 671overflow_read_test(int evfd) 672{ 673 uint64_t count; 674 io_context_t ctx; 675 int fd; 676 int ret; 677 678 ret = trigger_eventfd_overflow(evfd, &fd, &ctx); 679 if (ret == -1) { 680 tst_resm(TBROK, "error triggering eventfd overflow"); 681 return; 682 } 683 684 ret = read(evfd, &count, sizeof(count)); 685 if (ret == -1) { 686 tst_resm(TBROK, "error reading eventfd: %s", strerror(errno)); 687 goto err_cleanup; 688 } 689 690 if (count == UINT64_MAX) 691 tst_resm(TPASS, "overflow occurred as expected"); 692 else 693 tst_resm(TFAIL, "overflow did not occur"); 694 695 err_cleanup: 696 cleanup_overflow(fd, ctx); 697} 698#else 699static void 700overflow_select_test(int evfd) 701{ 702 tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); 703} 704 705static void 706overflow_poll_test(int evfd) 707{ 708 tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); 709} 710 711static void 712overflow_read_test(int evfd) 713{ 714 tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); 715} 716#endif 717 718int 719main(int argc, char **argv) 720{ 721 int lc; /* loop counter */ 722 char *msg; /* message returned from parse_opts */ 723 int fd; 724 725 /* parse standard options */ 726 msg = parse_opts(argc, argv, (option_t *) NULL, NULL); 727 if (msg != NULL) { 728 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 729 tst_exit(); 730 /* NOTREACHED */ 731 } 732 733 setup(); 734 735 /* check for looping state if -i option is given */ 736 for (lc = 0; TEST_LOOPING(lc); lc++) { 737 int ret; 738 uint64_t einit = 10; 739 740 /* reset Tst_count in case we are looping */ 741 Tst_count = 0; 742 743 fd = myeventfd(einit, 0); 744 if (fd == -1) 745 tst_brkm(TBROK, cleanup, "error creating eventfd: %s", 746 strerror(errno)); 747 748 ret = fcntl(fd, F_SETFL, O_NONBLOCK); 749 if (ret == -1) 750 tst_brkm(TBROK, cleanup, 751 "error setting non-block mode: %s", strerror); 752 753 read_test(fd, einit); 754 read_eagain_test(fd); 755 write_test(fd); 756 write_eagain_test(fd); 757 read_einval_test(fd); 758 write_einval_test(fd); 759 write_einval2_test(fd); 760 readfd_set_test(fd); 761 readfd_not_set_test(fd); 762 writefd_set_test(fd); 763 writefd_not_set_test(fd); 764 child_inherit_test(fd); 765 overflow_select_test(fd); 766 overflow_poll_test(fd); 767 overflow_read_test(fd); 768 769 close(fd); 770 } 771 772 cleanup(); 773 /* NOT REACHED */ 774 775 return 0; 776} 777 778/* 779 * setup() - performs all ONE TIME setup for this test 780 */ 781static void 782setup(void) 783{ 784 /* capture signals */ 785 tst_sig(FORK, DEF_HANDLER, cleanup); 786 787 if (tst_kvercmp(2, 6, 22) < 0) 788 tst_brkm(TCONF, cleanup, "2.6.22 or greater kernel required"); 789 790 /* Pause if that option was specified 791 * TEST_PAUSE contains the code to fork the test with the -c option. 792 */ 793 TEST_PAUSE; 794} 795 796/* 797 * cleanup() - performs all ONE TIME cleanup for this test 798 */ 799static void 800cleanup(void) 801{ 802 /* 803 * print timing stats if that option was specified. 804 * print errno log if that option was specified. 805 */ 806 TEST_CLEANUP; 807 808 /* exit with return code appropriate for results */ 809 tst_exit(); 810 /*NOTREACHED*/ 811} 812