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