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
56struct 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
116private:
117	int	fCount;
118};
119
120// SelectSet
121class SelectSet {
122public:
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
183private:
184	FDSet	fReadSet;
185	FDSet	fWriteSet;
186	FDSet	fErrorSet;
187};
188
189// Runnable
190class Runnable {
191public:
192	virtual ~Runnable() {}
193	virtual int32 Run() = 0;
194};
195
196// Caller
197template<typename Type>
198class Caller : public Runnable {
199public:
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
211private:
212	Type	*fObject;
213	int32	(Type::*fFunction)();
214};
215
216// create_caller
217template<typename Type>
218static inline Runnable *
219create_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
227struct Thread : public DoublyLinkedListLinkImpl<Thread> {
228public:
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
267private:
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
278class TestCase {
279public:
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
295protected:
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
390private:
391	typedef DoublyLinkedList<Thread> ThreadList;
392
393	ThreadList	fThreads;
394};
395
396
397// open_tty
398static int
399open_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
418static void
419close_tty(int &fd)
420{
421	if (fd >= 0) {
422		close(fd);
423		fd = -1;
424	}
425}
426
427
428// #pragma mark -
429
430// TestUnblockOnCloseRead
431class TestUnblockOnCloseRead : public TestCase {
432public:
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
443protected:
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
471private:
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
483private:
484	int		fMaster;
485	int		fSlave;
486	bool	fTestMaster;
487	bool	fCrossOver;
488};
489
490// TestUnblockOnCloseWrite
491class TestUnblockOnCloseWrite : public TestCase {
492public:
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
505protected:
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
538private:
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
551private:
552	int		fMaster;
553	int		fSlave;
554	bool	fTestMaster;
555	bool	fCrossOver;
556	bool	fEcho;
557};
558
559// TestSelectAlreadyReady
560class TestSelectAlreadyReady : public TestCase {
561public:
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
572protected:
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
595private:
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
615private:
616	int		fMaster;
617	int		fSlave;
618	bool	fTestMaster;
619	bool	fWrite;
620};
621
622// TestSelectNotifyOnClose
623class TestSelectNotifyOnClose : public TestCase {
624public:
625	TestSelectNotifyOnClose(bool master)
626		: fMaster(-1),
627		  fSlave(-1),
628		  fTestMaster(master)
629	{
630		printf("TestSelectNotifyOnClose(%d)\n", master);
631	}
632
633
634protected:
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
661private:
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
687private:
688	int		fMaster;
689	int		fSlave;
690	bool	fTestMaster;
691};
692
693// TestSelectNotifyAfterPending
694class TestSelectNotifyAfterPending : public TestCase {
695public:
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
708protected:
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
765private:
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
799private:
800	int		fMaster;
801	int		fSlave;
802	bool	fTestMaster;
803	bool	fWrite;
804	bool	fUnblock;
805};
806
807// TestIoctlFIONRead
808class TestIoctlFIONRead : public TestCase {
809public:
810	TestIoctlFIONRead(bool master)
811		: fMaster(-1),
812		  fSlave(-1),
813		  fTestMaster(master)
814	{
815		printf("TestIoctlFIONRead(%d)\n", master);
816	}
817
818
819protected:
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);
838printf("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);
845printf("e: %s\n", strerror(errno));
846		CHK(errno == EFAULT);
847
848		errno = 0;
849
850		err = ioctl(fd, FIONREAD, &toRead);
851printf("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);
860printf("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
884private:
885	int		fMaster;
886	int		fSlave;
887	bool	fTestMaster;
888};
889
890
891
892// #pragma mark -
893
894int
895main()
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