xref: /netbsd-src/regress/sys/kern/select/select.c (revision 6f39b50ccf37e978a6dc9cac665c74df89550960)
1*6f39b50cSyamt /*	$NetBSD: select.c,v 1.3 2011/11/02 16:49:12 yamt Exp $	*/
29ff0d7c1Syamt 
39ff0d7c1Syamt /*-
49ff0d7c1Syamt  * Copyright (c)2008 YAMAMOTO Takashi,
59ff0d7c1Syamt  * All rights reserved.
69ff0d7c1Syamt  *
79ff0d7c1Syamt  * Redistribution and use in source and binary forms, with or without
89ff0d7c1Syamt  * modification, are permitted provided that the following conditions
99ff0d7c1Syamt  * are met:
109ff0d7c1Syamt  * 1. Redistributions of source code must retain the above copyright
119ff0d7c1Syamt  *    notice, this list of conditions and the following disclaimer.
129ff0d7c1Syamt  * 2. Redistributions in binary form must reproduce the above copyright
139ff0d7c1Syamt  *    notice, this list of conditions and the following disclaimer in the
149ff0d7c1Syamt  *    documentation and/or other materials provided with the distribution.
159ff0d7c1Syamt  *
169ff0d7c1Syamt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
179ff0d7c1Syamt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
189ff0d7c1Syamt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199ff0d7c1Syamt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
209ff0d7c1Syamt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219ff0d7c1Syamt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
229ff0d7c1Syamt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
239ff0d7c1Syamt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249ff0d7c1Syamt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
259ff0d7c1Syamt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
269ff0d7c1Syamt  * SUCH DAMAGE.
279ff0d7c1Syamt  */
289ff0d7c1Syamt 
299ff0d7c1Syamt #define	FD_SETSIZE	65536
309ff0d7c1Syamt #include <sys/select.h>
310c65d1b6Sad #include <sys/atomic.h>
32*6f39b50cSyamt #include <sys/time.h>
339ff0d7c1Syamt 
34*6f39b50cSyamt #include <assert.h>
359ff0d7c1Syamt #include <errno.h>
369ff0d7c1Syamt #include <fcntl.h>
379ff0d7c1Syamt #include <pthread.h>
38*6f39b50cSyamt #include <stdint.h>
399ff0d7c1Syamt #include <stdio.h>
409ff0d7c1Syamt #include <stdlib.h>
419ff0d7c1Syamt #include <string.h>
429ff0d7c1Syamt #include <unistd.h>
439ff0d7c1Syamt 
449ff0d7c1Syamt #define	NPIPE	128
459ff0d7c1Syamt #define	NTHREAD	64
46*6f39b50cSyamt #define	NBALLS	5
479ff0d7c1Syamt #define	VERBOSE	0
489ff0d7c1Syamt 
499ff0d7c1Syamt #if !defined(RANDOM_MAX)
509ff0d7c1Syamt #define	RANDOM_MAX	((1UL << 31) - 1)
519ff0d7c1Syamt #endif
529ff0d7c1Syamt 
539ff0d7c1Syamt int fds[NPIPE][2];
549ff0d7c1Syamt 
55*6f39b50cSyamt volatile unsigned count;
560c65d1b6Sad 
570c65d1b6Sad pthread_barrier_t barrier;
589ff0d7c1Syamt 
599ff0d7c1Syamt static void
dowrite(void)609ff0d7c1Syamt dowrite(void)
619ff0d7c1Syamt {
629ff0d7c1Syamt 	char buf[1];
639ff0d7c1Syamt 	int fd;
649ff0d7c1Syamt 	int i;
659ff0d7c1Syamt 
669ff0d7c1Syamt 	i = random() % NPIPE;
679ff0d7c1Syamt 	fd = fds[i][1];
689ff0d7c1Syamt #if VERBOSE
699ff0d7c1Syamt 	printf("[%p] write %d\n", (void *)pthread_self(), fd);
709ff0d7c1Syamt #endif
719ff0d7c1Syamt 	if (write(fd, buf, sizeof(buf)) == -1) {
729ff0d7c1Syamt 		perror("write");
739ff0d7c1Syamt 		abort();
749ff0d7c1Syamt 	}
759ff0d7c1Syamt }
769ff0d7c1Syamt 
779ff0d7c1Syamt static void *
f(void * dummy)789ff0d7c1Syamt f(void *dummy)
799ff0d7c1Syamt {
809ff0d7c1Syamt 
810c65d1b6Sad 	pthread_barrier_wait(&barrier);
820c65d1b6Sad 
839ff0d7c1Syamt 	for (;;) {
849ff0d7c1Syamt 		struct timeval to;
859ff0d7c1Syamt 		fd_set oset;
869ff0d7c1Syamt 		fd_set set;
879ff0d7c1Syamt 		int maxfd = -1;
889ff0d7c1Syamt 		int nfd = 0;
899ff0d7c1Syamt 		int ret;
909ff0d7c1Syamt 		int fd;
919ff0d7c1Syamt 		int i;
929ff0d7c1Syamt 
939ff0d7c1Syamt 		FD_ZERO(&set);
949ff0d7c1Syamt 		do {
959ff0d7c1Syamt 			for (i = 0; i < NPIPE; i++) {
969ff0d7c1Syamt 				fd = fds[i][0];
979ff0d7c1Syamt 				if (fd > FD_SETSIZE) {
989ff0d7c1Syamt 					fprintf(stderr,
999ff0d7c1Syamt 					    "fd(%d) > FD_SETSIZE(%d)\n",
1009ff0d7c1Syamt 					    fd, FD_SETSIZE);
1019ff0d7c1Syamt 					abort();
1029ff0d7c1Syamt 				}
1039ff0d7c1Syamt 				if (random() & 1) {
104*6f39b50cSyamt 					assert(!FD_ISSET(fd, &set));
1059ff0d7c1Syamt 					FD_SET(fd, &set);
106*6f39b50cSyamt 					nfd++;
1079ff0d7c1Syamt 					if (fd > maxfd) {
1089ff0d7c1Syamt 						maxfd = fd;
1099ff0d7c1Syamt 					}
1109ff0d7c1Syamt 				}
1119ff0d7c1Syamt 			}
1129ff0d7c1Syamt 		} while (nfd == 0);
1139ff0d7c1Syamt 		memcpy(&oset, &set, sizeof(oset));
1149ff0d7c1Syamt 		memset(&to, 0, sizeof(to));
1159ff0d7c1Syamt 		to.tv_sec = random() % 10;
1169ff0d7c1Syamt 		to.tv_usec = random() % 1000000;
1179ff0d7c1Syamt #if VERBOSE
1189ff0d7c1Syamt 		printf("[%p] select start to=%lu\n", (void *)pthread_self(),
1199ff0d7c1Syamt 		    (unsigned long)to.tv_sec);
1209ff0d7c1Syamt #endif
1219ff0d7c1Syamt 		ret = select(maxfd + 1, &set, NULL, NULL, &to);
1229ff0d7c1Syamt #if VERBOSE
1239ff0d7c1Syamt 		printf("[%p] select done ret=%d\n",
1249ff0d7c1Syamt 		    (void *)pthread_self(), ret);
1259ff0d7c1Syamt #endif
1269ff0d7c1Syamt 		if (ret == -1) {
1279ff0d7c1Syamt 			perror("select");
1289ff0d7c1Syamt 			abort();
1299ff0d7c1Syamt 		}
1309ff0d7c1Syamt 		if (ret > nfd) {
1319ff0d7c1Syamt 			fprintf(stderr, "[%p] unexpected return value %d\n",
1329ff0d7c1Syamt 			    (void *)pthread_self(), ret);
1339ff0d7c1Syamt 			abort();
1349ff0d7c1Syamt 		}
135*6f39b50cSyamt 		if (ret > NBALLS) {
136*6f39b50cSyamt 			fprintf(stderr, "[%p] unexpected return value %d"
137*6f39b50cSyamt 			    " > NBALLS\n",
138*6f39b50cSyamt 			    (void *)pthread_self(), ret);
139*6f39b50cSyamt 			abort();
140*6f39b50cSyamt 		}
1419ff0d7c1Syamt 		nfd = 0;
1429ff0d7c1Syamt 		for (fd = 0; fd <= maxfd; fd++) {
1439ff0d7c1Syamt 			if (FD_ISSET(fd, &set)) {
1449ff0d7c1Syamt 				char buf[1];
1459ff0d7c1Syamt 
1469ff0d7c1Syamt #if VERBOSE
1479ff0d7c1Syamt 				printf("[%p] read %d\n",
1489ff0d7c1Syamt 				    (void *)pthread_self(), fd);
1499ff0d7c1Syamt #endif
1509ff0d7c1Syamt 				if (!FD_ISSET(fd, &oset)) {
1519ff0d7c1Syamt 					fprintf(stderr, "[%p] unexpected\n",
1529ff0d7c1Syamt 					    (void *)pthread_self());
1539ff0d7c1Syamt 					abort();
1549ff0d7c1Syamt 				}
1559ff0d7c1Syamt 				if (read(fd, buf, sizeof(buf)) == -1) {
1569ff0d7c1Syamt 					if (errno != EAGAIN) {
1579ff0d7c1Syamt 						perror("read");
1589ff0d7c1Syamt 						abort();
1599ff0d7c1Syamt 					}
1609ff0d7c1Syamt 				} else {
1619ff0d7c1Syamt 					dowrite();
1620c65d1b6Sad 					atomic_inc_uint(&count);
1639ff0d7c1Syamt 				}
1649ff0d7c1Syamt 				nfd++;
1659ff0d7c1Syamt 			}
1669ff0d7c1Syamt 		}
1679ff0d7c1Syamt 		if (ret != nfd) {
1689ff0d7c1Syamt 			fprintf(stderr, "[%p] ret(%d) != nfd(%d)\n",
1699ff0d7c1Syamt 			    (void *)pthread_self(), ret, nfd);
1709ff0d7c1Syamt 			abort();
1719ff0d7c1Syamt 		}
1729ff0d7c1Syamt 	}
1739ff0d7c1Syamt }
1749ff0d7c1Syamt 
1759ff0d7c1Syamt int
main(int argc,char * argv[])1769ff0d7c1Syamt main(int argc, char *argv[])
1779ff0d7c1Syamt {
1789ff0d7c1Syamt 	pthread_t pt[NTHREAD];
1799ff0d7c1Syamt 	int i;
1809ff0d7c1Syamt 	unsigned int secs;
181*6f39b50cSyamt 	struct timeval start_tv;
182*6f39b50cSyamt 	struct timeval end_tv;
183*6f39b50cSyamt 	uint64_t usecs;
184*6f39b50cSyamt 	unsigned int result;
1859ff0d7c1Syamt 
1869ff0d7c1Syamt 	secs = atoi(argv[1]);
1879ff0d7c1Syamt 
1889ff0d7c1Syamt 	for (i = 0; i < NPIPE; i++) {
1899ff0d7c1Syamt 		if (pipe(fds[i])) {
1909ff0d7c1Syamt 			perror("pipe");
1919ff0d7c1Syamt 			abort();
1929ff0d7c1Syamt 		}
1939ff0d7c1Syamt 		if (fcntl(fds[i][0], F_SETFL, O_NONBLOCK) == -1) {
1949ff0d7c1Syamt 			perror("fcntl");
1959ff0d7c1Syamt 			abort();
1969ff0d7c1Syamt 		}
1979ff0d7c1Syamt 	}
1980c65d1b6Sad 	pthread_barrier_init(&barrier, NULL, NTHREAD + 1);
1999ff0d7c1Syamt 	for (i = 0; i < NTHREAD; i++) {
2009ff0d7c1Syamt 		int error = pthread_create(&pt[i], NULL, f, NULL);
2019ff0d7c1Syamt 		if (error) {
2029ff0d7c1Syamt 			errno = error;
2039ff0d7c1Syamt 			perror("pthread_create");
2049ff0d7c1Syamt 			abort();
2059ff0d7c1Syamt 		}
2069ff0d7c1Syamt 	}
2070c65d1b6Sad 	pthread_barrier_wait(&barrier);
208*6f39b50cSyamt 	gettimeofday(&start_tv, NULL);
209*6f39b50cSyamt 	assert(count == 0);
210*6f39b50cSyamt 	for (i = 0; i < NBALLS; i++) {
2119ff0d7c1Syamt 		dowrite();
212*6f39b50cSyamt 	}
2139ff0d7c1Syamt 	sleep(secs);
214*6f39b50cSyamt 	gettimeofday(&end_tv, NULL);
215*6f39b50cSyamt 	result = count;
216*6f39b50cSyamt 	usecs = (end_tv.tv_sec - start_tv.tv_sec) * 1000000
217*6f39b50cSyamt 	    + end_tv.tv_usec - start_tv.tv_usec;
218*6f39b50cSyamt 	printf("%u / %f = %f\n", result, (double)usecs / 1000000,
219*6f39b50cSyamt 	    (double)result / usecs * 1000000);
2209ff0d7c1Syamt 	exit(EXIT_SUCCESS);
2219ff0d7c1Syamt }
222