1/* $NetBSD: select.c,v 1.2 2008/03/21 16:03:33 ad 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 53int fds[NPIPE][2]; 54 55volatile unsigned count; 56 57pthread_barrier_t barrier; 58 59static void 60dowrite(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 77static void * 78f(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 175int 176main(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