Home | History | Annotate | Line # | Download | only in select
      1 /*	$NetBSD: select.c,v 1.3 2011/11/02 16:49:12 yamt Exp $	*/
      2 
      3 /*-
      4  * Copyright (c)2008 YAMAMOTO Takashi,
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #define	FD_SETSIZE	65536
     30 #include <sys/select.h>
     31 #include <sys/atomic.h>
     32 #include <sys/time.h>
     33 
     34 #include <assert.h>
     35 #include <errno.h>
     36 #include <fcntl.h>
     37 #include <pthread.h>
     38 #include <stdint.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <unistd.h>
     43 
     44 #define	NPIPE	128
     45 #define	NTHREAD	64
     46 #define	NBALLS	5
     47 #define	VERBOSE	0
     48 
     49 #if !defined(RANDOM_MAX)
     50 #define	RANDOM_MAX	((1UL << 31) - 1)
     51 #endif
     52 
     53 int fds[NPIPE][2];
     54 
     55 volatile unsigned count;
     56 
     57 pthread_barrier_t barrier;
     58 
     59 static void
     60 dowrite(void)
     61 {
     62 	char buf[1];
     63 	int fd;
     64 	int i;
     65 
     66 	i = random() % NPIPE;
     67 	fd = fds[i][1];
     68 #if VERBOSE
     69 	printf("[%p] write %d\n", (void *)pthread_self(), fd);
     70 #endif
     71 	if (write(fd, buf, sizeof(buf)) == -1) {
     72 		perror("write");
     73 		abort();
     74 	}
     75 }
     76 
     77 static void *
     78 f(void *dummy)
     79 {
     80 
     81 	pthread_barrier_wait(&barrier);
     82 
     83 	for (;;) {
     84 		struct timeval to;
     85 		fd_set oset;
     86 		fd_set set;
     87 		int maxfd = -1;
     88 		int nfd = 0;
     89 		int ret;
     90 		int fd;
     91 		int i;
     92 
     93 		FD_ZERO(&set);
     94 		do {
     95 			for (i = 0; i < NPIPE; i++) {
     96 				fd = fds[i][0];
     97 				if (fd > FD_SETSIZE) {
     98 					fprintf(stderr,
     99 					    "fd(%d) > FD_SETSIZE(%d)\n",
    100 					    fd, FD_SETSIZE);
    101 					abort();
    102 				}
    103 				if (random() & 1) {
    104 					assert(!FD_ISSET(fd, &set));
    105 					FD_SET(fd, &set);
    106 					nfd++;
    107 					if (fd > maxfd) {
    108 						maxfd = fd;
    109 					}
    110 				}
    111 			}
    112 		} while (nfd == 0);
    113 		memcpy(&oset, &set, sizeof(oset));
    114 		memset(&to, 0, sizeof(to));
    115 		to.tv_sec = random() % 10;
    116 		to.tv_usec = random() % 1000000;
    117 #if VERBOSE
    118 		printf("[%p] select start to=%lu\n", (void *)pthread_self(),
    119 		    (unsigned long)to.tv_sec);
    120 #endif
    121 		ret = select(maxfd + 1, &set, NULL, NULL, &to);
    122 #if VERBOSE
    123 		printf("[%p] select done ret=%d\n",
    124 		    (void *)pthread_self(), ret);
    125 #endif
    126 		if (ret == -1) {
    127 			perror("select");
    128 			abort();
    129 		}
    130 		if (ret > nfd) {
    131 			fprintf(stderr, "[%p] unexpected return value %d\n",
    132 			    (void *)pthread_self(), ret);
    133 			abort();
    134 		}
    135 		if (ret > NBALLS) {
    136 			fprintf(stderr, "[%p] unexpected return value %d"
    137 			    " > NBALLS\n",
    138 			    (void *)pthread_self(), ret);
    139 			abort();
    140 		}
    141 		nfd = 0;
    142 		for (fd = 0; fd <= maxfd; fd++) {
    143 			if (FD_ISSET(fd, &set)) {
    144 				char buf[1];
    145 
    146 #if VERBOSE
    147 				printf("[%p] read %d\n",
    148 				    (void *)pthread_self(), fd);
    149 #endif
    150 				if (!FD_ISSET(fd, &oset)) {
    151 					fprintf(stderr, "[%p] unexpected\n",
    152 					    (void *)pthread_self());
    153 					abort();
    154 				}
    155 				if (read(fd, buf, sizeof(buf)) == -1) {
    156 					if (errno != EAGAIN) {
    157 						perror("read");
    158 						abort();
    159 					}
    160 				} else {
    161 					dowrite();
    162 					atomic_inc_uint(&count);
    163 				}
    164 				nfd++;
    165 			}
    166 		}
    167 		if (ret != nfd) {
    168 			fprintf(stderr, "[%p] ret(%d) != nfd(%d)\n",
    169 			    (void *)pthread_self(), ret, nfd);
    170 			abort();
    171 		}
    172 	}
    173 }
    174 
    175 int
    176 main(int argc, char *argv[])
    177 {
    178 	pthread_t pt[NTHREAD];
    179 	int i;
    180 	unsigned int secs;
    181 	struct timeval start_tv;
    182 	struct timeval end_tv;
    183 	uint64_t usecs;
    184 	unsigned int result;
    185 
    186 	secs = atoi(argv[1]);
    187 
    188 	for (i = 0; i < NPIPE; i++) {
    189 		if (pipe(fds[i])) {
    190 			perror("pipe");
    191 			abort();
    192 		}
    193 		if (fcntl(fds[i][0], F_SETFL, O_NONBLOCK) == -1) {
    194 			perror("fcntl");
    195 			abort();
    196 		}
    197 	}
    198 	pthread_barrier_init(&barrier, NULL, NTHREAD + 1);
    199 	for (i = 0; i < NTHREAD; i++) {
    200 		int error = pthread_create(&pt[i], NULL, f, NULL);
    201 		if (error) {
    202 			errno = error;
    203 			perror("pthread_create");
    204 			abort();
    205 		}
    206 	}
    207 	pthread_barrier_wait(&barrier);
    208 	gettimeofday(&start_tv, NULL);
    209 	assert(count == 0);
    210 	for (i = 0; i < NBALLS; i++) {
    211 		dowrite();
    212 	}
    213 	sleep(secs);
    214 	gettimeofday(&end_tv, NULL);
    215 	result = count;
    216 	usecs = (end_tv.tv_sec - start_tv.tv_sec) * 1000000
    217 	    + end_tv.tv_usec - start_tv.tv_usec;
    218 	printf("%u / %f = %f\n", result, (double)usecs / 1000000,
    219 	    (double)result / usecs * 1000000);
    220 	exit(EXIT_SUCCESS);
    221 }
    222