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