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,
411			strerror(errno));
412		exit(1);
413	}
414
415	return fd;
416}
417
418
419static void
420close_tty(int &fd)
421{
422	if (fd >= 0) {
423		close(fd);
424		fd = -1;
425	}
426}
427
428
429// #pragma mark -
430
431// TestUnblockOnCloseRead
432class TestUnblockOnCloseRead : public TestCase {
433public:
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
445protected:
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
473private:
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
485private:
486	int		fMaster;
487	int		fSlave;
488	bool	fTestMaster;
489	bool	fCrossOver;
490};
491
492// TestUnblockOnCloseWrite
493class TestUnblockOnCloseWrite : public TestCase {
494public:
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
508protected:
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
541private:
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
554private:
555	int		fMaster;
556	int		fSlave;
557	bool	fTestMaster;
558	bool	fCrossOver;
559	bool	fEcho;
560};
561
562// TestSelectAlreadyReady
563class TestSelectAlreadyReady : public TestCase {
564public:
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
576protected:
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
599private:
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
619private:
620	int		fMaster;
621	int		fSlave;
622	bool	fTestMaster;
623	bool	fWrite;
624};
625
626// TestSelectNotifyOnClose
627class TestSelectNotifyOnClose : public TestCase {
628public:
629	TestSelectNotifyOnClose(bool master)
630		: fMaster(-1),
631		  fSlave(-1),
632		  fTestMaster(master)
633	{
634		printf("TestSelectNotifyOnClose(%d)\n", master);
635	}
636
637
638protected:
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
665private:
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
691private:
692	int		fMaster;
693	int		fSlave;
694	bool	fTestMaster;
695};
696
697// TestSelectNotifyAfterPending
698class TestSelectNotifyAfterPending : public TestCase {
699public:
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
713protected:
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
770private:
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
804private:
805	int		fMaster;
806	int		fSlave;
807	bool	fTestMaster;
808	bool	fWrite;
809	bool	fUnblock;
810};
811
812// TestIoctlFIONRead
813class TestIoctlFIONRead : public TestCase {
814public:
815	TestIoctlFIONRead(bool master)
816		:
817		fMaster(-1),
818		fSlave(-1),
819		fTestMaster(master)
820	{
821		printf("TestIoctlFIONRead(%d)\n", master);
822	}
823
824
825protected:
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
890private:
891	int		fMaster;
892	int		fSlave;
893	bool	fTestMaster;
894};
895
896
897
898// #pragma mark -
899
900int
901main()
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