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, strerror(errno)); 411 exit(1); 412 } 413 414 return fd; 415 } 416 417 418 static void 419 close_tty(int &fd) 420 { 421 if (fd >= 0) { 422 close(fd); 423 fd = -1; 424 } 425 } 426 427 428 // #pragma mark - 429 430 // TestUnblockOnCloseRead 431 class TestUnblockOnCloseRead : public TestCase { 432 public: 433 TestUnblockOnCloseRead(bool master, bool crossOver) 434 : fMaster(-1), 435 fSlave(-1), 436 fTestMaster(master), 437 fCrossOver(crossOver) 438 { 439 printf("TestUnblockOnCloseRead(%d, %d)\n", master, crossOver); 440 } 441 442 443 protected: 444 virtual ~TestUnblockOnCloseRead() 445 { 446 close_tty(fMaster); 447 close_tty(fSlave); 448 } 449 450 virtual void Test() 451 { 452 fMaster = open_tty(0, true); 453 fSlave = open_tty(0, false); 454 455 Thread *thread = CreateThread( 456 CALLER(this, &TestUnblockOnCloseRead::_Reader), "reader"); 457 thread->Resume(); 458 459 snooze(100000); 460 CHK_ALIVE(thread); 461 462 if (fCrossOver) 463 close_tty(fTestMaster ? fSlave : fMaster); 464 else 465 close_tty(fTestMaster ? fMaster : fSlave); 466 467 snooze(100000); 468 CHK_DEAD(thread); 469 } 470 471 private: 472 int32 _Reader() 473 { 474 char buffer[32]; 475 ssize_t bytesRead = read((fTestMaster ? fMaster : fSlave), buffer, 476 sizeof(buffer)); 477 478 CHK((bytesRead < 0)); 479 480 return 0; 481 } 482 483 private: 484 int fMaster; 485 int fSlave; 486 bool fTestMaster; 487 bool fCrossOver; 488 }; 489 490 // TestUnblockOnCloseWrite 491 class TestUnblockOnCloseWrite : public TestCase { 492 public: 493 TestUnblockOnCloseWrite(bool master, bool crossOver, bool echo) 494 : fMaster(-1), 495 fSlave(-1), 496 fTestMaster(master), 497 fCrossOver(crossOver), 498 fEcho(echo) 499 { 500 printf("TestUnblockOnCloseWrite(%d, %d, %d)\n", master, crossOver, 501 echo); 502 } 503 504 505 protected: 506 virtual ~TestUnblockOnCloseWrite() 507 { 508 close_tty(fMaster); 509 close_tty(fSlave); 510 } 511 512 virtual void Test() 513 { 514 fMaster = open_tty(0, true); 515 fSlave = open_tty(0, false); 516 517 if (fEcho) 518 SetEcho((fTestMaster ? fSlave : fMaster)); 519 520 WriteUntilBlock((fTestMaster ? fMaster : fSlave)); 521 522 Thread *thread = CreateThread( 523 CALLER(this, &TestUnblockOnCloseWrite::_Writer), "writer"); 524 thread->Resume(); 525 526 snooze(100000); 527 CHK_ALIVE(thread); 528 529 if (fCrossOver) 530 close_tty(fTestMaster ? fSlave : fMaster); 531 else 532 close_tty(fTestMaster ? fMaster : fSlave); 533 534 snooze(100000); 535 CHK_DEAD(thread); 536 } 537 538 private: 539 int32 _Writer() 540 { 541 char buffer[32]; 542 memset(buffer, 'A', sizeof(buffer)); 543 ssize_t bytesWritten = write((fTestMaster ? fMaster : fSlave), buffer, 544 sizeof(buffer)); 545 546 CHK((bytesWritten < 0)); 547 548 return 0; 549 } 550 551 private: 552 int fMaster; 553 int fSlave; 554 bool fTestMaster; 555 bool fCrossOver; 556 bool fEcho; 557 }; 558 559 // TestSelectAlreadyReady 560 class TestSelectAlreadyReady : public TestCase { 561 public: 562 TestSelectAlreadyReady(bool master, bool write) 563 : fMaster(-1), 564 fSlave(-1), 565 fTestMaster(master), 566 fWrite(write) 567 { 568 printf("TestSelectAlreadyReady(%d, %d)\n", master, write); 569 } 570 571 572 protected: 573 virtual ~TestSelectAlreadyReady() 574 { 575 close_tty(fMaster); 576 close_tty(fSlave); 577 } 578 579 virtual void Test() 580 { 581 fMaster = open_tty(0, true); 582 fSlave = open_tty(0, false); 583 584 if (!fWrite) 585 WriteDontFail((fTestMaster ? fSlave : fMaster), 1); 586 587 Thread *thread = CreateThread( 588 CALLER(this, &TestSelectAlreadyReady::_Selector), "selector"); 589 thread->Resume(); 590 591 snooze(100000); 592 CHK_DEAD(thread); 593 } 594 595 private: 596 int32 _Selector() 597 { 598 SelectSet selectSet; 599 SelectSet compareSet; 600 if (fWrite) { 601 selectSet.AddWriteFD((fTestMaster ? fMaster : fSlave)); 602 compareSet.AddWriteFD((fTestMaster ? fMaster : fSlave)); 603 } else { 604 selectSet.AddReadFD((fTestMaster ? fMaster : fSlave)); 605 compareSet.AddReadFD((fTestMaster ? fMaster : fSlave)); 606 } 607 608 int result = selectSet.Select(); 609 CHK(result > 0); 610 CHK(selectSet == compareSet); 611 612 return 0; 613 } 614 615 private: 616 int fMaster; 617 int fSlave; 618 bool fTestMaster; 619 bool fWrite; 620 }; 621 622 // TestSelectNotifyOnClose 623 class TestSelectNotifyOnClose : public TestCase { 624 public: 625 TestSelectNotifyOnClose(bool master) 626 : fMaster(-1), 627 fSlave(-1), 628 fTestMaster(master) 629 { 630 printf("TestSelectNotifyOnClose(%d)\n", master); 631 } 632 633 634 protected: 635 virtual ~TestSelectNotifyOnClose() 636 { 637 close_tty(fMaster); 638 close_tty(fSlave); 639 } 640 641 virtual void Test() 642 { 643 fMaster = open_tty(0, true); 644 fSlave = open_tty(0, false); 645 646 WriteUntilBlock((fTestMaster ? fMaster : fSlave)); 647 648 Thread *thread = CreateThread( 649 CALLER(this, &TestSelectNotifyOnClose::_Selector), "selector"); 650 thread->Resume(); 651 652 snooze(100000); 653 CHK_ALIVE(thread); 654 655 close_tty((fTestMaster ? fSlave : fMaster)); 656 657 snooze(100000); 658 CHK_DEAD(thread); 659 } 660 661 private: 662 int32 _Selector() 663 { 664 int fd = (fTestMaster ? fMaster : fSlave); 665 666 SelectSet selectSet; 667 selectSet.AddReadFD(fd); 668 selectSet.AddWriteFD(fd); 669 selectSet.AddErrorFD(fd); 670 671 // In case the slave is closed while we select() on the master, only a 672 // `write' event will arrive. 673 SelectSet compareSet; 674 if (!fTestMaster) { 675 compareSet.AddReadFD(fd); 676 compareSet.AddErrorFD(fd); 677 } 678 compareSet.AddWriteFD(fd); 679 680 int result = selectSet.Select(); 681 CHK(result > 0); 682 CHK(selectSet == compareSet); 683 684 return 0; 685 } 686 687 private: 688 int fMaster; 689 int fSlave; 690 bool fTestMaster; 691 }; 692 693 // TestSelectNotifyAfterPending 694 class TestSelectNotifyAfterPending : public TestCase { 695 public: 696 TestSelectNotifyAfterPending(bool master, bool write, bool unblock) 697 : fMaster(-1), 698 fSlave(-1), 699 fTestMaster(master), 700 fWrite(write), 701 fUnblock(unblock) 702 { 703 printf("TestSelectNotifyAfterPending(%d, %d, %d)\n", master, write, 704 unblock); 705 } 706 707 708 protected: 709 virtual ~TestSelectNotifyAfterPending() 710 { 711 close_tty(fMaster); 712 close_tty(fSlave); 713 } 714 715 virtual void Test() 716 { 717 fMaster = open_tty(0, true); 718 fSlave = open_tty(0, false); 719 720 if (fWrite) 721 WriteUntilBlock((fTestMaster ? fMaster : fSlave)); 722 723 Thread *readWriter = CreateThread( 724 CALLER(this, &TestSelectNotifyAfterPending::_ReadWriter), 725 "read-writer"); 726 Thread *selector = CreateThread( 727 CALLER(this, &TestSelectNotifyAfterPending::_Selector), "selector"); 728 729 readWriter->Resume(); 730 selector->Resume(); 731 732 snooze(100000); 733 CHK_ALIVE(readWriter); 734 CHK_ALIVE(selector); 735 736 if (fUnblock) { 737 // unblock the read-writer and the selector 738 if (fWrite) 739 ReadDontFail((fTestMaster ? fSlave : fMaster), 2); 740 else 741 WriteDontFail((fTestMaster ? fSlave : fMaster), 2); 742 743 snooze(100000); 744 CHK_DEAD(readWriter); 745 CHK_DEAD(selector); 746 747 } else { 748 // unblock the read-writer, but not the selector 749 if (fWrite) 750 ReadDontFail((fTestMaster ? fSlave : fMaster), 1); 751 else 752 WriteDontFail((fTestMaster ? fSlave : fMaster), 1); 753 754 snooze(100000); 755 CHK_DEAD(readWriter); 756 CHK_ALIVE(selector); 757 758 close_tty((fTestMaster ? fMaster : fSlave)); 759 760 snooze(100000); 761 CHK_DEAD(selector); 762 } 763 } 764 765 private: 766 int32 _ReadWriter() 767 { 768 int fd = (fTestMaster ? fMaster : fSlave); 769 if (fWrite) 770 WriteDontFail(fd, 1); 771 else 772 ReadDontFail(fd, 1); 773 774 return 0; 775 } 776 777 int32 _Selector() 778 { 779 int fd = (fTestMaster ? fMaster : fSlave); 780 781 SelectSet selectSet; 782 SelectSet compareSet; 783 784 if (fWrite) { 785 selectSet.AddWriteFD(fd); 786 compareSet.AddWriteFD(fd); 787 } else { 788 selectSet.AddReadFD(fd); 789 compareSet.AddReadFD(fd); 790 } 791 792 int result = selectSet.Select(); 793 CHK(result > 0); 794 CHK(selectSet == compareSet); 795 796 return 0; 797 } 798 799 private: 800 int fMaster; 801 int fSlave; 802 bool fTestMaster; 803 bool fWrite; 804 bool fUnblock; 805 }; 806 807 // TestIoctlFIONRead 808 class TestIoctlFIONRead : public TestCase { 809 public: 810 TestIoctlFIONRead(bool master) 811 : fMaster(-1), 812 fSlave(-1), 813 fTestMaster(master) 814 { 815 printf("TestIoctlFIONRead(%d)\n", master); 816 } 817 818 819 protected: 820 virtual ~TestIoctlFIONRead() 821 { 822 close_tty(fMaster); 823 close_tty(fSlave); 824 } 825 826 virtual void Test() 827 { 828 fMaster = open_tty(0, true); 829 fSlave = open_tty(0, false); 830 831 int fd = (fTestMaster ? fMaster : fSlave); 832 status_t err; 833 int toRead = -1; 834 835 errno = 0; 836 err = ioctl(fd, FIONREAD, NULL); 837 CHK(err == -1); 838 printf("e: %s\n", strerror(errno)); 839 // should be CHK(errno == EINVAL); !! 840 CHK(errno == EFAULT); 841 842 errno = 0; 843 err = ioctl(fd, FIONREAD, (void *)1); 844 CHK(err == -1); 845 printf("e: %s\n", strerror(errno)); 846 CHK(errno == EFAULT); 847 848 errno = 0; 849 850 err = ioctl(fd, FIONREAD, &toRead); 851 printf("e: %s\n", strerror(errno)); 852 //CHK(err == 0); 853 //CHK(toRead == 0); 854 855 WriteDontFail((fTestMaster ? fSlave : fMaster), 1); 856 857 errno = 0; 858 859 err = ioctl(fd, FIONREAD, &toRead); 860 printf("e: %d\n", err); 861 CHK(err == 0); 862 CHK(toRead == 1); 863 864 WriteUntilBlock((fTestMaster ? fSlave : fMaster)); 865 866 err = ioctl(fd, FIONREAD, &toRead); 867 CHK(err == 0); 868 CHK(toRead > 1); 869 870 close_tty((fTestMaster ? fSlave : fMaster)); 871 872 err = ioctl(fd, FIONREAD, &toRead); 873 CHK(err == 0); 874 CHK(toRead > 1); 875 876 ReadDontFail(fd, toRead); 877 878 err = ioctl(fd, FIONREAD, &toRead); 879 CHK(err == 0); 880 CHK(toRead == 0); 881 882 } 883 884 private: 885 int fMaster; 886 int fSlave; 887 bool fTestMaster; 888 }; 889 890 891 892 // #pragma mark - 893 894 int 895 main() 896 { 897 // unblock tests 898 899 RUN_TEST(new TestUnblockOnCloseRead(true, false)); 900 RUN_TEST(new TestUnblockOnCloseRead(false, false)); 901 RUN_TEST(new TestUnblockOnCloseRead(false, true)); 902 903 RUN_TEST(new TestUnblockOnCloseWrite(true, false, false)); 904 RUN_TEST(new TestUnblockOnCloseWrite(false, false, false)); 905 RUN_TEST(new TestUnblockOnCloseWrite(true, true, false)); 906 RUN_TEST(new TestUnblockOnCloseWrite(false, true, false)); 907 // TODO: How to enable echo mode? 908 // RUN_TEST(new TestUnblockOnCloseWrite(true, false, true)); 909 // RUN_TEST(new TestUnblockOnCloseWrite(false, false, true)); 910 // RUN_TEST(new TestUnblockOnCloseWrite(true, true, true)); 911 // RUN_TEST(new TestUnblockOnCloseWrite(false, true, true)); 912 913 // select tests 914 915 RUN_TEST(new TestSelectAlreadyReady(true, true)); 916 RUN_TEST(new TestSelectAlreadyReady(false, true)); 917 RUN_TEST(new TestSelectAlreadyReady(true, false)); 918 RUN_TEST(new TestSelectAlreadyReady(false, false)); 919 920 RUN_TEST(new TestSelectNotifyOnClose(true)); 921 RUN_TEST(new TestSelectNotifyOnClose(false)); 922 923 RUN_TEST(new TestSelectNotifyAfterPending(false, false, false)); 924 RUN_TEST(new TestSelectNotifyAfterPending(false, false, true)); 925 RUN_TEST(new TestSelectNotifyAfterPending(false, true, false)); 926 RUN_TEST(new TestSelectNotifyAfterPending(false, true, true)); 927 RUN_TEST(new TestSelectNotifyAfterPending(true, false, false)); 928 RUN_TEST(new TestSelectNotifyAfterPending(true, false, true)); 929 RUN_TEST(new TestSelectNotifyAfterPending(true, true, false)); 930 RUN_TEST(new TestSelectNotifyAfterPending(true, true, true)); 931 932 RUN_TEST(new TestIoctlFIONRead(true)); 933 //RUN_TEST(new TestIoctlFIONRead(false)); 934 935 return 0; 936 } 937