1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <algorithm> 7 8 #include <assert.h> 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <math.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <unistd.h> 16 #include <sys/ioctl.h> 17 #include <sys/select.h> 18 19 #include <OS.h> 20 21 #include <util/DoublyLinkedList.h> 22 23 // Test cases: 24 // 25 // 1. unblock on close: 26 // 27 // * unblock, when the same cookie is closed 28 // - read 29 // - write (with, without ECHO) 30 // * unblock write operations, when the other tty is closed 31 // * unblock slave operations, when the master is closed 32 // 33 // 34 // 2. select: 35 // 36 // * notify read, write, if ready when select()ing 37 // * notify read, write, error on close of the other TTY 38 // (the select() behavior when closing the same TTY is undefined) 39 // * notify read after pending write 40 // - with ECHO 41 // - without ECHO 42 // * notify write after pending read and full buffer 43 // - with ECHO 44 // - without ECHO 45 // * don't notify when there was a pending read/write 46 // 47 // 48 // TODO: There are no ECHO tests yet, since I don't know how to turn it on. 49 50 #define CHK(condition) assert(condition) 51 #define RUN_TEST(test) (test)->Run() 52 #define CHK_ALIVE(thread) CHK((thread)->IsAlive()) 53 #define CHK_DEAD(thread) CHK(!(thread)->IsAlive()) 54 55 // FDSet 56 struct FDSet : fd_set { 57 FDSet() 58 { 59 Clear(); 60 } 61 62 void Clear() 63 { 64 FD_ZERO(this); 65 fCount = 0; 66 } 67 68 void Add(int fd) 69 { 70 if (fd < 0 || fd >= FD_SETSIZE) { 71 fprintf(stderr, "FDSet::Add(%d): Invalid FD.\n", fd); 72 return; 73 } 74 75 FD_SET(fd, this); 76 if (fd >= fCount) 77 fCount = fd + 1; 78 } 79 80 int Count() const 81 { 82 return fCount; 83 } 84 85 void UpdateCount() 86 { 87 if (fCount > 0) { 88 for (int i = fCount - 1; i >= 0; i--) { 89 if (FD_ISSET(i, this)) { 90 fCount = i + 1; 91 return; 92 } 93 } 94 fCount = 0; 95 } 96 } 97 98 bool operator==(const FDSet &other) const 99 { 100 if (fCount != other.fCount) 101 return false; 102 103 for (int i = 0; i < fCount; i++) { 104 if (FD_ISSET(i, this) != FD_ISSET(i, &other)) 105 return false; 106 } 107 108 return true; 109 } 110 111 bool operator!=(const FDSet &other) const 112 { 113 return !(*this == other); 114 } 115 116 private: 117 int fCount; 118 }; 119 120 // SelectSet 121 class SelectSet { 122 public: 123 SelectSet() {} 124 ~SelectSet() {} 125 126 void Clear() 127 { 128 fReadSet.Clear(); 129 fWriteSet.Clear(); 130 fErrorSet.Clear(); 131 } 132 133 void AddReadFD(int fd) 134 { 135 fReadSet.Add(fd); 136 } 137 138 void AddWriteFD(int fd) 139 { 140 fWriteSet.Add(fd); 141 } 142 143 void AddErrorFD(int fd) 144 { 145 fErrorSet.Add(fd); 146 } 147 148 int Select(bigtime_t timeout = -1) 149 { 150 int count = max_c(max_c(fReadSet.Count(), fWriteSet.Count()), 151 fErrorSet.Count()); 152 fd_set *readSet = (fReadSet.Count() > 0 ? &fReadSet : NULL); 153 fd_set *writeSet = (fWriteSet.Count() > 0 ? &fWriteSet : NULL); 154 fd_set *errorSet = (fErrorSet.Count() > 0 ? &fErrorSet : NULL); 155 156 timeval tv = { timeout / 1000000, timeout % 1000000 }; 157 158 int result = select(count, readSet, writeSet, errorSet, 159 (timeout >= 0 ? &tv : NULL)); 160 if (result <= 0) { 161 Clear(); 162 } else { 163 fReadSet.UpdateCount(); 164 fWriteSet.UpdateCount(); 165 fErrorSet.UpdateCount(); 166 } 167 168 return result; 169 } 170 171 bool operator==(const SelectSet &other) const 172 { 173 return (fReadSet == other.fReadSet 174 && fWriteSet == other.fWriteSet 175 && fErrorSet == other.fErrorSet); 176 } 177 178 bool operator!=(const SelectSet &other) const 179 { 180 return !(*this == other); 181 } 182 183 private: 184 FDSet fReadSet; 185 FDSet fWriteSet; 186 FDSet fErrorSet; 187 }; 188 189 // Runnable 190 class Runnable { 191 public: 192 virtual ~Runnable() {} 193 virtual int32 Run() = 0; 194 }; 195 196 // Caller 197 template<typename Type> 198 class Caller : public Runnable { 199 public: 200 Caller(Type *object, int32 (Type::*function)()) 201 : fObject(object), 202 fFunction(function) 203 { 204 } 205 206 virtual int32 Run() 207 { 208 return (fObject->*fFunction)(); 209 } 210 211 private: 212 Type *fObject; 213 int32 (Type::*fFunction)(); 214 }; 215 216 // create_caller 217 template<typename Type> 218 static inline Runnable * 219 create_caller(Type *object, int32 (Type::*function)()) 220 { 221 return new Caller<Type>(object, function); 222 } 223 224 #define CALLER(object, function) create_caller(object, function) 225 226 // Thread 227 struct Thread : public DoublyLinkedListLinkImpl<Thread> { 228 public: 229 Thread(Runnable *runnable, const char *name) 230 : fRunnable(runnable) 231 { 232 fThread = spawn_thread(_Entry, name, B_NORMAL_PRIORITY, this); 233 if (fThread < 0) { 234 sprintf("Failed to spawn thread: %s\n", strerror(fThread)); 235 exit(1); 236 } 237 } 238 239 ~Thread() 240 { 241 Kill(); 242 delete fRunnable; 243 } 244 245 void Resume() 246 { 247 resume_thread(fThread); 248 } 249 250 void WaitFor() 251 { 252 status_t result; 253 wait_for_thread(fThread, &result); 254 } 255 256 void Kill() 257 { 258 kill_thread(fThread); 259 } 260 261 bool IsAlive() 262 { 263 thread_info info; 264 return (get_thread_info(fThread, &info) == B_OK); 265 } 266 267 private: 268 static int32 _Entry(void *data) 269 { 270 return ((Thread*)data)->fRunnable->Run(); 271 } 272 273 thread_id fThread; 274 Runnable *fRunnable; 275 }; 276 277 // TestCase 278 class TestCase { 279 public: 280 TestCase() {} 281 virtual ~TestCase() 282 { 283 while (Thread *thread = fThreads.Head()) { 284 fThreads.Remove(thread); 285 delete thread; 286 } 287 } 288 289 void Run() 290 { 291 Test(); 292 delete this; 293 } 294 295 protected: 296 virtual void Test() = 0; 297 298 Thread *CreateThread(Runnable *runnable, const char *name) 299 { 300 Thread *thread = new Thread(runnable, name); 301 fThreads.Add(thread); 302 return thread; 303 } 304 305 static void WriteUntilBlock(int fd) 306 { 307 // set non-blocking I/O 308 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 309 fprintf(stderr, "WriteUntilBlock(): Failed to set non-blocking I/O " 310 "mode: %s\n", strerror(errno)); 311 exit(1); 312 } 313 314 // write till blocking 315 char buffer[1024]; 316 memset(buffer, 'A', sizeof(buffer)); 317 ssize_t bytesWritten; 318 do { 319 bytesWritten = write(fd, buffer, sizeof(buffer)); 320 } while (bytesWritten > 0 || errno == B_INTERRUPTED); 321 322 if (bytesWritten < 0 && errno != B_WOULD_BLOCK) { 323 fprintf(stderr, "WriteUntilBlock(): Writing failed: %s\n", 324 strerror(errno)); 325 exit(1); 326 } 327 328 // reset to blocking I/O 329 if (fcntl(fd, F_SETFL, 0) < 0) { 330 fprintf(stderr, "WriteUntilBlock(): Failed to set blocking I/O " 331 "mode: %s\n", strerror(errno)); 332 exit(1); 333 } 334 } 335 336 static void ReadDontFail(int fd, int32 size) 337 { 338 char buffer[1024]; 339 340 while (size > 0) { 341 ssize_t bytesRead; 342 do { 343 int32 toRead = sizeof(buffer); 344 if (toRead > size) 345 toRead = size; 346 347 bytesRead = read(fd, buffer, toRead); 348 } while (bytesRead < 0 && errno == B_INTERRUPTED); 349 350 if (bytesRead < 0) { 351 fprintf(stderr, "ReadDontFail(): Failed to read: %s\n", 352 strerror(errno)); 353 exit(1); 354 } 355 356 size -= bytesRead; 357 } 358 } 359 360 static void WriteDontFail(int fd, int32 size) 361 { 362 char buffer[1024]; 363 memset(buffer, 'A', sizeof(buffer)); 364 365 while (size > 0) { 366 ssize_t bytesWritten; 367 do { 368 int32 toWrite = sizeof(buffer); 369 if (toWrite > size) 370 toWrite = size; 371 372 bytesWritten = write(fd, buffer, toWrite); 373 } while (bytesWritten < 0 && errno == B_INTERRUPTED); 374 375 if (bytesWritten < 0) { 376 fprintf(stderr, "WriteDontFail(): Failed to write: %s\n", 377 strerror(errno)); 378 exit(1); 379 } 380 381 size -= bytesWritten; 382 } 383 } 384 385 void SetEcho(int fd) 386 { 387 // TODO: How to set echo mode? 388 } 389 390 private: 391 typedef DoublyLinkedList<Thread> ThreadList; 392 393 ThreadList fThreads; 394 }; 395 396 397 // open_tty 398 static int 399 open_tty(int index, bool master) 400 { 401 if (index < 0 || index >= 16) 402 fprintf(stderr, "open_tty(%d, %d): Bad index!\n", index, master); 403 404 char path[32]; 405 sprintf(path, "/dev/%ct/r%x", (master ? 'p' : 't'), index); 406 // we do not want the slave to be our controlling tty 407 int fd = open(path, O_RDWR | (master ? 0 : O_NOCTTY)); 408 409 if (fd < 0) { 410 fprintf(stderr, "Failed to open tty `%s': %s\n", path, 411 strerror(errno)); 412 exit(1); 413 } 414 415 return fd; 416 } 417 418 419 static void 420 close_tty(int &fd) 421 { 422 if (fd >= 0) { 423 close(fd); 424 fd = -1; 425 } 426 } 427 428 429 // #pragma mark - 430 431 // TestUnblockOnCloseRead 432 class TestUnblockOnCloseRead : public TestCase { 433 public: 434 TestUnblockOnCloseRead(bool master, bool crossOver) 435 : 436 fMaster(-1), 437 fSlave(-1), 438 fTestMaster(master), 439 fCrossOver(crossOver) 440 { 441 printf("TestUnblockOnCloseRead(%d, %d)\n", master, crossOver); 442 } 443 444 445 protected: 446 virtual ~TestUnblockOnCloseRead() 447 { 448 close_tty(fMaster); 449 close_tty(fSlave); 450 } 451 452 virtual void Test() 453 { 454 fMaster = open_tty(0, true); 455 fSlave = open_tty(0, false); 456 457 Thread *thread = CreateThread( 458 CALLER(this, &TestUnblockOnCloseRead::_Reader), "reader"); 459 thread->Resume(); 460 461 snooze(100000); 462 CHK_ALIVE(thread); 463 464 if (fCrossOver) 465 close_tty(fTestMaster ? fSlave : fMaster); 466 else 467 close_tty(fTestMaster ? fMaster : fSlave); 468 469 snooze(100000); 470 CHK_DEAD(thread); 471 } 472 473 private: 474 int32 _Reader() 475 { 476 char buffer[32]; 477 ssize_t bytesRead = read((fTestMaster ? fMaster : fSlave), buffer, 478 sizeof(buffer)); 479 480 CHK((bytesRead < 0)); 481 482 return 0; 483 } 484 485 private: 486 int fMaster; 487 int fSlave; 488 bool fTestMaster; 489 bool fCrossOver; 490 }; 491 492 // TestUnblockOnCloseWrite 493 class TestUnblockOnCloseWrite : public TestCase { 494 public: 495 TestUnblockOnCloseWrite(bool master, bool crossOver, bool echo) 496 : 497 fMaster(-1), 498 fSlave(-1), 499 fTestMaster(master), 500 fCrossOver(crossOver), 501 fEcho(echo) 502 { 503 printf("TestUnblockOnCloseWrite(%d, %d, %d)\n", master, crossOver, 504 echo); 505 } 506 507 508 protected: 509 virtual ~TestUnblockOnCloseWrite() 510 { 511 close_tty(fMaster); 512 close_tty(fSlave); 513 } 514 515 virtual void Test() 516 { 517 fMaster = open_tty(0, true); 518 fSlave = open_tty(0, false); 519 520 if (fEcho) 521 SetEcho((fTestMaster ? fSlave : fMaster)); 522 523 WriteUntilBlock((fTestMaster ? fMaster : fSlave)); 524 525 Thread *thread = CreateThread( 526 CALLER(this, &TestUnblockOnCloseWrite::_Writer), "writer"); 527 thread->Resume(); 528 529 snooze(100000); 530 CHK_ALIVE(thread); 531 532 if (fCrossOver) 533 close_tty(fTestMaster ? fSlave : fMaster); 534 else 535 close_tty(fTestMaster ? fMaster : fSlave); 536 537 snooze(100000); 538 CHK_DEAD(thread); 539 } 540 541 private: 542 int32 _Writer() 543 { 544 char buffer[32]; 545 memset(buffer, 'A', sizeof(buffer)); 546 ssize_t bytesWritten = write((fTestMaster ? fMaster : fSlave), buffer, 547 sizeof(buffer)); 548 549 CHK((bytesWritten < 0)); 550 551 return 0; 552 } 553 554 private: 555 int fMaster; 556 int fSlave; 557 bool fTestMaster; 558 bool fCrossOver; 559 bool fEcho; 560 }; 561 562 // TestSelectAlreadyReady 563 class TestSelectAlreadyReady : public TestCase { 564 public: 565 TestSelectAlreadyReady(bool master, bool write) 566 : 567 fMaster(-1), 568 fSlave(-1), 569 fTestMaster(master), 570 fWrite(write) 571 { 572 printf("TestSelectAlreadyReady(%d, %d)\n", master, write); 573 } 574 575 576 protected: 577 virtual ~TestSelectAlreadyReady() 578 { 579 close_tty(fMaster); 580 close_tty(fSlave); 581 } 582 583 virtual void Test() 584 { 585 fMaster = open_tty(0, true); 586 fSlave = open_tty(0, false); 587 588 if (!fWrite) 589 WriteDontFail((fTestMaster ? fSlave : fMaster), 1); 590 591 Thread *thread = CreateThread( 592 CALLER(this, &TestSelectAlreadyReady::_Selector), "selector"); 593 thread->Resume(); 594 595 snooze(100000); 596 CHK_DEAD(thread); 597 } 598 599 private: 600 int32 _Selector() 601 { 602 SelectSet selectSet; 603 SelectSet compareSet; 604 if (fWrite) { 605 selectSet.AddWriteFD((fTestMaster ? fMaster : fSlave)); 606 compareSet.AddWriteFD((fTestMaster ? fMaster : fSlave)); 607 } else { 608 selectSet.AddReadFD((fTestMaster ? fMaster : fSlave)); 609 compareSet.AddReadFD((fTestMaster ? fMaster : fSlave)); 610 } 611 612 int result = selectSet.Select(); 613 CHK(result > 0); 614 CHK(selectSet == compareSet); 615 616 return 0; 617 } 618 619 private: 620 int fMaster; 621 int fSlave; 622 bool fTestMaster; 623 bool fWrite; 624 }; 625 626 // TestSelectNotifyOnClose 627 class TestSelectNotifyOnClose : public TestCase { 628 public: 629 TestSelectNotifyOnClose(bool master) 630 : fMaster(-1), 631 fSlave(-1), 632 fTestMaster(master) 633 { 634 printf("TestSelectNotifyOnClose(%d)\n", master); 635 } 636 637 638 protected: 639 virtual ~TestSelectNotifyOnClose() 640 { 641 close_tty(fMaster); 642 close_tty(fSlave); 643 } 644 645 virtual void Test() 646 { 647 fMaster = open_tty(0, true); 648 fSlave = open_tty(0, false); 649 650 WriteUntilBlock((fTestMaster ? fMaster : fSlave)); 651 652 Thread *thread = CreateThread( 653 CALLER(this, &TestSelectNotifyOnClose::_Selector), "selector"); 654 thread->Resume(); 655 656 snooze(100000); 657 CHK_ALIVE(thread); 658 659 close_tty((fTestMaster ? fSlave : fMaster)); 660 661 snooze(100000); 662 CHK_DEAD(thread); 663 } 664 665 private: 666 int32 _Selector() 667 { 668 int fd = (fTestMaster ? fMaster : fSlave); 669 670 SelectSet selectSet; 671 selectSet.AddReadFD(fd); 672 selectSet.AddWriteFD(fd); 673 selectSet.AddErrorFD(fd); 674 675 // In case the slave is closed while we select() on the master, only a 676 // `write' event will arrive. 677 SelectSet compareSet; 678 if (!fTestMaster) { 679 compareSet.AddReadFD(fd); 680 compareSet.AddErrorFD(fd); 681 } 682 compareSet.AddWriteFD(fd); 683 684 int result = selectSet.Select(); 685 CHK(result > 0); 686 CHK(selectSet == compareSet); 687 688 return 0; 689 } 690 691 private: 692 int fMaster; 693 int fSlave; 694 bool fTestMaster; 695 }; 696 697 // TestSelectNotifyAfterPending 698 class TestSelectNotifyAfterPending : public TestCase { 699 public: 700 TestSelectNotifyAfterPending(bool master, bool write, bool unblock) 701 : 702 fMaster(-1), 703 fSlave(-1), 704 fTestMaster(master), 705 fWrite(write), 706 fUnblock(unblock) 707 { 708 printf("TestSelectNotifyAfterPending(%d, %d, %d)\n", master, write, 709 unblock); 710 } 711 712 713 protected: 714 virtual ~TestSelectNotifyAfterPending() 715 { 716 close_tty(fMaster); 717 close_tty(fSlave); 718 } 719 720 virtual void Test() 721 { 722 fMaster = open_tty(0, true); 723 fSlave = open_tty(0, false); 724 725 if (fWrite) 726 WriteUntilBlock((fTestMaster ? fMaster : fSlave)); 727 728 Thread *readWriter = CreateThread( 729 CALLER(this, &TestSelectNotifyAfterPending::_ReadWriter), 730 "read-writer"); 731 Thread *selector = CreateThread( 732 CALLER(this, &TestSelectNotifyAfterPending::_Selector), "selector"); 733 734 readWriter->Resume(); 735 selector->Resume(); 736 737 snooze(100000); 738 CHK_ALIVE(readWriter); 739 CHK_ALIVE(selector); 740 741 if (fUnblock) { 742 // unblock the read-writer and the selector 743 if (fWrite) 744 ReadDontFail((fTestMaster ? fSlave : fMaster), 2); 745 else 746 WriteDontFail((fTestMaster ? fSlave : fMaster), 2); 747 748 snooze(100000); 749 CHK_DEAD(readWriter); 750 CHK_DEAD(selector); 751 752 } else { 753 // unblock the read-writer, but not the selector 754 if (fWrite) 755 ReadDontFail((fTestMaster ? fSlave : fMaster), 1); 756 else 757 WriteDontFail((fTestMaster ? fSlave : fMaster), 1); 758 759 snooze(100000); 760 CHK_DEAD(readWriter); 761 CHK_ALIVE(selector); 762 763 close_tty((fTestMaster ? fMaster : fSlave)); 764 765 snooze(100000); 766 CHK_DEAD(selector); 767 } 768 } 769 770 private: 771 int32 _ReadWriter() 772 { 773 int fd = (fTestMaster ? fMaster : fSlave); 774 if (fWrite) 775 WriteDontFail(fd, 1); 776 else 777 ReadDontFail(fd, 1); 778 779 return 0; 780 } 781 782 int32 _Selector() 783 { 784 int fd = (fTestMaster ? fMaster : fSlave); 785 786 SelectSet selectSet; 787 SelectSet compareSet; 788 789 if (fWrite) { 790 selectSet.AddWriteFD(fd); 791 compareSet.AddWriteFD(fd); 792 } else { 793 selectSet.AddReadFD(fd); 794 compareSet.AddReadFD(fd); 795 } 796 797 int result = selectSet.Select(); 798 CHK(result > 0); 799 CHK(selectSet == compareSet); 800 801 return 0; 802 } 803 804 private: 805 int fMaster; 806 int fSlave; 807 bool fTestMaster; 808 bool fWrite; 809 bool fUnblock; 810 }; 811 812 // TestIoctlFIONRead 813 class TestIoctlFIONRead : public TestCase { 814 public: 815 TestIoctlFIONRead(bool master) 816 : 817 fMaster(-1), 818 fSlave(-1), 819 fTestMaster(master) 820 { 821 printf("TestIoctlFIONRead(%d)\n", master); 822 } 823 824 825 protected: 826 virtual ~TestIoctlFIONRead() 827 { 828 close_tty(fMaster); 829 close_tty(fSlave); 830 } 831 832 virtual void Test() 833 { 834 fMaster = open_tty(0, true); 835 fSlave = open_tty(0, false); 836 837 int fd = (fTestMaster ? fMaster : fSlave); 838 status_t err; 839 int toRead = -1; 840 841 errno = 0; 842 err = ioctl(fd, FIONREAD, NULL); 843 CHK(err == -1); 844 printf("e: %s\n", strerror(errno)); 845 // should be CHK(errno == EINVAL); !! 846 CHK(errno == EFAULT); 847 848 errno = 0; 849 err = ioctl(fd, FIONREAD, (void *)1); 850 CHK(err == -1); 851 printf("e: %s\n", strerror(errno)); 852 CHK(errno == EFAULT); 853 854 errno = 0; 855 856 err = ioctl(fd, FIONREAD, &toRead); 857 printf("e: %s\n", strerror(errno)); 858 //CHK(err == 0); 859 //CHK(toRead == 0); 860 861 WriteDontFail((fTestMaster ? fSlave : fMaster), 1); 862 863 errno = 0; 864 865 err = ioctl(fd, FIONREAD, &toRead); 866 printf("e: %d\n", err); 867 CHK(err == 0); 868 CHK(toRead == 1); 869 870 WriteUntilBlock((fTestMaster ? fSlave : fMaster)); 871 872 err = ioctl(fd, FIONREAD, &toRead); 873 CHK(err == 0); 874 CHK(toRead > 1); 875 876 close_tty((fTestMaster ? fSlave : fMaster)); 877 878 err = ioctl(fd, FIONREAD, &toRead); 879 CHK(err == 0); 880 CHK(toRead > 1); 881 882 ReadDontFail(fd, toRead); 883 884 err = ioctl(fd, FIONREAD, &toRead); 885 CHK(err == 0); 886 CHK(toRead == 0); 887 888 } 889 890 private: 891 int fMaster; 892 int fSlave; 893 bool fTestMaster; 894 }; 895 896 897 898 // #pragma mark - 899 900 int 901 main() 902 { 903 // unblock tests 904 905 RUN_TEST(new TestUnblockOnCloseRead(true, false)); 906 RUN_TEST(new TestUnblockOnCloseRead(false, false)); 907 RUN_TEST(new TestUnblockOnCloseRead(false, true)); 908 909 RUN_TEST(new TestUnblockOnCloseWrite(true, false, false)); 910 RUN_TEST(new TestUnblockOnCloseWrite(false, false, false)); 911 RUN_TEST(new TestUnblockOnCloseWrite(true, true, false)); 912 RUN_TEST(new TestUnblockOnCloseWrite(false, true, false)); 913 // TODO: How to enable echo mode? 914 // RUN_TEST(new TestUnblockOnCloseWrite(true, false, true)); 915 // RUN_TEST(new TestUnblockOnCloseWrite(false, false, true)); 916 // RUN_TEST(new TestUnblockOnCloseWrite(true, true, true)); 917 // RUN_TEST(new TestUnblockOnCloseWrite(false, true, true)); 918 919 // select tests 920 921 RUN_TEST(new TestSelectAlreadyReady(true, true)); 922 RUN_TEST(new TestSelectAlreadyReady(false, true)); 923 RUN_TEST(new TestSelectAlreadyReady(true, false)); 924 RUN_TEST(new TestSelectAlreadyReady(false, false)); 925 926 RUN_TEST(new TestSelectNotifyOnClose(true)); 927 RUN_TEST(new TestSelectNotifyOnClose(false)); 928 929 RUN_TEST(new TestSelectNotifyAfterPending(false, false, false)); 930 RUN_TEST(new TestSelectNotifyAfterPending(false, false, true)); 931 RUN_TEST(new TestSelectNotifyAfterPending(false, true, false)); 932 RUN_TEST(new TestSelectNotifyAfterPending(false, true, true)); 933 RUN_TEST(new TestSelectNotifyAfterPending(true, false, false)); 934 RUN_TEST(new TestSelectNotifyAfterPending(true, false, true)); 935 RUN_TEST(new TestSelectNotifyAfterPending(true, true, false)); 936 RUN_TEST(new TestSelectNotifyAfterPending(true, true, true)); 937 938 RUN_TEST(new TestIoctlFIONRead(true)); 939 //RUN_TEST(new TestIoctlFIONRead(false)); 940 941 return 0; 942 } 943