It looks like poll() is implemented on top of select() in cygwin. This is fine unless you try to use it in a program with more than 1024 fd's or so. Here's the result of running a test app that goes beyond that limit:
Program received signal SIGSEGV, Segmentation fault. 0x6106fe3a in select () from /usr/bin/cygwin1.dll (gdb) bt #0 0x6106fe3a in select () from /usr/bin/cygwin1.dll #1 0x61610790 in ?? () #2 0x6106ca1d in select () from /usr/bin/cygwin1.dll #3 0x6106c223 in select () from /usr/bin/cygwin1.dll #4 0x61059e7d in poll () from /usr/bin/cygwin1.dll #5 0x004012d3 in count_connects (ipadr=16777343, portnum=80, want=1200) at pollbug.c:120 #6 0x0040175d in main (argc=2, argv=0xa0418c8) at pollbug.c:211
And here's the test code. To reproduce the bug, just run with argument 1500 or so. - Dan
/*-------------------------------------------------------------------------- Copyright 1999,2000, Dan Kegel http://www.kegel.com/ See the file COPYING
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------- Program to measure limits on network sockets, file descriptors, etc. --------------------------------------------------------------------------*/ #include <errno.h> #include <fcntl.h> #include <netinet/in.h> #include <arpa/inet.h> #include <poll.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/resource.h> #include <time.h> #include <unistd.h> #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif #define MAX_TEST 100000 int fds[MAX_TEST]; /*---------------------------------------------------------------------- Portable function to set a socket into nonblocking mode. ----------------------------------------------------------------------*/ static int setNonblocking(int fd) { int flags; /* Caution: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */ #if defined(O_NONBLOCK) if (-1 == (flags = fcntl(fd, F_GETFL, 0))) flags = 0; return fcntl(fd, F_SETFL, flags | O_NONBLOCK); #else flags = 1; return ioctl(fd, FIOBIO, &flags); #endif } static int count_connects(int ipadr, int portnum, int want) { int i; int maxfd; int nopen; struct pollfd pfds[MAX_TEST]; int nok; int nrej; time_t end; #ifdef VERBOSE printf("Starting connections until we can't start any more; will print what stops us to stderr.\n"); #endif for (i = 0; i < want; i++) { struct sockaddr_in srv_addr; int err; fds[i] = socket(AF_INET, SOCK_STREAM, 0); if (fds[i] < 0) { #ifdef VERBOSE perror("socket"); #endif break; } setNonblocking(fds[i]); /* else connect will wait until resources avail */ memset((char *) &srv_addr, 0, sizeof(srv_addr)); srv_addr.sin_family = AF_INET; srv_addr.sin_addr.s_addr = ipadr; srv_addr.sin_port = htons(portnum); err = connect(fds[i], (struct sockaddr *) &srv_addr, sizeof(srv_addr)); if ((err != 0) && (errno != EINPROGRESS)) { #ifdef VERBOSE perror("connect"); #endif break; } pfds[i].fd = fds[i]; pfds[i].events = POLLOUT; } maxfd = i; #ifdef VERBOSE printf("%d connections in progress...\n", maxfd); #endif /* Now sit until they all connect or fail, or until five seconds * pass, whichever comes first. */ end = time(0) + 6; for (nrej=nok=0, nopen=maxfd; nopen; ) { int nready; if ((end - time(0)) < 0) break; nready = poll(pfds, maxfd, 1000); if (nready < 0) { perror("poll"); exit(1); } for (i=0; i<maxfd; i++) { if ((pfds[i].fd == -1) || !pfds[i].revents) continue; /* question: if a connect fails, will it show up first * as a POLLERR, POLLHUP, or POLLOUT? */ if (pfds[i].revents & (POLLHUP|POLLERR)) { /* connect failed? */ close(pfds[i].fd); nrej++; } else if (pfds[i].revents & POLLOUT) { /* check to see if connect succeeded */ int connecterr = -1; socklen_t len = sizeof(connecterr); if (getsockopt(pfds[i].fd, SOL_SOCKET, SO_ERROR, (char *)&connecterr, &len) < 0) { perror("getsockopt"); exit(1); } if (!connecterr) { nok++; /* keep socket open */ } else if (connecterr == ECONNREFUSED) { close(pfds[i].fd); nrej++; } } else { printf("bad poll result: pfds[%d].fd %d, .revents %x\n", i, pfds[i].fd, pfds[i].revents); exit(1); } pfds[i].fd = -1; nopen--; } } /* Close 'em (might close a few extra, but that's ok) */ for (i = 0; i < maxfd; i++) close(fds[i]); #ifdef VERBOSE printf("%d connections accepted, %d rejected, %d pending\n", nok, nrej, nopen); #endif return nok + nrej + nopen; } int main(int argc, char **argv) { const char *ipadrstr; int ipadr; int portnum; int want; if (argc < 2) { printf("Usage: %s num_wanted [ipadr portnum]\n\ Tries to open the specified number of sockets in various ways.\n\ ", argv[0]); exit(1); } want = atoi(argv[1]); if (want < 1 || want > MAX_TEST) { printf("Sorry, want must be between 1 and %d\n", MAX_TEST); exit(1); } if (argc < 3) ipadrstr = "127.0.0.1"; else ipadrstr = argv[2]; ipadr = inet_addr(ipadrstr); if (ipadr == -1) { printf("Bad ip address %s.\n", ipadrstr); exit(1); } if (argc < 4) portnum = 80; else { const char *portnumstr; portnumstr = argv[3]; portnum = atoi(portnumstr); if ((portnum <= 0) || (portnum > 65535)) { printf("Bad port number '%s'. Must be number between 1 and 65535.\n", portnumstr); exit(1); } } printf("Can start %d nonblocking connect()'s\n", count_connects(ipadr, portnum, want)); return 0; }
-- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/