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